InfoQ|重新思考日志:业务系统竟然是一个大数据库?

《IHeartLogs》出版于2014年 , 是一本很短小的书 。 作者JayKreps , 是前LinkedIn的PrincipalStaffEngineer , 也是LinkedIn许多著名开源项目的负责人及联合作者 , 如Kafka、Voldemort等 。 他是现任Confluent的CEO , 主要工作在于围绕实时数据提供企业级服务支持 。 这本书算是JayKreps过去多年实践的思考结晶 。 本文主要是对书中的一些看法、观点的梳理 , 有兴趣可以阅读原著或博客 。
注:本文大部分图片、内容来自于原著或原博客 。
日志即数据在讨论日志之前 , 首先要明确日志的含义 。 这里的日志并非指我们常用的非结构化或半结构化的服务日志 , 而更接近数据库中常见的结构化的提交日志(commitlog/journal/WAL) , 这些日志通常是只往后追加数据 , 这里的序号暗含着逻辑时间 , 标识着连续日志产生的逻辑先后顺序:
InfoQ|重新思考日志:业务系统竟然是一个大数据库?
文章图片
数据库中的日志日志在数据库中常常被用来实现故障恢复、数据复制、最终一致性等 。 一个事务提交成功与否在日志提交成功时就可以确定 , 只要WAL落盘 , 便可告诉客户端提交成功 , 即便数据库发生故障 , 也能从WAL日志中恢复数据;日志(如BinLog)的pub/sub机制可以用来在主节点与复制节点之间同步数据 , 通过同步的进度可以知道不同复制节点的同步进度 , 此外日志的逻辑顺序保证了主节点与复制节点之间数据的一致性 。
分布式系统中的日志数据库利用日志来解决的问题 , 也是所有分布式系统需要解决的根本问题 , 如刚才提到的故障恢复、数据同步、数据一致性等等 , 可以称之为以日志为中心(log-centric)的解决方案 。 更严谨地说:
如果两个相同的(identical)、确定(deterministic)的进程以相同的状态启动 , 按相同的顺序获取相同的输入 , 它们将最终达到相同的状态 。
这就是状态机复制原则(statemachinereplicationprinciple) 。 多个这样的进程 , 就组成了我们熟知的各种分布式系统 。
日志为中心的设计日志为中心的设计可以分为两种:主备(primarybackup)和状态机复制(statemachinereplication) , 如下图所示:
InfoQ|重新思考日志:业务系统竟然是一个大数据库?
文章图片
在主备模式中 , 主节点接收所有的读写请求 , 每条写入的数据被记录到日志中 , 从节点通过订阅日志、执行操作来同步数据状态 。 如果主节点发生故障 , 就在从节点中选择一个作为新的主节点;在状态机复制中 , 不存在主节点 , 所有的写操作先进入日志 , 所有节点都通过订阅日志 , 执行操作来生成本地状态 。
日志与共识我们提到的日志与共识算法中的日志似乎也有些相似 , 但也有所不同 。 共识通常指系统中的所有节点连续达成共识 , 在每个时刻只能达成一个共识 , 这些共识是线性一致的;在实践中 , 系统通常需要同时做多个决定 , 这些决定之间并没有绝对的先后顺序或因果关系 。 因此相较于共识 , 日志的抽象对于常见的分布式系统来说更加自然 。
我们往往过于关注复杂的共识算法实现 , 而没有注意到日志抽象的实践意义 , 这一点比较反常 。 比如 , 当人们谈论hashtable的时候 , 很少关注背后的实现是murmurhashwithlinearprobing还是其它实现变种 。 未来 , 想必日志抽象会将更加常见 , 背后也将有很多算法和实现相互竞争 , 以提供最好的服务保证和最优的系统性能 。
数据表与日志的对偶性日志记录着数据表的变化 , 数据表记录着数据的最新状态 。 完整的操作日志可以让我们做时空穿梭 , 回溯到数据的任何一个历史状态 。 这与代码的版本管理系统有些类似 , 实际上代码仓库本身就是一个可以回退到任何历史状态的数据库 。
更大的分布式数据库实际上 , 我们可以将企业中的所有数据、数据流以及数据系统合起来看作是一个巨型分布式数据库 。 所有原始数据表就是数据库中的基础数据;所有面向查询的系统都是基于这个数据库之上建立的索引 , 如Redis、ElasticSearch、Hivetables等等;流式处理系统 , 如Flink、Storm、Samza , 是这个数据库中基于触发器的实体化视图机制(trigger-and-viewmaterializationmechanism);日志系统就是数据库的操作日志 , 记录数据的变化 。


推荐阅读