Presto: SQL on EveryThing

摘要

Presto是一个开源分布式查询引擎,支撑了Facebook内部大部分的SQL分析工作。Presto的设计目标是具有适应性、灵活性和可扩展性。它支持具有不同特征的各种各样的用例。这些用例的范围从要求亚秒级延迟的面向用户的报表应用到花费数小时的聚合或关联数TB数据的ETL任务。Presto的连接器API允许以插件的方式为数十个数据源提供高性能I/O接口,包括Hadoop数据仓库、RDBMS数据库、NoSQL系统和流处理系统。在本论文中,我们概述了Presto在Facebook内部支撑的一系列用例。然后,我们描述了它的架构和实现,并阐述了使其能够支持这些用例的功能和性能优化。最后,我们展示了性能结果,从而论证了我们主要的设计决策的影响。

关键词: SQL,查询引擎,大数据,数据仓库

阅读全文 »

DBLog:一款通用的变化数据捕获框架

本篇是论文的中文简单翻译

应⽤程序使⽤多个异构数据库是⼀种常⻅的模式,其中每个数据库都⽤于满⾜特定需求,例如存储规范形式的数据或提供⾼级搜索功能。因此,对于应⽤程序来说,需要保持多个数据库同步。我们观察到了⼀系列试图解决这个问题的不同模式,例如双写和分布式事务。然⽽,这些⽅法在可行性、稳健性和维护⽅⾯存在局限性。最近出现的另⼀种⽅法是利⽤变更数据捕获 (CDC) 从数据库的事务⽇志中捕获更改的行,并最终以低延迟将它们传递到下游。为了解决数据同步问题,还需要复制数据库的完整状态,⽽事务⽇志通常不包含完整的更改历史记录。同时,有些⽤例需要事务⽇志事件的⾼可⽤性,以便数据库尽可能保持同步。

为了应对上述挑战,我们开发了⼀种新颖的 CDC数据库框架,即 DBLog。 DBLog 利⽤基于⽔印的⽅法,允许我们将事务⽇志事件与我们直接从表中选择的行交错以捕获完整状态。我们的解决⽅案允许⽇志事件继续进行,⽽不会在处理选择时停⽌。可以随时在所有表、特定表或表的特定主键上触发选择。 DBLog 以块的形式执行选择并跟踪进度,允许它们暂停和恢复。⽔印⽅法不使⽤锁,对源的影响最⼩。 DBLog⽬前被 Netflix 的数⼗个微服务⽤于⽣产。

关键字:

  • databases
  • replication
  • change-data-capture
阅读全文 »

IO 模型

在《UNIX网络编程》中介绍了5中I/O模型:阻塞I/O、非阻塞I/O、I/O复用、SIGIO 、异步I/O; Unix的I/O模型,一个输入操作通常包括两个不同的阶段:

  • 等待数据准备好;
  • 从内核向进程复制数据。

对于一个套接字的输入操作,第一步通常涉及等待数据从网络到达,当所等待分组到达时,被复制到内核的某个缓冲区;第二步把数据从内核缓冲区复制到应用进程缓冲区。

网络应用需要处理的无非就是两大类问题,网络IO,数据计算。相对于后者,网络IO的延迟,给应用带来的性能瓶颈大于后者。网络IO的模型大致有如下几种:

  • 阻塞IO(bloking IO)
  • 非阻塞IO(non-blocking IO)
  • 多路复用IO(multiplexing IO)
  • 信号驱动式IO(signal-driven IO)
  • 异步IO(asynchronous IO)
阅读全文 »

Scalable IO in Java

本文是 Doug Lea 的 “Scalable IO in Java” 读书笔记

可扩展的网络服务

在一般的网络或分布式服务等应用程序中,大都具备一些相同的处理流程,例如:

  1. 读取请求数据;
  2. 对请求数据进行解码;
  3. 对数据进行处理;
  4. 对回复数据进行编码;
  5. 发送回复;

当然在实际应用中每一步的运行效率都是不同的,例如其中可能涉及到xml解析、文件传输、web页面的加载、计算服务等不同功能。

阅读全文 »

算法之MD5

MD5 即Message-Digest Algorithm 5 (信息-摘要算法5)。MD5 使用little-endian(小端模式),输入任意不定长度信息,以 512-bit 进行分组,生成四个32-bit 数据,最后联合输出固定 128-bit 的信息摘要。

MD5 不是足够安全的。Hans Dobbertin在1996年找到了两个不同的512-bit 块,它们 在MD5 计算下产生相同的hash 值。至今还没有真正找到两个不同的消息,它们的MD5 的hash 值相等。

阅读全文 »

logback 性能优化

日志是服务中一个重要组成部分,当优化性能的时候,也要思考对日志的性能优化。

控制台日志

生产环境应该关闭控制台日志。可以减少不必要的开销。

获取行号

logback和log4j等日志框架获取行号的方式是相同的。即通过throw 时获取 StackTrace,然后从中解析出 文件名和行号。

1
2
3
4
5
6
7
public StackTraceElement[] getCallerData() {
if (callerDataArray == null) {
callerDataArray = CallerData
.extract(new Throwable(), fqnOfLoggerClass, loggerContext.getMaxCallerDataDepth(), loggerContext.getFrameworkPackages());
}
return callerDataArray;
}

在生产环境中可以不打印 文件名和行号来减少日志的性能消耗。

如果开启了异步Appender, 还要注意一个参数 includeCallerData

