This commit is contained in:
Jerry Lee
2015-08-09 18:37:41 +08:00
parent 391d8a0bfc
commit f078523b70
5 changed files with 108 additions and 108 deletions

View File

@@ -33,8 +33,8 @@ PS
日志:每个软件工程师都应该知道的有关实时数据的统一抽象
=====================================================================
我在六年前加入到`LinkedIn`公司,那是一个令人兴奋的时刻:我们刚开始面临单一庞大的集中式数据库的限制问题,需要过渡到一套专的分布式系统。
这是一个令人兴奋的经历:我们构建、部署和运行分布式图数据库(`distributed graph database`)、分布式搜索后端(`distributed search backend`)、
我在六年前加入到`LinkedIn`公司,那是一个令人兴奋的时刻:我们刚开始面临单一庞大的集中式数据库的限制问题,需要过渡到一套专的分布式系统。
这是一个令人兴奋的经历:我们构建、部署和运行分布式图数据库(`distributed graph database`)、分布式搜索后端(`distributed search backend`)、
`Hadoop`以及第一代和第二代键值数据存储(`key-value store`),而且这套系统一直运行至今。
这个过程中,我学到的最有益的事情是我们所构建这套系统的许多组件其核心都包含了一个很简单的概念:日志。
@@ -67,7 +67,7 @@ PS
- [数据流图(`data flow graphs`](part3-logs-and-real-time-stream-processing.md#数据流图data-flow-graphs)
- [有状态的实时流处理](part3-logs-and-real-time-stream-processing.md#有状态的实时流处理)
- [日志合并(`log compaction`](part3-logs-and-real-time-stream-processing.md#日志合并log-compaction)
- [第四部分:构建系统](part4-system-building.md)
- [第四部分:系统构建(`system building`](part4-system-building.md)
- [分解单品方式而不是打包套餐方式(`Unbundling`](part4-system-building.md#分解单品方式而不是打包套餐方式unbundling)
- [日志在系统架构中的地位](part4-system-building.md#日志在系统架构中的地位)
- [结束语](the-end.md)

View File

@@ -6,19 +6,20 @@
- [变更日志101表与事件的二相性`duality`](#变更日志101表与事件的二相性duality)
- [接下来的内容](#接下来的内容)
日志可能是一种最简单的不能再简单的存储抽象。它是一个只能追加、完全按照时间排序的记录序列。日志看起来的样子:
日志可能是一种最简单的不能再简单的存储抽象只能追加、按照时间完全有序(`totally-ordered`的记录序列。日志看起来的样子:
![](images/log.png)
我们可以给日志的末尾添加记录,读取日志记录则从左到右。每一条记录都指定了一个唯一序的日志记录编号。
日志的末尾添加记录,读取日志记录则从左到右。每一条记录都指定了一个唯一的顺序的日志记录编号。
日志记录的次序(`ordering`)定义了『时间』概念,因为位于左边的日志记录表示比右边的要早。
日志记录编号可以看作是这条日志记录的『时间戳』。
把次序直接看成是时间概念,刚开始你会觉得有点怪异,但是这样的做法有个便利的性:解耦了 时间 和 任一特定的物理时钟(`physical clock`)。引入分布式系统后,这会成为一个必不可少的属性。
把次序直接看成是时间概念,刚开始你会觉得有点怪异,但是这样的做法有个便利的性:解耦了 时间 和 任一特定的物理时钟(`physical clock`)。
引入分布式系统后,这会成为一个必不可少的性质。
***【译注】*** 分布式系统的 时间、次序、时钟是个最基础根本的问题,详见被引用最多的***Leslie Lamport***的论文***Time Clocks and the Ordering of Events in a Distributed System***[中文翻译](http://duanple.blog.163.com/blog/static/709717672012920101343237/)),现在先***不要***去看,除非读完本文后你还是有很兴趣要探个明白
***【译注】*** 分布式系统的 时间、次序、时钟是个最基础根本的问题,详见被引用最多的***Leslie Lamport***的论文***Time Clocks and the Ordering of Events in a Distributed System***[中文翻译](http://duanple.blog.163.com/blog/static/709717672012920101343237/)),现在先 ***不要*** 去看,除非读完本文后你还是有很兴趣要探个明白
日志记录的内容和格式是什么对于本文讨论并不重要。另外,不可能一直给日志添加记录,因为总会耗尽存储空间。稍后我们会回到这个问题。
日志记录的内容和格式是什么对于本文讨论并不重要。另外,不可能一直给日志添加记录,因为总会耗尽存储空间。稍后我们会再回来讨论这个问题。
所以,日志 和 文件或数据表(`table`)并没有什么大的不同。文件是一系列字节,表是由一系列记录组成,而日志实际上只是一种按照时间顺序存储记录的数据表或文件。
@@ -29,63 +30,64 @@
应用日志记录是我说的日志概念的一种退化。两者最大的区别是:文本日志意味着主要用来方便人去阅读,而构建我所说的『日志(`journal`)』或者『数据日志(`data logs`)』是用于程序的访问。
(实际上,如果你深入地思考一下,会觉得人去阅读某个机器上的日志这样的想法有些落伍过时了。
当涉及到许多服务和服务器时,这样的做法很快就变得难于管理,而且为了认识多个机器的行为,
这样日志的目很快就变成 输入查询 和 输出用于理解多台机器的行为的图表
—— 在这种的情况止下,文件中的字句文本 几乎肯定不如 本文所描述的结构化日志 更合适。)
当涉及多服务和服务器时,这样的做法很快就变得难于管理,
我们的目很快就变成 输入查询 和 输出用于理解多台机器的行为的图表
因此,文件中的字句文本 几乎肯定不如 本文所描述的结构化日志 更合适。)
数据库中的日志
-------------------------
我不知道日志概念起源于何处 —— 可能就像二分查找(`binary search`)一样,发明者觉得太简单了而不是一项发明。早在`IBM`的[系统R](http://www.cs.berkeley.edu/~brewer/cs262/SystemR.pdf)出现时候日志就出现了。
我不知道日志概念起源 —— 可能就像二分查找(`binary search`)一样,发明者觉得太简单了而不是一项发明。早在`IBM`的[系统R](http://www.cs.berkeley.edu/~brewer/cs262/SystemR.pdf)出现时候日志就出现了。
在数据库里的用法是在崩溃的时候用它来保持各种数据结构和索引的同步。为了保证操作的原子性(`atomic`)和持久性(`durable`)
在对数据库维护的所有各种数据结构做更改之前,数据库会把要做的更改操作的信息写入日志。
日志记录了发生了什么,而每个表或者索引都是更改历史中的个投影。由于日志是即持久化的,发生崩溃时,可以把它当作恢复其他所有永久性结构的可靠来源。
日志记录了发生了什么,而每个表或者索引都是更改历史中的个投影。由于日志是即持久化的,发生崩溃时,可以作恢复其他所有持久化结构的可靠来源。
随着时间的推移,日志的用途从`ACID`的实现细节成长为数据库间复制数据的一种方法。
结果证明,发生在数据库上的更改序列 即是 与远程副本数据库(`replica database`)保持同步 所需的操作。
`Oracle``MySQL``PostgreSQL`都包括一个日志传送协议(`log shipping protocol`用于给作为备库(`Slave`)的副本数据库日志片段
`Oracle`还把日志产品化为一个通用的数据订阅机制,为非`Oracle`数据订阅用户提供了[`XStreams`](http://docs.oracle.com/cd/E11882_01/server.112/e16545/xstrm_intro.htm)和[`GoldenGate`](http://www.oracle.com/technetwork/middleware/goldengate/overview/index.html)`MySQL``PostgreSQL`类似设施已经许多数据架构的关键组件。
`Oracle``MySQL``PostgreSQL`都包括一个日志传送协议(`log shipping protocol`传输日志给作为备库(`Slave`)的复本(`replica`)数据库
`Oracle`还把日志产品化为一个通用的数据订阅机制,为非`Oracle`数据订阅用户提供了[`XStreams`](http://docs.oracle.com/cd/E11882_01/server.112/e16545/xstrm_intro.htm)和[`GoldenGate`](http://www.oracle.com/technetwork/middleware/goldengate/overview/index.html),在`MySQL``PostgreSQL`中类似设施许多数据架构的关键组件。
正是由于这样的起源,机器可识别的日志这个概念主要都被局限在数据库的内部。日志做数据订阅机制似乎是偶然出现的。
但正是这样的抽象才非常适合用于支持所有类型的消息传输、数据流和实时数据处理。
正是由于这样的起源,机器可识别的日志概念主要都被局限在数据库的内部。日志作为做数据订阅机制的用法似乎是偶然出现的。
正是支持各种的消息传输、数据流和实时数据处理的理想抽象
分布式系统中的日志
-------------------------
日志解决了两个问题:更改动作的排序和数据的分发,这两个问题在分布式数据系统更是尤为重要。
协商一致的更改动作的顺序(或协商出保持各个子系统本身的做法和可以进行存在副作用的数据拷贝)是分布式系统设计的核心问题之一。
日志解决了两个问题:更改动作的排序和数据的分发,这两个问题在分布式数据系统更是尤为重要。
协商达成一致的更改动作的顺序(或协商达成不一致做法并去做有副作用的数据拷贝)是分布式系统设计的核心问题之一。
以日志为中心的分布式系统方案是受到了一个简单经验的启发,我把这个经验称为**状态机复制原理**`State Machine Replication Principle`
分布式系统以日志为中心的方案是来自于一个简单的观察,我称之为**状态机复制原理**`State Machine Replication Principle`
**如果两个相同的、确定性的进程从同一状态开始,并且以相同的顺序获得相同的输入,那么这两个进程将会生成相同的输出,并且结束在相同的状态。**
听起来有点难以晦涩,让我们更加深入的探讨,弄懂它的真正含义。
[确定性](http://en.wikipedia.org/wiki/Deterministic_algorithm)`deterministic `)意味着处理过程是与时间无关的,而且任何其他『带外数据(`out of band`)』的输入不会影响处理结果。
例如,如果一个程序的输出会受到线程执行的具体顺序影响,或者受到`gettimeofday`调用、或者其他一些非重复性事件的影响,那么这样的程序一般被认为是非确定性的。
[确定性](http://en.wikipedia.org/wiki/Deterministic_algorithm)`deterministic `)意味着处理过程是与时间无关的,而且不让任何其他『带外数据(`out of band`)』的输入影响处理结果。
例如,如果一个程序的输出会受到线程执行的具体顺序影响,或者受到`getTimeOfDay`调用、或者其他一些非重复性事件的影响,那么这样的程序一般被认为是非确定性的。
进程***状态***是进程保存在机器上的任何数据,在进程处理结束的时候,这些数据要么保存在内存里,要么保存在磁盘上。
进程***状态*** 是进程保存在机器上的任何数据,在进程处理结束的时候,这些数据要么保存在内存里,要么保存在磁盘上。
当碰到以相同的顺序输入相同的内容的情况时,应该触发你的条件反射:这个地方要引入日志。
下面是个很直觉的意识:如果给两段确定性代码相同的日志输入,那么它们就会生产相同的输出。
应用到分布式计算中就相当明显了。你可以把用多台机器都执行相同事情的问题化简为实现分布式一致性日志作为这些处理的输入的问题。
日志的目的是把所有非确定性的东西排除在输入流之外,以确保处理这些输入各个复本(`replica`)保持同步。
应用到分布式计算中就相当明显了。你可以把用多台机器都执行相同事情的问题化简为实现分布式一致性日志作为这些处理的输入的问题。
日志的目的是把所有非确定性的东西排除在输入流之外,以确保处理这些输入各个复本(`replica`)保持同步。
当你理解了这个以后,状态机复制原理就不再复杂或深奥了:这个原理差不多就等于说的是『确定性的处理过程就是确定性的』。不管怎样,我认为它是分布式系统设计中一个更通用的工具。
这样方案的一个美妙之处就在于:用于索引日志的时间戳 就像 用于保持副本状态的时钟 —— 你可以只用一个数字来描述每一个副本,即这个副本已处理的最大日志记录的时间戳。关联了日志的时间戳 一一对应 副本的完整状态。
这样方案的一个美妙之处就在于:用于索引日志的时间戳 就像 用于保持副本状态的时钟 —— 你可以只用一个数字来描述每一个副本,即这个副本已处理的最大日志记录的时间戳。
日志中的时间戳 一一对应了 副本的完整状态。
写进日志的内容,这个原理可以有不同的应用方式。举个例子,我们记录一个服务的输入请求日志,或者从请求到响应服务的状态变化日志,或者服务所执行的状态转换命令的日志。
理论上来说,我们甚至可以记录每一个副本执行的机器指令序列的日志 或是 所调用的方法名和参数序列的日志。
根据写进日志的内容,这个原理可以有不同的应用方式。举个例子,我们可以记录一个服务的输入请求日志,或者从请求到响应服务的状态变化日志,或者服务所执行的状态转换命令的日志。
理论上来说,我们甚至可以记录个副本执行的机器指令序列的日志 或是 所调用的方法名和参数序列的日志。
只要两个进程用相同的方式处理这些输入,这些副本进程就会保持一致的状态。
关于日志的用法,大家见仁见智。数据库工作者通常区分***物理***日志(`physical logging`)和***逻辑***日志(`logical logging`)。物理日志是指记录每一行被改变的内容。逻辑日志记录的不是改变的行而是那些引起行的内容改变的`SQL`语句(`insert``update``delete`语句)。
对日志用法不同群体有不同的说法。数据库工作者通常说成***物理***日志(`physical logging`)和***逻辑***日志(`logical logging`)。物理日志是指记录每一行被改变的内容。逻辑日志记录的不是改变的行而是那些引起行的内容改变的`SQL`语句(`insert``update``delete`语句)。
分布式系统文献通常把处理和复制(`processing and replication`)方案宽泛地分成两种。『状态机器模型』常常被称为主动-主动模型(`active-active model` ——
记录输入请求的日志,个复本处理每个请求。
对这个模型做了细微的调整称为『主备模型』(`primary-backup model`),即选出一个副本做为`leader`,让`leader`按请求到达的顺序处理请求并输出它请求处理的状态变化日志。
其他的副本按照顺序应用`leader`状态变日志保持和`leader`同步,并能够在`leader`失败的时候接替它成为`leader`
分布式系统文献通常把处理和复制(`processing and replication`)方案宽泛地分成两种。『状态机器模型』常常被称为主动-主动模型(`active-active model`
记录输入请求的日志,个复本处理每个请求。
对这个模型做了细微的调整称为『主备模型』(`primary-backup model`),即选出一个副本做为`leader`,让`leader`按请求到达的顺序处理请求并输出它请求处理的状态变化日志。
其他的副本按照顺序应用`leader`状态变日志保持和`leader`同步,并能够在`leader`失败的时候接替它成为`leader`
![](images/active_and_passive_arch.png)
@@ -96,7 +98,7 @@
<img src="images/paxos_postcard.jpg" width="290" hspace="10px" align="right" >
分布式日志可以用于建模[一致性](https://en.wikipedia.org/wiki/Consensus_(computer_science))`consensus`)问题的数据结构。
分布式日志可以看作是建模[一致性](https://en.wikipedia.org/wiki/Consensus_(computer_science))`consensus`)问题的数据结构。
因为日志代表了『下一个』追加值的一系列决策。
你需要眯起眼睛才能从[`Paxos`](http://en.wikipedia.org/wiki/Paxos_(computer_science))算法簇中找到日志的身影,尽管构建日志是它们最常见的实际应用。
`Paxos`通过称为`multi-paxos`的一个扩展协议来构建日志,把日志建模为一系列一致性值的问题,日志的每个记录对应一个一致性值。
@@ -125,33 +127,33 @@
这个过程也是可逆的:如果你对一张表进行更新,你可以记录这些变更,并把所有更新的『变更日志(`changelog`)』发布到表的状态信息中。
这些变更日志正是你所需要的支持准实时的复制。
基于此,你就可以清楚的理解表与事件的二相性: 表支持了静态数据而日志记录了变更。日志的魅力就在于它是变更的_完整_记录它不仅仅包含了表的最终版本的内容
而且可以用于重建任何存在过其它版本。事实上,日志可以看作是表_每个_历史状态的一系列备份。
而且可以用于重建任何存在过其它版本。事实上,日志可以看作是表***每个***历史状态的一系列备份。
这可能会让你想到源代码的版本控制。源码控制和数据库之间有着密切的关系。
版本管理解决了一个和分布式数据系统要解决的很类似的问题 —— 管理分布式并发的状态变更。
版本管理系统建模的是补丁序列(`the sequence of patches`),实际上这就是日志。
你可以当前的代码检出的一个『快照』并直接操作,这个当前代码可以类比成表。
你会注意到,与其他分布式状态化系统类似,版本控制系统通过日志来完成复制:更新代码即是拉下补丁并应用到你的当前快照中。
这可能会让你想到源代码的版本控制`source code version control`。源码控制和数据库之间有着密切的关系。
版本管理解决了一个和分布式数据系统要解决的很类似的问题 —— 管理分布式并发的状态变更。
版本管理系统建模的是补丁序列(`the sequence of patches`),实际上这就是日志。
你可以检出当前的代码的一个『快照』并直接操作,这个代码快照可以类比成表。
你会注意到,正如有状态的分布式系统一样,版本控制系统通过日志来完成复制:更新代码即是拉下补丁并应用到你的当前快照中。
从销售日志数据库的公司[`Datomic`](http://www.datomic.com/)那里,大家可以看到一些这样想法。
[这个视频](https://www.youtube.com/watch?v=Cym4TZwTCNU)他们如何在他们的系统中应用这些想法的不错介绍
当然这些想法不是只专于这个系统,这十多年他们贡献了很多分布式系统和数据库的文献。
从销售日志数据库的公司[`Datomic`](http://www.datomic.com/)那里,大家可以看到一些这样想法。
[这个视频](https://www.youtube.com/watch?v=Cym4TZwTCNU)比较好地介绍了他们如何在系统中应用这些想法。
当然这些想法不是只专于这个系统,这十多年他们贡献了很多分布式系统和数据库方面的文献。
这节的内容可能有点理论化了。但别沮丧!后面马上就是实操的干货。
接下来的内容
-------------------------
本文剩下的内容,我会试着讲述,除了作为分布式计算内部实现或模型抽象,日志有什么优点。包含:
本文剩下的内容,我会试着重点讲述,除了作为分布式计算内部实现或模型抽象,日志有什么优点。包含:
1. _数据集成_`Data Integration` —— 让组织的全部存储和处理系统可以容易地得到访问组织所有数据。
1. _数据集成_`Data Integration` —— 让组织中所有存储和处理系统可以容易地访问组织所有数据。
1. _实时数据处理_ —— 计算生成的数据流。
1. _分布式系统设计_ —— 如何通过集中式日志的设计来简化实际应用系统。
所有这些用法都是通过把日志用做单独服务来实现的。
上面各个用法中,日志的好处都来自日志所能提供的简单功能:生成持久化的可重放的历史记录。
令人意外的是,这些问题的核心是可以让多台机器以确定性的方式(`deterministic manner`)按各自的速度重放历史记录的能力。
上面这些场景中,日志的好处都来自日志所能提供的简单功能:生成持久化的可重放的历史记录。
令人意外的是,让多台机器以确定性的方式(`deterministic manner`)按各自的速度重放历史记录的能力是这些问题的核心
-----------------

View File

@@ -10,105 +10,104 @@
- [日志文件与事件](#日志文件与事件)
- [构建可伸缩的日志](#构建可伸缩的日志)
请让我首先解释一下『数据集成』(`data integration`)是什么意思,还有为什么我觉得它很重要,然后我们再来看看它和日志有什么关系。
先解释一下我说的是『数据集成』(`data integration`)是什么,还有为什么我觉得它很重要,然后我们再来看看它是如何和日志建立关系
**数据集成 是指 一个组织的所有数据 对 这个组织的所有的服务和系统 可使用。**
**数据集成 是指 使一个组织的所有数据 对 这个组织的所有的服务和系统 可用。**
『数据集成』还不是一个常见的用语,但是我找不到一个更好的。大家更熟知的术语[`ETL`](http://en.wikipedia.org/wiki/Extract,_transform,_load)
(译注:`ETL``Extraction-Transformation-Loading`的缩写,即数据提取、转换和加载)
通常只是覆盖了数据集成的一个有限子集 —— 主要在关系型数据仓库的场景。但我描述的东西很大程度上可以理解为,将`ETL`推广至实时系统和处理流程。
通常只是覆盖了数据集成的一个有限子集 —— 主要在关系型数据仓库的场景。但我描述的东西很大程度上可以理解为,将`ETL`推广至覆盖实时系统和处理流程。
<img src="images/cabling.jpg" width="270" hspace="10px" align="right" >
你一定不会听到数据集成就兴趣盎然屏住呼吸,并且天花乱坠的想到关于_大数据_的概念,
不过,我相信这个陈词滥调的『让数据可以使用』的问题是一件组织应该关注的更有价值的事情。
你一定不会听到数据集成就兴趣盎然屏住呼吸,并且天花乱坠的想到***大数据***的概念,
但尽管如此,我相信这个陈词滥调的『让数据可用』的问题是组织可以关注的更有价值的事情之一
对数据的高效使用遵循一种[马斯洛的需要层次理论](http://en.wikipedia.org/wiki/Maslow%27s_hierarchy_of_needs)。
金字塔的基础部分包含捕获所有相关数据,能够将它们全部放到适当的处理环境中(可以是一个华丽的实时查询系统,或仅仅是文本文件和`python`脚本构成的环境)。
这些数据需要以统一的方式建模,以方便读取和处理。
一旦这些以统一的方式捕获数据的基本需求得到满足,那么以不同方法在基础设施上处理这些数据就变得理所当然 —— `MapReduce`、实时查询系统等等。
一旦这些以统一的方式捕获数据的基本需求得到满足,那么在基础设施上以不同方法处理这些数据就变得理所当然 —— `MapReduce`、实时查询系统等等。
显而易见但值得注意的一点:如果没有可靠的、完整的数据流,`Hadoop`集群只不过是个非常昂贵而且安装麻烦的供暖器。
一旦有了数据和处理(`data and processing`),人们的关注点转移到良好的数据模型和一致且易于理解的语义这些更精致的问题上来。
最后,关注点会移动更高级处理上 —— 更好的可视化、生成报表以及处理和预测算法。
一旦有了数据和处理(`data and processing`),人们的关注点就会转移到良好的数据模型和一致且易于理解的语义这些更精致的问题上来。
最后,关注点会转移到更高级处理上 —— 更好的可视化、生成报表以及处理和预测算法。
以我的经验,大多数组织在这个数据金字塔的底部存在巨大的漏洞 —— 缺乏可靠的完整的数据流 ——
却想直接跳到高级数据模型技术上。这样做完全是本未倒置。
所以问题是,我们如何在组织中构建贯穿所有数据系统的可靠数据流?
所以问题是,我们如何在组织中构建贯穿所有数据系统的可靠数据流?
数据集成:两个难题
----------------------
两个趋势使数据集成变得更困难。
两个趋势使数据集成变得更困难。
### 事件数据管道
第一个趋势是增长的事件数据(`event data`)。事件数据记录的是发生的事情,而不是已存在的事情。
`Web`系统中,这就意味着用户活动日志,还有为了可靠地操作和监控数据中心机器的价值记录的机器级别的事件和统计数字。
人们倾向称它们为『日志数据』,因为它们经常被写到应用日志中,但这样的法混淆了形式与功能。
这些数据是现代`Web`的核心:归根结底,`Google`的财富来自于建立在点击和展示(`clicks and impressions`)上的相关性管道(`relevance pipeline`),而这些点击和展示是事件。
`Web`系统中,这就意味着用户活动日志,还有为了可靠地操作和监控数据中心机器的价值记录的机器级别的事件和统计数字。
人们倾向称它们为『日志数据`log data`』,因为它们经常被写到应用日志中,但这样的法混淆了形式与功能。
这些数据是现代`Web`的核心:归根结底,`Google`的财富来自于建立在点击和展示(`clicks and impressions`)上的相关性管道(`relevance pipeline`),而这些点击和展示是事件。
些事并不是仅限于网络公司,只是网络公司已经完全数字化,所以更容易记录。财务数据长久一直是以事件为中心的`event-centric`
[`RFID`](http://en.wikipedia.org/wiki/RFID)(无线射频识别)赋予了物理对象这种跟踪能力
随着传统商务和活动的[数字化(`digitization`](http://online.wsj.com/article/SB10001424053111903480904576512250915629460.html)
样的事情并不是仅限于`Web`公司,只是`Web`公司已经完全数字化,所以更容易完成。财务数据长久以来一直是以事件为中心的。
[`RFID`](http://en.wikipedia.org/wiki/RFID)(无线射频识别)使得能对物理设备做这样的跟踪
随着传统的业务和活动的[数字化(`digitization`](http://online.wsj.com/article/SB10001424053111903480904576512250915629460.html)
我认为这个趋势仍将继续。
这种类型的事件数据记录了发生的事情,而且往往比传统数据库应用要大好几个数量级。这对于处理提出了重大挑战。
这种类型的事件数据记录了发生的事情,往往比传统数据库应用要大好几个数量级。这对于处理提出了重大挑战。
### 专用的数据系统(`specialized data systems`)的爆发
第二个趋势来自于专用的数据系统的[爆发](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.68.9136),这些数据系统在最近五年开始流行并且可以免费获得。
专门用于[`OLAP`](https://github.com/metamx/druid/wiki)、[搜索](http://www.elasticsearch.org/)、[简单](http://www.rethinkdb.com/) [在线](http://www.slideshare.net/amywtang/espresso-20952131) [存储](http://hadoop.apache.org/)、 [批处理](http://hadoop.apache.org/)、[分析](http://graphlab.org/) [](http://redis.io/) [](http://spark.incubator.apache.org/) 的数据系统已经出现。
专门用于[`OLAP`](https://github.com/metamx/druid/wiki)、[搜索](http://www.elasticsearch.org/)、[简单](http://www.rethinkdb.com/) [在线](http://www.slideshare.net/amywtang/espresso-20952131) [存储](http://hadoop.apache.org/)、 [批处理](http://hadoop.apache.org/)、[图分析`graph analysis`](http://graphlab.org/) [](http://redis.io/) [](http://spark.incubator.apache.org/) 的数据系统已经出现。
更多样化的数据同时变成更加大量,而且这些数据期望放到更多的系统中,这些需求同时要解决,导致了一个巨大的数据集成问题。
多样化的数据同时变成更加大量,而且这些数据期望放到更多的系统中,这些需求同时要解决,导致了一个巨大的数据集成问题。
日志结构化的(`log-structured`)数据流
----------------------
处理系统之间的数据流,日志是最自然的数据结构。解决方法很简单:
**提取所有组织的数据,并放到一个可以实时订阅的中心日志中。**
**提取所有组织的数据,并放到一个用于实时订阅的中心日志中。**
每个逻辑数据源都可以建模为它自己的日志。
一个数据源可以看作 一个输出事件日志的应用(如点击或页面的浏览),或是 一个接受修改的数据库表。
每个订阅消息的系统都尽可能快的从日志读取信息,将每条新的记录应用到自己的存储中,同时向前滚动自己日志文件的位置。
一个数据源可以看作 一个输出事件日志的应用(如点击或页面的浏览),或是 一个接受修改的数据库表。
每个订阅消息的系统都尽可能快的从日志读取信息,将每条新的记录应用到自己的存储中,同时向前滚动日志文件中的自己的位置。
订阅方可以是任意一种数据系统 —— 缓存、`Hadoop`、另一个网站中的另一个数据库、一个搜索系统,等等。
<img src="images/log_subscription.png" hspace="10px" align="right" >
举个例子,日志概念为每个变更提供了逻辑时钟,所有的订阅方都可以比较这个逻辑时钟。
这极大简化了如何去分析不同的订阅系统的状态彼此是否一致的,因为每个系统都持有了一个读到哪儿的『时间点』。
这极大简化了如何去推断不同的订阅系统的状态彼此是否一致的,因为每个系统都持有了一个读到哪儿的『时间点』。
为了让讨论更具体些,我们考虑一个简单的案例,有一个数据库和一组缓存服务器集群。
日志提供了一个方法可以同步更新到所有这些系统,并分析出每个系统的所处在的时间点
日志提供了一个方法可以同步更新到所有这些系统,并推断出每个系统的所处在的时间点。
我们假设做了一个写操作,对应日志记录`X`,然后要从缓存做一次读操作。
如果我们想保证看到的不是过时的数据,我们只需保证,不要去读取那些复制还没有跟上`X`的缓存即可。
如果我们想保证看到的不是过时的数据,我们只需保证,不要去读取那些复制操作还没有跟上`X`的缓存即可。
日志也起到缓存的作用,使数据的生产异步于数据的消费。有许多原因让这点很重要,特别是在多个订阅方消费数据的速度各不相同的时候。
日志也起到缓存的作用,使数据的生产异步于数据的消费。有许多原因使得这一点很重要,特别是在多个订阅方消费数据的速度各不相同的时候。
这意味着一个数据订阅系统可以宕机或是下线维护,在重新上线后再赶上来:订阅方可以按照自己的节奏来消费数据。
批处理系统如`Hadoop`或者是一个数据仓库,或许只能每小时或者每天消费一次数据,而实时查询系统可能需要及时到秒。
无论是来源数据源还是日志都不会感知各种目标数据系统的相关知识,所以消费方系统的添加和删除无需去改变传输管道。
无论是起始的数据源还是日志都感知感知各种各样的目标数据系统,所以消费方系统的添加和删除无需去改变传输管道。
特别重要的是:目标系统只知道日志,不知道来源系统的任何细节。
不管是数据来自于一个`RDBMS`(关系型数据库管理系统)、一种新型的键值存储,还是任何形式的实时查询系统所生成的,消费方系统自身无需关心。
特别重要的是:目标系统只知道日志,不知道来源系统的任何细节。
无论是数据来自于一个`RDBMS`、一种新型的键值存储,还是由一个不包含任何类型实时查询系统所生成的,消费方系统无需关心。
这似乎是一个小问题,但实际上却是至关重要的。
>
<img src="images/19202238_eoij.jpg" width="250" >
> [『每个工作数据管道设计得像是一个日志;每个损坏的数据管道以其自己的方式损坏。』
> [『每个工作数据管道设计得像是一个日志;每个损坏的数据管道以其自己的方式损坏。』
> —— ***Count Leo Tolstoy*** (由作者翻译)](http://en.wikipedia.org/wiki/Anna_Karenina_principle)
这里我使用术语『日志』取代了『消息系统』或者『发布-订阅』,因为在语义上明确得多,并且准确得多描述了在实际实现支持数据复制时你所要做的事。
这里我使用术语『日志』取代了『消息系统』或者『发布-订阅』,因为在语义上明确得多,并且准确得多描述了在实际实现支持数据复制时你所要做的事。
我发现『发布订阅』只是表达出了消息的间接寻址(`indirect addressing of messages` ——
如果你去比较两个发布-订阅的消息系统的话,会发现他们承诺的是完全不同的东西,而且大多数模型在这一领域没什么用。
你可以认为日志是一种有持久性保证和强有序(`strong ordering`)语义的消息系统。
在分布式系统中,这个通信模型有时有个(有些可怕的)名字叫做[原子广播(`atomic broadcast`](http://en.wikipedia.org/wiki/Atomic_broadcast)。
值得强调的是,日志仍然只是基础设施并不是掌握数据流这个故事的结束:
故事的余部分围绕着元数据(`metadata`)、`schemas`、兼容性以及处理数据结构及其演化的所有细节。
除非有一种可靠的通用的方来处理数据流的机制,否则语义细节总是次要的。
值得强调的是,日志仍然只是基础设施并不是精通数据流这个故事的结束:
故事的余部分围绕着元数据(`metadata`)、`schemas`、兼容性以及处理数据结构及其演化的所有细节来展开
但是,除非有一种可靠的通用的方来处理数据流的机制,否则语义细节总是次要的。
`LinkedIn`
---------------------------
@@ -123,7 +122,7 @@
- [`Social Graph`](http://engineering.linkedin.com/real-time-distributed-graph/using-set-cover-algorithm-optimize-query-latency-large-scale-distributed)
- [`Voldemort`](http://project-voldemort.com/) (键值存储)
- [`Espresso`](http://data.linkedin.com/projects/espresso) (文档存储)
- [推荐引擎`Recommendation engine`](http://www.quora.com/LinkedIn-Recommendations/How-does-LinkedIns-recommendation-system-work)
- [推荐引擎](http://www.quora.com/LinkedIn-Recommendations/How-does-LinkedIns-recommendation-system-work)
- `OLAP`查询引擎
- [`Hadoop`](http://hadoop.apache.org/)
- [`Terradata`](http://www.teradata.com/)
@@ -131,19 +130,19 @@
每一个都是专用的分布式系统,在各自的专门领域提供高级的功能。
使用日志作为数据流的这个想法,甚至在我到这里之前,就已经`LinkedIn`各个地方开始浮现了。
使用日志作为数据流的这个想法,甚至在我到这里之前,就已经`LinkedIn`各个地方开始浮现了。
我们开发的最早的一个基础设施是一个称为[`databus`](https://github.com/linkedin/databus)的服务,
它在我们早期的`Oracle`表上提供了一种日志缓存抽象,为了做到可伸缩订阅数据库修改,给我们的`social graph`和搜索索引输入数据。
它在我们早期的`Oracle`表上提供了一种日志缓存抽象,用于可伸缩订阅数据库修改,给我们的`social graph`和搜索索引输入数据。
我先简单介绍一些历史以提供讨论的上下文。在发布键值存储之后,大约2008年我开始参与进来
我的一个项目是一个`Hadoop`部署用起来,并把一些我们的推荐处理迁移上来。
我先简单介绍一些历史以提供讨论的上下文。在发布我们自己键值存储之后,大约2008年我开始参与这个项目
接着的一个项目是一个运行的`Hadoop`部署用起来,迁移我们的一些推荐处理上来。
由于缺乏这方面的经验,我们只计划了几周时间完成数据的导入导出,剩下的时间则用来实现复杂的预测算法。
就这样我们开始了长途跋涉。
我们本来计划是仅仅将数据从现存的`Oracle`数据仓库中剖离。
但是我们首先发现将数据从`Oracle`中迅速取出简直是一个黑魔法(`dark art`)。
更糟的是,数据仓库的处理过程并不适合于 我们为`Hadoop`的生产批处理过程 ——
大部分处理都是不可逆的,并且与即将生成的具体报表相关。
更糟的是,数据仓库的处理过程并不适合于 我们为`Hadoop`计的生产批处理过程 ——
大部分处理都是不可逆的,并且与生成的具体报表相关。
最终我们采取的办法是,避免使用数据仓库,直接访问源数据库和日志文件。
最后,我们实现了一个管道,用于完成[加载数据到我们的键值存储](http://data.linkedin.com/blog/2009/06/building-a-terabyte-scale-data-cycle-at-linkedin-with-hadoop-and-project-voldemort)并生成结果。
@@ -152,7 +151,7 @@
在错误的数据基础上运行复杂的算法只会产生更多的错误数据。
虽然我们已经使用了一种很通用的构建方式,但是每个数据源都需要自定义的安装配置。这也被证明是大量错误与失败的根源。
`Hadoop`实现的网站功能已经开始流行起来,同时我们发现自己有一大把需要协作的工程师。
我们`Hadoop`实现的网站功能开始流行起来,我们发现自己有一大把需要协作的工程师。
每个用户都有他们想要集成的一大把的系统,并且想要导入的一大把新数据源。
有些东西在我面前开始渐渐清晰起来。
@@ -160,47 +159,46 @@
首先,我们已建成的通道虽然有一些杂乱,但实际上是极有价值的。
仅在一个新的处理系统(`Hadoop`)让数据可用于处理 就开启了大量的可能性。
基于这些数据过去很难实现的计算如今已变为可能。
许多新的产品和分析技术都来源于把多个分片的数据放在一起,这些数据过去被锁定在特定的系统中。
许多新的产品和分析技术都来源于把多个数据片块放在一起,这些数据过去被锁定在特定的系统中。
> <img src="images/sisyphus.jpg" width="250" >
> 古希腊时代的`ETL`。并没有太多变化。
第二,可靠的数据加载需要数据通道的深度支持,这点已经变得很清晰明白
如果我们可以捕获所有我们需要的结构,就可以使得`Hadoop`数据全自动加载,
这样不需要额外的手动操作就可以完成增加新的数据源或者处理`schema`变更 ——
第二,可靠的数据加载需要数据通道的深度支持,这点已经变得很清晰
如果我们可以捕获所有我们需要的结构,就可以使得`Hadoop`数据全自动加载,
这样不需要额外的手动操作就可以加新的数据源或者处理`schema`变更 ——
数据就会自动的出现在`HDFS`,并且`Hive`表就会自动的为新数据源生成恰当的列。
第三,我们的数据覆盖率仍然非常低。
如果看一下`LinkedIn`所有数据在`Hadoop`中可用的比率,仍然很不完整
相比接入并运转一个新数据源的努力,完整接入数据源更不容易。
第三,我们的数据覆盖率仍然低。
如果看一下`LinkedIn`所有数据在`Hadoop`中可用的比率,仍然很不完整。
相比接入并运转一个新数据源所要做的努力,完整接入一个数据源更不容易。
我们曾经推行的方式,即为每个数据源和目标构建自定义的数据加载,很显然是不可行的。
我们曾经推行的方式为每个数据源和目标构建自定义的数据加载,很显然是不可行的。
我们有几十个数据系统和数据仓库。把这些系统和仓库联系起来,就会导致任意两两系统间构建自定义的管道,如下所示:
![](images/datapipeline_complex.png)
需要注意的是数据是双向流动的:例如许多系统(数据库、`Hadoop`)同时是数据转化的来源和目的。
需要注意的是数据是双向流动的:例如许多系统(数据库、`Hadoop`)同时是数据传输的来源和目的。
这就意味着我们我们最后要为每个系统建立两个通道:一个用于数据输入,一个用于数据输出。
这显然需要一大群人,而且也不具有可操作性。随着我们接近完全连接,最终我们有差不多`O(N^2)`条管道。
这显然需要一大群人,而且也不具有可操作性。随着我们接近完全连接,最终我们有差不多`O(N^2)`条管道。
要避免上面的问题,我们需要像这样通用方式:
要避免上面的问题,我们需要像这样通用方式:
![](images/datapipeline_simple.png)
我们需要尽可能的将每个消费者与数据源隔离。理想情形下,它们应该只与一个单独的数据仓库集成,能访问到所有数据。
我们需要尽可能的将每个消费者与数据源隔离。理想情形下,它们应该只与一个单独的数据集成,能访问到所有数据。
这个思想是增加一个新的数据系统 —— 它可以作为数据来源或者数据目的地 ——
集成工作只需连接这个新系统一个单独的管道,而无需连接到每个数据消费方。
集成工作只需连接这个新系统一个单独的管道,而无需连接到每个数据消费方。
这样的经历使得我注于创建[`Kafka`](http://kafka.apache.org/)
`Kafka`结合了 消息系统 和 数据库和分布式系统内核所必要的日志 两者的特点。
这样的经历使得我注于创建[`Kafka`](http://kafka.apache.org/)把 我们所知的消息系统的特点 与 在数据库和分布式系统内核常用的日志概念 结合起来。
我们需要首先一个实体作为所有的活动数据的中心管道,并逐步的扩展到很多其他使用方式,包含`Hadoop`之外的数据、数据监控等等。
在相当长的时间内,`Kafka`是独一无二的(有人会说是怪异) ——
作为一个底层设施,它既不是数据库,也不是日志文件收集系统,更不是传统的消息系统。
但是最近`Amazon`提供了非常非常类似`Kafka`的服务,称之为[`Kinesis`](http://aws.amazon.com/kinesis)。
相似度包括了分片处理的方式,数据的保持的方式,甚至包括有点特别的`Kafka API`分类(分成高端和低端消费者)。
相似度包括了分片处理的方式,数据的持有方式,甚至包括有点特别的`Kafka API`分类(分成高端和低端消费者)。
我很开心看到这些,这表明了你已经创建了很好的底层设施抽象,`AWS`已经把它作为服务提供!
他们对此的想法看起来与我所描述的完全吻合:
管道联通了所有的分布式系统,诸如`DynamoDB`,`RedShift`,`S3`等,同时作为使用`EC2`进行分布式流处理的基础。

View File

@@ -174,4 +174,4 @@
-----------------
[« 第二部分:数据集成](part2-data-integration.md)    [第四部分:构建系统 »](part4-system-building.md)
[« 第二部分:数据集成](part2-data-integration.md)    [第四部分:系统构建(`system building` »](part4-system-building.md)

View File

@@ -1,4 +1,4 @@
第四部分:构建系统
第四部分:系统构建(`system building`
===============================
- [分解单品方式而不是打包套餐方式(`Unbundling`](#分解单品方式而不是打包套餐方式unbundling)