--- layout: post title: I love log 读书笔记 category: 技术 tags: Kafka keywords: description: --- {:toc} # 原书作者 Jay Kreps: kafka 的创始人,Linkedin 的首席科学家 # 什么是log? ## 最常见的log ``` 2019-07-29 11:04:34.688 - - [INFO] main RequestMappingHandlerMapping Mapped "{[/api/thrift/getAllBlockedList],methods=[GET]}" onto public com.test.oh.hecate.thrift.PoiIdsShopIdsResp com.test.hecate.web.api.ThriftController.test1() 2019-07-29 11:04:34.692 - - [INFO] main RequestMappingHandlerMapping Mapped "{[/search/searchItems],methods=[GET]}" onto public com.test.oh.hecate.response.BaseResponse> com.test.oh.hecate.web.api.SearchController.getSearchItems() 2019-07-29 11:04:34.692 - - [INFO] main RequestMappingHandlerMapping Mapped "{[/search/pageAndSortHistory],methods=[GET]}" onto public com.test.oh.hecate.response.PageListResponse com.test.oh.hecate.web.api.SearchController.pageAndSortHistory(int,int) 2019-07-29 11:04:34.693 - - [INFO] main RequestMappingHandlerMapping Mapped "{[/search/download/request],methods=[GET]}" onto public com.test.oh.hecate.response.BaseResponse com.test.oh.hecate.web.api.SearchController.download(java.lang.String) ``` 这种是写业务的程序员最常见的日志信息,结构化的可视化的日志信息。 但这种日志并非是 log 的全部,这些只是些业务日志,还有些日志时一般程序员平时接触不到的。但是重要的是我们将日志视为抽象数据结构,而不是文本文件 ## 其他 log log和文件或表没有任何区别,文件是字节数组,而表述记录的数组。而 log 实际上只是一种文件或表,其中的记录按照时间排好了序。 此时你可能会想,“为什么值得谈论这么简单的事情?”与数据系统有关的以仅追加的记录序列如何?答案是日志有一个特定的目的:它们记录了什么 发生了什么时候。 对于分布式数据系统,这在许多方面都是问题的核心 ### 数据库中的 log 1. 在数据库中的 log与系统崩溃时保持各数据结构和索引有关,为了使得log 是原子和可持久的,在数据库变更前,会将修改的信息记录并持久下来。因为 log 是立即持久的,因此可以在系统崩溃时作为数据恢复的权威来源。 2. 在数据库间进行远程副本同步。比如 mysql 的主从结构等。oracle,mysql,mongo 等都有日志传输协议将数据副本传输到作为从库的远程节点上。这样可以保持主从一致。 ### 分布式系统中的 log 在分布式系统中的日志使用方式其实是早期数据库中 log的两种使用方式的变种: 1. log 用于发布/订阅机制,在主从间传递数据副本 2. log 用于一致性机制,用于对应用的多个副本的更新保持有序。 状态机复制原理: 如果两个相同的确定性过程以相同的状态开始,以相同的顺序得到相同的输入,它们将产生相同的输出,并以相同的状态结束。 直观的概念就是: 对于相同的确定的代码片段,输入相同的 log,那么它们会按照相同的顺序产出相同的输出结果。 一句话总结: 确定性的处理是确定性的。 #### 对于不同的社区对状态机的描述不同: 1. 数据库社区会区分物理和逻辑日志。物理日志或者基于行的日志意味着记录更改的每一行的内容。逻辑日志或者声明日志不会记录改变的行,而是会记录导致行改变的 sql 命令。 2. 分布式系统文献通常描述两种广泛的处理和复制的方法。 1. 状态机模型:通常指的是主动模型,即保存输入请求的日志,每个副本都按日志顺序执行每个请求。所有节点都是对等的,先写入日志,所有节点按日志确定的顺序应用写入。 ![状态机模型](//raw.githubusercontent.com/George5814/blog-pic/master/image/state-machine-model.png) 2. 主备模型:状态机模型的改版。选举主节点,主节点按顺序处理请求,并将更改记录到由于处理请求而发生的状态。其他副本应用主节点的状态改变,保持同步并在主节点宕机后准备接替成为主节点。 ![主备模型](//raw.githubusercontent.com/George5814/blog-pic/master/image/primary-backup-model.png) 分布式日志可以被认为是模拟共识问题的模型。 对于Paxos,通常使用 `multi-paxos` 扩展协议,将日志建模为一系列的共识问题。一个用于日志中的每个槽。日志在其他协议中更为突出,比如 ZAB,RAFT 和Viewstamped Replication。他们直接模拟维护分布式一致日志的问题。 # 应用 ## 数据集成 术语`数据集成`不常见,通常有 ETL 术语,但是数据集成是 ETL 的超集。 通过统一的方式捕获数据,以统一的方式建模,就可以在此基础上以各种方式处理这些数据。比如:批处理(Mapreduce),流处理,实时查询等。 数据的处理可能需要基于类马斯洛的金字塔模型。 ![用于数据的类马斯洛金字塔模型](//raw.githubusercontent.com/George5814/blog-pic/master/image/maslow-like-model.png) ### 困扰数据集成的两种问题 1. 数据的多样化 1. 业务数据,如订单数据,用户数据和产品数据等 2. 事件数据或日志数据,如用户活动日志,机器日志和监控数据等,这些数据已经成为现代 web 的核心数据。 2. 专业数据系统的爆炸 ### 两种问题的解决办法 `日志结构的数据流` 日志是处理系统间数据流的自然数据结构。概念就是:`获取组织的日志数据,并将其放入日志中心系统中进行实时订阅。` 即以此理论实践出了`kafka`系统,多订阅用户系统。数据输出源和数据输出源可以是任意的系统。 而`kafka`作为以日志为基础的统一的数据管道,不管订阅者或发布者新增,删除,崩溃等情况,都不会影响管道的数据。 ## 数据流处理 **使用统一的数据管道前**的系统间数据传输的架构 ![使用统一的数据管道前的系统间数据传输的架构](//raw.githubusercontent.com/George5814/blog-pic/master/image/old-arch-between-systems.png) **使用统一的数据管道后**的系统间数据传输的架构 ![使用统一的数据管道后的系统间数据传输的架构](//raw.githubusercontent.com/George5814/blog-pic/master/image/new-arch-between-systems.png) 新架构使用同一的数据管道,使用`topic`术语区分不同的系统和业务的数据结构,简化了系统间对接的复杂度。数据生产者和数据使用者互相不知道,他们只需要知道有类似于`kafka`这样的统一的数据管道即可。 ## 实时流计算 ### 为什么流计算需要 log ? 1. log (如 kafka) 可以使得每个数据集都有多个订阅者 2. 确保每个数据消费者在处理过程中保持顺序.如果乱序可能会导致错误的结果。 3. 为每个处理进程提供数据的缓存和隔离 1. 上游生产快被阻塞。起初阻止听起来像是一个可接受的选择,但实际上变成了一个大问题。考虑到我们想要的不仅仅是对单个应用程序的处理进行建模,而是对整个组织的全部数据流进行建模。这将不可避免地成为不同团队拥有的处理器之间非常复杂的数据流网络,并以不同的服务级别协议运行。在这个复杂的数据处理网络中,如果任何一个消费者失败或者跟不上,上游生产者将会阻塞,阻塞将会通过数据流图级联起来,把所有的东西都碾成两半 2. 丢弃数据。某些情况可以,但一般不可取也不可接受。 3. 缓存数据隔离生产和消费两个进程。缓存在其他地方并不罕见。比如 复杂的MapReduce 会使用文件产生中间结果和 checkpoint。复杂的 Sql 会产生中间表等。 ### 对 Lambda 架构的评价和改进 参考文档: ## 有状态的流计算 如果实际的流式计算中确实需要保存状态,那这也是 log 的一种用途。 在流式计算中可能会需要统计总数,聚合或加入流窗口等操作。 当然会想到集中保存状态的方式 1. 将状态存在内存中。但是如果机器崩溃或重启后,内存中的数据就丢失了。 2. 状态存在远程的存储系统中。但这样就会引入的网络,可能会存在大量的网络传输。 3. 因为考虑到表和 log 的二重性,这为我们提供了能够将流转换为与我们的处理共存的表的工具,以及处理这些表的容错的机制 1. 可以将状态保存在本地表或索引中,如`bdb`,`rocksdb`,`lucene`,`fastbit`等,存储的内容从输入流中获取。当进程失败后,可以从变更日志中恢复索引。日志将本地状态转换为一次性增量记录备份。 2. 当与来自数据库的日志结合用于数据集成时,日志/表二元性的能力变得清晰。 可以从数据库中提取更改日志,并通过各种流处理器以不同形式编制索引以与事件流进行连接 ## 日志的作用 1. 通过对节点的并发更新排序来处理数据一致性(无论是最终的还是立即的) 2. 提供节点间的数据复制 3. 为作者提供“提交”语义(例如只有在保证不会丢失你的写入时才进行确认) 4. 从系统提供外部数据订阅源 5. 提供恢复丢失数据或引导新数据的失败副本的功能 6. 处理节点之间数据的重新平衡 7.