1
2
3
4
5
protected void preprocess(ILoggingEvent eventObject) {
eventObject.prepareForDeferredProcessing();
if (includeCallerData)
eventObject.getCallerData();
}
1
2
3
4
<appender name="access-async" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="access"/>
<includeCallerData>false</includeCallerData>
</appender>

过滤异常栈

异常栈可以非常有效地帮助定位问题,但是也会因为异常栈太长,包含了太多几乎无价值的信息,比如反射、动态代理、Spring、tomcat等调用信息。过滤掉这部分信息,既减少了日志量,也减少大对象的数量,降低Full GC的次数。常用配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<property name="commonPattern" value="[%thread][%level][%class{0}:%line]: %msg%n%rEx{full,
java.lang.reflect.Method,
sun.reflect,
org.apache.catalina,
org.springframework.aop,
org.springframework.security,
org.springframework.transaction,
org.springframework.web,
org.springframework.beans,
org.springframework.cglib,
net.sf.cglib,
org.apache.tomcat.util,
org.apache.coyote,
ByCGLIB,
BySpringCGLIB,
com.google.common.cache.LocalCache$
}"/>

分布式追踪系统

随着微服务和云原生开发的兴起,越来越多应用基于分布式进行开发,大型应用拆分为微服务后,服务之间的依赖和调用变得越来越复杂。微服务提供了一个强大的体系结构,但也有面临了一些挑战,例如:

  • 如何调试和观察跨复杂网络的分布式调用?
  • 如何分析服务链路的瓶颈并对其进行调优?
  • 如何快速进行服务链路的故障发现?
  • ……

为了更好地维护这些服务,软件领域出现了 Observability 思想。

阅读全文 »

Dapper,大规模分布式系统的跟踪系统

本篇是论文(见参考)的中文简单翻译

概述

当代的互联网的服务,通常都是用复杂的、大规模分布式集群来实现的。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要一些可以帮助理解系统行为、用于分析性能问题的工具。

Dapper—Google生产环境下的分布式跟踪系统,应运而生。那么我们就来介绍一个大规模集群的跟踪系统,它是如何满足一个低损耗、应用透明的、大范围部署这三个需求的。当然Dapper设计之初,参考了一些其他分布式系统的理念,尤其是Magpie和X-Trace,但是我们之所以能成功应用在生产环境上,还需要一些画龙点睛之笔,例如采样率的使用以及把代码植入限制在一小部分公共库的改造上。

自从Dapper发展成为一流的监控系统之后,给其他应用的开发者和运维团队帮了大忙,所以我们今天才发表这篇论文,来汇报一下这两年来,Dapper是怎么构建和部署的。Dapper最初只是作为一个自给自足的监控工具起步的,但最终进化成一个监控平台,这个监控平台促生出多种多样的监控工具,有些甚至已经不是由Dapper团队开发的了。下面我们会介绍一些使用Dapper搭建的分析工具,分享一下这些工具在google内部使用的统计数据,展现一些使用场景,最后会讨论一下我们迄今为止从Dapper收获了些什么。

阅读全文 »

时间格式字符串-年底的惊喜

这一个常在元旦附近出没的Bug,主要原因是Java 日期格式FormatString 中的yyyy 被写成了YYYY。
要注意的是,对于年份来说,大写的Y和小写的y其意义是不同的。y 是Year, Y 表示的是Week year

经过试验,得出的结果如下:Week year 意思是当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,那么这周就算入下一年。

注意上面的Week year 指format时的结果,对于YYYY格式使用parse, 会得到意想不到的结果。

1
2
3
4
5
6
7
8
SimpleDateFormat upperFormater = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
SimpleDateFormat lowerFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(lowerFormater.parse("2021-12-30 09:00:00"));
String lower = lowerFormater.format(lowerFormater.parse("2021-12-30 09:00:00"));
System.out.println(lower);
String upper = upperFormater.format(lowerFormater.parse("2021-12-30 09:00:00"));
System.out.println(upper);
System.out.println(upperFormater.parse("2021-12-30 09:00:00"));

MySQL参数 kill_idle_transaction

最近遇到一个问题,在执行长事务任务的过程中,频繁出现异常 com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communications link failure during commit(). Transaction resolution unknown.即,事务提交时发现连接已经失效。一开始以为是连接超时设置的有问题,但是这个异常重复出现,并且,数据库连接池设置了testOnBorrow。所以应该不是连接超时导致。后来发现,出现报错时,事务开启都刚好超过了5S。

经过和RDS同学的沟通。他们设置了kill_idle_transaction 这个参数,并且默认为5S

在线上遇到5.7.26的锁问题,需要解决idle事务长时间挂起的问题。同时也调研了现有的mysql timeout机制,以确保其和现有的timeout机制可以吻合。Percona从5.1.59-13.0引入了innodb_kill_idle_transaction,用于解决长事务场景,即对idle事务设定一个超时时间,对超过该时间的事务所在的用户连接进行断开。引入该参数也可以防止purge线程的长时间阻塞(长事务会一直保持在活跃状态,则会导致purge长时间的等待,从而导致undo无法清理从而造成磁盘空间的不断增加)。在实现上,开始是通过扫描InnoDB事务列表来进行判断的,在Percona Server 5.6.35-80.0则改为判断connection socket read timeout。这样优化的好处是,巡检可能会造成CPU空跑,而基于socket select超时则发生超时才会触发,使代码的运行更有效率。另外,percona现在提供了两个参数:innodb_kill_idle_transaction(后者的alias,5.7中已标记为deprecated)和kill_idle_transaction。我们在port时只保留kill_idle_transaction。

阅读全文 »