diff --git a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/images/log_compaction_0.png b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/images/log_compaction_0.png
new file mode 100644
index 0000000..4e4a833
Binary files /dev/null and b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/images/log_compaction_0.png differ
diff --git a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part2.md b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part2.md
index fefa61c..fa6fd84 100644
--- a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part2.md
+++ b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part2.md
@@ -157,11 +157,11 @@
第二,可靠的数据加载需要数据通道的深度支持,这点已经变得很清晰明白。
如果我们可以捕获所有我们需要的结构,就可以使得`Hadoop`数据全自动的加载,
-这样就不需要额外的手动操作就可以完成增加新的数据源或者处理`schema`变更 --
+这样就不需要额外的手动操作就可以完成增加新的数据源或者处理`schema`变更 ——
数据就会自动的出现在`HDFS`,并且`Hive`表就会自动的为新数据源生成恰当的列。
第三,我们的数据覆盖率仍然非常低。
-如果看一下`Linked`所有数据在`Hadoop`中可用的比率,仍然还很不完整的。
+如果看一下`LinkedIn`所有数据在`Hadoop`中可用的比率,仍然还很不完整的。
相比接入并运转一个新数据源的努力,完整接入数据源更是不容易。
我们曾经推行的方式,即为每个数据源和目标构建自定义的数据加载,很显然是不可行的。
@@ -215,7 +215,7 @@
这就意味着这些数据对于需要实时处理/实时输入处理、搜索索引、系统监控等系统来说不可用的。
依我之见,`ETL`包括两件事。
-首先,它是数据抽取和数据规整的处理 -- 本质上就是释放被锁在组织的各类系统中的数据,去除特定于系统的约束。
+首先,它是数据抽取和数据规整的处理 —— 本质上就是释放被锁在组织的各类系统中的数据,去除特定于系统的约束。
第二,依照数据仓库的查询重构数据,例如使其符合关系数据库类型系统,
强制使用星号、雪花型模式(`star schema`、`snowflake schema`),可能会打散数据成高性能的[列](http://parquet.io/) [格式](http://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.0.0.2/ds_Hive/orcfile.html)(`column format`),等等。合并这两者是有困难的。
这些集成仓库的规整的数据除了要索引到实时存储系统中,也应当可用于实时或是低时延处理中。
@@ -268,16 +268,21 @@
因为在这个阶段(一般比较自然地对应到传统的`ETL`处理阶段),现在处理的是一组规整得多和统一得多的流,
处理过程已经大简化了。
-日志文件和事件
+日志文件与事件
---------------------
-我们再来聊聊这种架构的优势:它支持解耦和事件驱动的系统。
+我们再来聊聊这种架构的附带的优势:支持解耦的事件驱动的系统。
-在网络行业取得活动数据的典型方法是把它记为文本形式的日志,这些文本文件是可分解进入数据仓库或者Hadoop,用于聚合和查询处理的。由此产生的问题与所有批处理的ETL的问题是相同的:它耦合了数据流进入数据仓库系统的能力和流程的调度。
+在`Web`行业取得活动数据的典型方法是把打日志到文本文件中,
+然后这些文本文件分解进入数据仓库或者`Hadoop`用于聚合和查询。
+这做的问题和所有批处理的`ETL`做法一样:数据流耦合了数据仓库系统的能力和处理的计划。
-在LinkedIn中,我们已经以中心日志的方式构建了事件数据处理。我们正在使用Kafka做为中心的、多订阅者事件日志。我们已经定义了数百种事件类型,每种类型都会捕获用于特定类型动作的独特的属性。这将会覆盖包括页面视图、表达式、搜索以及服务调用、应用异常等方方面面。
+在`LinkedIn`,我们以中心日志的风格构建事件数据处理。
+我们使用`Kafka`做为中心的多订阅方的事件日志,定义数百种事件类型,
+每种类型都会捕获一个特定动作类型的独特属性。
+这样的方式覆盖从页面浏览、广告展示、和搜索到服务调用、应用异常的方方面面。
-为了进一步理解这一优势:设想一个简单的事务--在日志页面显示已发布的日志。这个日志页面应当只包括显示日志所需要的逻辑。然而,在相当多的动态站点中,日志页面常常变的添加了很多与显示日志无关的逻辑。例如,我们将对如下的系统进行集成:
+为了进一步理解这一优势:设想一个简单的事务 —— 在日志页面显示已发布的日志。这个日志页面应当只包括显示日志所需要的逻辑。然而,在相当多的动态站点中,日志页面常常变的添加了很多与显示日志无关的逻辑。例如,我们将对如下的系统进行集成:
- 需要把数据传送到Hadoop和数据仓库中用于离线数据处理。
- 需要对视图进行统计,确保视图订阅者不会攻击一些内容片段。
@@ -286,7 +291,7 @@
- 推荐系统需要记录日志用于正确的跟踪作业的普及度。
- 等等。
-不久,简单的作业显示变得相当的复杂。我们增加了作业显示的其它终端--移动终端应用等--这些逻辑必须继续存在,复杂度不断的增加。更糟的是我们需要与之做接口交互的系统现在是错综复杂的--在为显示日作业而工作的工程师们需要知晓多个其它系统和它们的特征,才可以确保它们被正确的集成了。这仅仅是问题的简单版本,真实的的应用系统只会更加的复杂。
+不久,简单的作业显示变得相当的复杂。我们增加了作业显示的其它终端 —— 移动终端应用等 —— 这些逻辑必须继续存在,复杂度不断的增加。更糟的是我们需要与之做接口交互的系统现在是错综复杂的 _ 在为显示日作业而工作的工程师们需要知晓多个其它系统和它们的特征,才可以确保它们被正确的集成了。这仅仅是问题的简单版本,真实的的应用系统只会更加的复杂。
“事件驱动”的模式提供了一种简化这类问题的机制。作业显示页面现在只显示作业并记录与正在显示的作业,作业订阅者相关的其它属性,和其它与作业显示相关的其它有价值的属性。每个与此相关的其它系统诸如推荐系统、安全系统、作业推送分析系统和数据仓库,所有这些只是订阅种子文件,并进行它们的操作。显示代码并不需要关注其它的系统,也不需要因为增加了数据的消费者而相应的进行变更。
diff --git a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part3.md b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part3.md
index 81471bc..210a2b5 100644
--- a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part3.md
+++ b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part3.md
@@ -11,7 +11,7 @@
这些视图都有一些局限性。流处理与SQL是无关的。它也局限于实时流处理。不存在内在的原因限制你不能处理昨天的或者一个月之前的流数据,且使用多种不同的语言表达计算。
-
+
我把流处理视为更广泛的概念:持续数据流处理的基础架构。我认为计算模型可以像MapReduce或者分布式处理架构一样普遍,但是有能力处理低时延的结果。
@@ -38,9 +38,9 @@
数据流图
------------------
-
+
-流处理最有趣的角度是它与流处理系统内部无关,但是与之密切相关的是如何扩展了我们谈到的早期数据集成的数据获取的理念。我们主要讨论了基础数据的获取或日志--事件和各类系统执行中产生的数据等。但是流处理允许我们包括了计算其它数据的数据。这些衍生的数据在消费者看来与他们计算的原始数据没什么差别。这些衍生的数据可以按任意的复杂度进行压缩。
+流处理最有趣的角度是它与流处理系统内部无关,但是与之密切相关的是如何扩展了我们谈到的早期数据集成的数据获取的理念。我们主要讨论了基础数据的获取或日志 —— 事件和各类系统执行中产生的数据等。但是流处理允许我们包括了计算其它数据的数据。这些衍生的数据在消费者看来与他们计算的原始数据没什么差别。这些衍生的数据可以按任意的复杂度进行压缩。
让我们再深入一步。我们的目标是:流处理作业可以读取任意的日志并把日志写入到日志或者其它的系统中。他们用于输入输出的日志把这些处理关联到一组处理过程中。事实上,使用这种样式的集中日志,你可以把组织全部的数据抓取、转化和工作流看成是一系列的日志和写入它们的处理过程。
@@ -48,7 +48,7 @@
日志集成的目标是双重的:
-首先,它确保每个数据集都有多个订阅者和有序的。让我们回顾一下状态复制原理来记住顺序的重要性。为了使这个更加具体,设想一下从数据库中更新数据流--如果在处理过程中我们把对同一记录的两次更新重新排序,可能会产生错误的输出。 TCP之类的链接仅仅局限于单一的点对点链接,这一顺序的持久性要优于TCP之类的链接,它可以在流程处理失败和重连时仍然存在。
+首先,它确保每个数据集都有多个订阅者和有序的。让我们回顾一下状态复制原理来记住顺序的重要性。为了使这个更加具体,设想一下从数据库中更新数据流 —— 如果在处理过程中我们把对同一记录的两次更新重新排序,可能会产生错误的输出。 TCP之类的链接仅仅局限于单一的点对点链接,这一顺序的持久性要优于TCP之类的链接,它可以在流程处理失败和重连时仍然存在。
第二,日志提供了流程的缓冲。这是非常基础的。如果处理流程是非同步的,那么上行生成流数据的作业比下行消费流数据的作业运行的更快。这将会导致处理流程阻塞,或者缓冲数据,或者丢弃数据。丢弃数据并不是可行的方法,阻塞将会导致整个流程图立即停止。 日志实际上是一个非常大的缓冲,它允许流程重启或者停止但不会影响流程图其它部分的处理速度。如果要把数据流扩展到更大规模的组织,如果处理作业是由多个不同的团队提供的,这种隔离性是极其重的。我们不能容忍一个错误的作业引发后台的压力,这种压力会使得整个处理流程停止。
@@ -56,7 +56,7 @@ Storm和Sama这两者都是按非同步方式设计的,可以使用Kafka或者
### 有状态的实时流处理
-一些实时流处理在转化时是无状态的记录。在流处理中大部分的应用会是相当复杂的统计、聚合、不同窗口之间的关联。例如有时人们想扩大包含用户操作信息的事件流(一系列的单击动作)--实际上关联了用户的单击动作流与用户的账户信息数据库。不变的是这类流程最终会需要由处理器维护的一些状态信息。例如数据统计时,你需要统计到目前为止需要维护的计数器。如果处理器本身失败了,如何正确的维护这些状态信息呢?
+一些实时流处理在转化时是无状态的记录。在流处理中大部分的应用会是相当复杂的统计、聚合、不同窗口之间的关联。例如有时人们想扩大包含用户操作信息的事件流(一系列的单击动作) —— 实际上关联了用户的单击动作流与用户的账户信息数据库。不变的是这类流程最终会需要由处理器维护的一些状态信息。例如数据统计时,你需要统计到目前为止需要维护的计数器。如果处理器本身失败了,如何正确的维护这些状态信息呢?
最简单的替换方案是把这些状态信息保存在内存中。但是如果流程崩溃,它就会丢失中间状态。如果状态是按窗口维护的,流程就会回退到日志中窗口开始的时间点上。但是,如果统计是按小时进行的,那么这种方式就会变得不可行。
@@ -66,7 +66,7 @@ Storm和Sama这两者都是按非同步方式设计的,可以使用Kafka或者
回顾一下关于表和日志二相性的讨论。这一机制提供了工具把数据流转化为与处理过程协同定位的表,同时也提供了这些表的容错处理的机制。
-流处理器可以把它的状态保存在本地的表或索引--[bdb](http://www.oracle.com/technetwork/products/berkeleydb),或者[leveldb](https://code.google.com/p/leveldb),甚至于类似于[Lucene](http://lucene.apache.org/) 或[fastbit](https://sdm.lbl.gov/fastbit)一样不常见的索引。这些内容存储在它的输入流中(或许是使用任意的转化)。生成的变更日志记录了本地的索引,它允许存储事件崩溃、重启等的状态信息。流处理提供了通用的机制用于在本地输入流数据的随机索引中保存共同分片的状态。
+流处理器可以把它的状态保存在本地的表或索引 —— [bdb](http://www.oracle.com/technetwork/products/berkeleydb),或者[leveldb](https://code.google.com/p/leveldb),甚至于类似于[Lucene](http://lucene.apache.org/) 或[fastbit](https://sdm.lbl.gov/fastbit)一样不常见的索引。这些内容存储在它的输入流中(或许是使用任意的转化)。生成的变更日志记录了本地的索引,它允许存储事件崩溃、重启等的状态信息。流处理提供了通用的机制用于在本地输入流数据的随机索引中保存共同分片的状态。
当流程运行失败时,它会从变更日志中恢复它的索引。每次备份时,日志把本地状态转化成一系列的增量记录。
@@ -79,6 +79,8 @@ Storm和Sama这两者都是按非同步方式设计的,可以使用Kafka或者
日志压缩
------------------------
+
+
当然,我们不能奢望保存全部变更的完整日志。除非想要使用无限空间,日志不可能完全清除。为了澄清它,我们再来聊聊Kafka的实现。在Kafka中,清理有两种选择,这取决于数据是否包括关键更新和事件数据。对于事件数据,Kafka支持仅维护一个窗口的数据。通常,配置需要一些时间,窗口可以按时间或空间定义。虽然对于关键数据而言,完整日志的重要特征是你可以重现源系统的状态信息,或者在其它的系统重现。
随着时间的推移,保持完整的日志会使用越来越多的空间,重现所耗费的时间越来越长。因些在Kafka中,我们支持不同类型的保留。我们移除了废弃的记录(这些记录的主键最近更新过)而不是简单的丢弃旧日志。我们仍然保证日志包含了源系统的完整备份,但是现在我们不再重现原系统的全部状态,而是仅仅重现最近的状态。我们把这一特征称为[日志压缩](https://cwiki.apache.org/confluence/display/KAFKA/Log+Compaction)。
diff --git a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part4.md b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part4.md
index 0fc3701..f6a4369 100644
--- a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part4.md
+++ b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/part4.md
@@ -8,7 +8,7 @@
分类计价吗?
-----------------
-如果换个角度,你可以看到把整个组织系统和数据流看做是单一的分布式数据系统。你可以把所有的子查询系统(诸如Redis, SOLR,Hive表等)看成是数据的特定索引。你可以把Storm或Samza一样的流处理系统看成是发展良好的触发器和视图具体化机制。我已经注意到,传统的数据库管理人员非常喜欢这样的视图,因为它最终解释了这些不同的数据系统到底是做什么用的--它们只是不同的索引类型而已。
+如果换个角度,你可以看到把整个组织系统和数据流看做是单一的分布式数据系统。你可以把所有的子查询系统(诸如Redis, SOLR,Hive表等)看成是数据的特定索引。你可以把Storm或Samza一样的流处理系统看成是发展良好的触发器和视图具体化机制。我已经注意到,传统的数据库管理人员非常喜欢这样的视图,因为它最终解释了这些不同的数据系统到底是做什么用的 —— 它们只是不同的索引类型而已。
不可否认这类数据库系统现在大量的出现,但是事实上,这种复杂性一直都存在。即使是在关系数据库系统的鼎盛时期,组织中有大量的关系数据库系统。或许自大型机时代开始,所有的数据都存储在相同的位置,真正的集成是根本不存在的。存在多种外在需求,需要把数据分解成多个系统,这些外在需求包括:规模、地理因素、安全性,性能隔离是最常见的因素。这些需求都可以由一个优质的系统实现:例如,组织可以使用单一的Hadoop聚簇,它包括了全部的数据,可以服务于大型的和多样性的客户。
@@ -49,7 +49,7 @@
下面我们来看下该系统是如何工作的。系统被分为两个逻辑区域:日志和服务层。日志按顺序捕获状态变化,服务节点存储索引提供查询服务需要的所有信息(键-值的存储可能以B-tree或SSTable的方式进行,而搜索系统可能存在与之相反的索引)。写入器可以直接访问日志,尽管需要通过服务层代理。在写入日志的时候会产生逻辑时间戳(即log中的索引),如果系统是分段式的,那么就会产生与段数目相同数量的日志文件和服务节点,这里的数量和机器数量可能会有较大差距。
-
+
服务节点订阅日志信息并将写入器按照日志存储的顺序尽快应用到它的本地索引上。
diff --git a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/the-end.md b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/the-end.md
index 677cafd..0bec89a 100644
--- a/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/the-end.md
+++ b/log-what-every-software-engineer-should-know-about-real-time-datas-unifying/the-end.md
@@ -51,11 +51,11 @@
企业级软件存在着同样的问题,只是名称不同,或者规模较小,或者是XML格式的。哈哈,开个玩笑。
-- [事件驱动](http://cs.brown.edu/research/aurora/hwang.icde05.ha.pdf)--据我所知:它就是企业级应用的工程师们常说的“状态机的复现”。有趣的是同样的理念会用在如此迥异的场景中。事件驱动关注的是小的、内存中的使用场景。这种机制在应用开发中看起来是把发生在日志事件中的“流处理”和应用关联起来。因此变得不那么琐碎:当处理的规模大到需要数据分片时,我关注的是流处理作为独立的首要的基础设施。
-- [变更数据捕获](http://en.wikipedia.org/wiki/Change_data_capture)--在数据库之外会有些对于数据的舍入处理,这些处理绝大多数都是日志友好的数据扩展。
+- [事件驱动](http://cs.brown.edu/research/aurora/hwang.icde05.ha.pdf) —— 据我所知:它就是企业级应用的工程师们常说的“状态机的复现”。有趣的是同样的理念会用在如此迥异的场景中。事件驱动关注的是小的、内存中的使用场景。这种机制在应用开发中看起来是把发生在日志事件中的“流处理”和应用关联起来。因此变得不那么琐碎:当处理的规模大到需要数据分片时,我关注的是流处理作为独立的首要的基础设施。
+- [变更数据捕获](http://en.wikipedia.org/wiki/Change_data_capture) —— 在数据库之外会有些对于数据的舍入处理,这些处理绝大多数都是日志友好的数据扩展。
- [企业级应用集成](http://en.wikipedia.org/wiki/Enterprise_application_integration),当你有一些现成的类似客户类系管理CRM和供应链管理SCM的软件时,它似乎可以解决数据集成的问题。
- [复杂事件处理(CEP)](http://en.wikipedia.org/wiki/Complex_event_processing)没有人知道它的确切涵义或者它与流处理有什么不同。这些差异看起来集中在无序流和事件过滤、发现或者聚合上,但是依我之见,差别并不明显。我认为每个系统都有自己的优势。
-- [企业服务总线(ESB)](http://en.wikipedia.org/wiki/Enterprise_service_bus)--我认为企业服务总线的概念类似于我所描述的数据集成。在企业级软件社区中这个理念取得了一定程度的成功,对于从事网络和分布式基础架构的工程师们这个概念还是很陌生的。
+- [企业服务总线(ESB)](http://en.wikipedia.org/wiki/Enterprise_service_bus) —— 我认为企业服务总线的概念类似于我所描述的数据集成。在企业级软件社区中这个理念取得了一定程度的成功,对于从事网络和分布式基础架构的工程师们这个概念还是很陌生的。
一些相关的开源软件: