写在前面

最近在玩的同时,整理了一些之前的工作的内容,在重新翻看之前写的关于秒杀活动的代码,里面关键性的使用到了 Kafka 进行流量削峰,这是一个常规操作。我认为程序员的技术栈,不能只有“增删改查”,掌握 更多的底层技术,是一个非常明智的选择,这是我在刚入行时就知道的一个道理。从我进入大学开始,技术圈的风向似乎一直在变,大数据、云的热度似乎已经慢慢消退,现在当红的是 AI 和 loT。那不变的是什么,我想无论是大数据还是 AI,都是一个分布式系统,都要处理海量的数据,面对海量并发,它们需要解决的底层问题是一样的。所以我重新学习了 Kafka,或者说是 消息队列。

对于任何牛叉的项目,它的背后都离不开论文/博文的支持,比如当红的 ChatGPT,它的开山论文就是这篇《Improving Language Understanding by Generative Pre-Training》 。那对于 Kafka 来说,它的灵魂是这篇博客:The Log: What every software engineer should know about real-time data’s unifying abstraction,对应的中文译稿在这里:《日志:每个软件工程是都应该知道的有关实时数据的统一抽象》。这篇博客是 Kafka 的创始人 Jay Kreps 在 LinkedIn 工作时写的,他考虑将日志抽象作为任何分布式系统的关键部分。这不是 Kafka 的设计论文、实现或教程,而是导致其诞生的想法的酝酿过程,非常有意思。这篇博文被评为程序员史诗般必读文章,我花了一些时间去阅读并试图理解,结果收益匪浅,这篇文章可以看作我阅读这篇博文的笔记。

日志在数据管理中的核心角色:从概念到实用

在第一部份,作者聊到了日志是什么?。日志,是一种最简单的存储抽象,但在数据库和分布式系统中,它确实核心工具之一。本文探讨了日志在这两个重要领域中的应用,我将结合 Redis 和 MySQL 中的实例进行说明,并涉及相关的一致性算法。

数据库中的日志

日志在数据库系统中起到了保持数据一致性和支持数据恢复的重要作用。它记录了数据库中的所有变更操作,使数据库即使在崩溃后,也可以通过重放这些日志来恢复数据状态。数据库日志不仅实现了 ACID 特性的持久性,还支持数据库之间的数据复制。

例如,MySQL 的 Binlog 就是记录数据变更的重要工具。通过将所有的写操作记录下来,MySQL 能够在发生故障时重建数据,也能够实现主从复制,在主从架构中,主库通过 Binlog 同步数据变更到从库,从而在多个数据库实例之间保持一致性。所以,当我们在讨论 MySQL 的高可用时,离不开主从复制,也就离不开日志。此外,MySQL 的事务也以来日志来实现 ACID 特性: Rede Log 提供数据持久化保障,Undo Log 支持事务回滚和多版本并发控制。日志不仅让数据库具备了强大的容错能力,还未复杂的分布式系统提供了可靠的底层支持。

分布式系统中的日志

在分布式系统中,日志解决了变更操作的排序和数据分发,这是分布式系统的一大核心问题。在这种环境中,日志充当了时间流的角色。根据状态机复制原理,当相同的输入以相同的顺序被分发到多个节点时,这些节点会保持一致的状态。这种原理在实现系统一致性中至关重要。

在这一趴中,有几个关键点和基础概念需要重点理解。

  1. 日志的作用:日志用于解决分布式系统中的两个重要问题:变更操作的排序和数据的分发。确定变更操作的顺序是分布式系统设计的核心问题之一,因为多个节点(应用实例)可能同时对同一份数据进行修改。
  2. 状态机复制原理:文章提到了一个称为“状态机复制原理”的概念,它指出如果两个进程是确定性的(即相同的输入和初始状态总能产生相同的输出和最终状态),那么它们只需获得相同的有序输入,就能保持一致性。是不是很难懂?简单理解就是:两个或多个相同的程序或应用实例,它们遵循相同的逻辑和操作步骤,比如 MySQL 主从架构。
  3. 确定性和状态:
    1. 确定性意味着进程的执行不会因为外部因素(如当前时间或线程调度)而改变。
    2. 进程的状态是指,在执行过程中存储的数据,可以保存在内存或磁盘上。
  4. 两种日志应用模型:
    1. 主-主模型:每个副本独立处理输入请求,并记录输入请求的日志。
    2. 主备模型:一个主节点(leader)按顺序处理请求并记录状态变化日志,其他副本应用这些变化以确保同步。
    3. 文章写了一个不太严谨的例子,说的是要将一个变量进行加法和乘法计算。比如对 0 进行 +1 和 *2。主-主模型的做法是每个副本(这次说是副本,其实就是应用实例/进程/节点,都可以啦,理解就好)都执行一遍 +1 和 *2,从而经过一系列相同的值,并得到相同的结果。而主备模式,会有一个单独的节点(leader 或 master)执行 +1 和 *2,得到结果后同步给其他副本。
  5. 一致性协议和日志:文章提到了一些一致性协议,如 Paxos、ZAB 和 RAFT,这些协议常用于维护分布式一致的日志。日志在这些协议中的角色是 存储决策序列,从而实现一直的状态。

对于后面提到的一致性算法,如Paxos和Raft 以日志为基础,帮助系统在网络不稳定或节点故障的情况下保持数据一致性。这里我相对熟悉的是 Raft 协议,Raft 被广泛应用于 etcd 等系统中,通过日志记录于处理,实现系统的高可靠性和一致性。相对于 Paxos 协议,Raft 相对易于理解和实现,并且提供了类似的功能和一致性保障。

一句话总结:分布式系统中,日志通过排序和分发变更操作,结合状态机复制原理和一致性协议,确保多个节点在不确定的网络环境中实现数据的一致性和系统的高可靠性。

变更日志101:表与事件的二象性

光看标题,就够抽象的了。

好在文章不算难懂,总结起来便是,日志与数据库表之间,有着一种迷人的二象性:日志记录的是所有变更(如银行流水),而表表示数据在某一时刻的状态(如账户余额)。通过变更日志,系统可以重建任何过去的状态,也可以支持准实时的数据复制。日志不仅在数据库中重要,在版本控制系统中同样如此。

Redis 的 AOF 日志就是一个具体的例子,MongoDB 也有类似机制:通过记录对数据的所有命令,Redis 可以在系统重启后恢复数据,确保数据的一致性和持久性。在 AOF 模式下,Redis 会将每一个写操作(如增加、修改或删除键值对)记录为一条命令,并追加到一个日志文件中。AOF 日志中的这些命令可以在 Redis 重启时被重新执行,以重建数据集。不过与此同时,使用 AOF 会引入一定的写入开销,这是题外话了。

这里我借用 Redis 来解释了我对 变更日志 的理解,Redis 的 AOF 是变更日志概念在实用中的一个具体实现。它利用变更日志的方法来确保数据在高性能的内存数据库中的安全性和一致性。

数据集成:从可靠数据流到 Kafka 的核心角色

在第二部分,作者认为,数据集成是指将一个组织的所有数据对其所有服务和系统可用。一个组织必须先拥有可靠和完整的数据流,否则无论多强大的数据处理工具,如 Hadoop 都无济于事。如果缺乏这些基础,组织直接尝试高级数据技术是本末倒置的。

两个难题

接着讨论了数据集成变得更加复杂的两个主要趋势,即 事件数据管道 和 专用数据系统 的爆发,这两个趋势导致了数据集成复杂性的大幅增加,需要新的解决方案来应对这些变化。

  1. 事件数据管道:记录发生的每一件事

    想象一下,我们每天上网浏览、点击广告、购物,这些行为都会被记录下来,称为“事件数据”。和传统的数据库记录(比如一个订单信息)不同,事件数据更像是一种实时的行为跟踪,比如“某人点击了这个页面”“某台机器出现了警报”等。

    • 举个例子:像谷歌这样的公司会记录用户的点击和广告展示数据,用来优化广告投放和相关性推荐。
    • 这种趋势不仅在互联网公司里常见,也开始在其他领域扩展,比如记录股票交易的金融数据,或者通过 RFID(射频识别)技术跟踪物流中的包裹位置。
    • 难点在于,这种事件数据量非常大,远远超过传统数据库能轻松处理的范围。这就让处理和集成这些数据变得越来越困难。
  2. 专用数据系统的爆发:每个问题都有专门的工具

    另一个趋势是,用于不同用途的 “专用数据系统” 越来越多。

    • 举个例子:如果你需要做报表分析,会用专门的分析系统(OLAP);如果你想做搜索功能,可能会用 Elasticsearch;而存储普通数据可能会用简单的数据库;再比如处理超大量数据可能用到批处理工具(像 Hadoop)。
    • 这些系统就像是各种各样的电器,每个都有它的专长,但问题是,当数据需要在这些系统之间流转时,就会变得非常复杂。比如,从记录用户点击的事件数据系统中提取数据,再同步到做报表分析的系统中,就像要让洗衣机和烤箱配合工作一样复杂。

也就是说,随着越来越多的行为被记录成事件数据,加上各种 “专用工具” 的出现,数据集成就像一场复杂的 “数据搬运工” 工作。它需要把这些数据从一个系统搬到另一个系统,还得保证快速、高效和准确,这无疑是对当时的技术提出了巨大的挑战。

日志结构化的数据流

提取所有组织的数据,并放到一个用于实时订阅的中心日志中

为了应对两个难题带来的复杂性,作者提出了一种策略:用日志结构化的数据流来解决数据集成的问题。这种方法的核心是用日志集中管理数据流,从而实现系统间的高效同步和异步处理。这背后正是 Kafka 的设计理念。这部分作者使用的篇幅并不多,我进行了一些总结,下面我用通俗的方式讲解,并结合 Kafka 的应用来说明。

  1. 日志作为自然的数据结构:日志就像一本时间顺序记录事件的账簿,可以用来提取和汇总所有数据,提供给需要的系统做实时订阅。每个数据源(如用户操作、订单记录)都对应自己的日志,订阅方只需从日志中获取数据更新自身状态。 在 Kafka 中,主题(Topic)就是这种日志结构的具体实现,所有事件按顺序写入主题,消费者从主题订阅数据更新自己。
  2. 一致性与时间点:每个数据变更都被日志记录下来,附带逻辑顺序(像时间戳),订阅系统可以根据顺序判断自己的状态是否与其他系统一致。通过日志可以追溯到任何时间点,避免数据遗漏。在 Kafka 中, 使用 Offset(位移)记录消费者处理到的日志位置,支持从任意时间点读取数据,实现一致性恢复。
  3. 异步处理与灵活性:日志可以作为“缓冲区”,解耦数据生产和消费速度。即使数据生成很快,慢速处理的系统也可以按自己的节奏消费数据,避免系统压力过大。即允许系统中不同的服务可以按照自己的节奏处理数据,无需同步更新。在 Kafka中,生产者可以快速写入数据,消费者则根据自己的能力按需消费。即使消费者掉线,Kafka 仍然保留数据,确保不会丢失。关联 “流量削峰”。
  4. 简化数据集成:通过日志,生产系统与订阅系统解耦,订阅系统无需了解数据源的细节,只需读取日志即可完成集成。这让系统扩展更简单,添加或移除系统时不会影响整体流程。Kafka 的主题将数据源与消费者解耦,一个主题可以同时支持多个订阅者(如报表生成系统和实时监控系统),且互不干扰。
  5. 日志与消息队列比较:相比传统的消息队列,作者使用 “日志” 这个术语,作者认为 “日志” 是一种持久化且有序的消息模型,消费者可以随时从任何位置读取历史数据,而不仅仅是处理最新消息。这种模型更适合分布式数据集成和数据复制场景。Kafka 允许配置日志的保留策略,数据可以保存数天甚至永久,支持消费者重读和数据回溯,远比传统消息队列灵活。

不过,尽管日志是数据流集成的基础,但它只是整个数据管理故事的一部分。其他重要部分包括元数据、schemas、兼容性等,旨在处理数据结构及演变。

这一小节,作者强调 日志结构化的数据流可以作为构建可靠数据集成基础设施的有效方法,提供一种标准化的方式就可以处理组织内庞大的数据流,确保各种数据订阅系统顺畅地获取和处理处理。

在 LinkedIn

在 LinkedIn 的实践中,日志结构化的数据流被证明是解决分布式系统数据集成复杂性的有效方法。随着 LinkedIn 从集中式数据库向分布式系统(如 Voldemort、Espresso 和 Hadoop)转型,数据集成的难度显著增加,尤其是在多源多目标的数据加载中,传统方式因管道复杂性爆发(O(N²))而难以为继。通过开发 Kafka,LinkedIn 将日志结构化的理念具体化,构建了一个统一、可靠的异步数据流平台,简化了系统间的集成,减少了直接访问数据库的负担,并支持了多种实时和批处理场景。Kafka 成为了数据系统的中心管道,大大提升了系统扩展性和操作的自动化水平,也为行业提供了一个成功的实践样本。

LinkedIn 的经验表明,通过中心化的数据流管理和日志架构设计(也就是 Kafka),可以大大简化数据集成过程,并支持系统的灵活扩展。

ETL 与数据仓库的关系

这部分讨论了传统数据仓库的理念和局限性,以及如何通过重型化日志的方式来优化整个数据集成流程。我也是第一次在这里听说数据仓库的概念,传统的数据仓库让我们可以把所有数据规整化,集中存储,用于分析和报表。作者表示这个方式有点过时,尤其是面对实时数据需求的时候,显得力不从心。

这里我专门去学习了这个概念,原来传统的数据仓库是以前(但也没有特别久远)的主流技术理念,它解决了数据分析的一个核心需求:把分散在不同系统里的数据整合起来,存储在一个中心位置,用于报表和分析。数据仓库本身不是一个单一的产品,而是一种系统架构或者技术理念,用来解决数据集成、存储和分析的问题。

以前的场景是怎么样的?

业务数据分散,难以分析。比如一个企业,它的业务系统可能有多个:一个负责销售订单管理,一个负责库存管理,一个负责客户关系管理(CRM),甚至还有一些历史遗留的手工系统或 Excel 表格。这些系统之间数据完全独立,彼此不通,想要从整体上了解企业的运营情况,比如 “哪个产品卖得最好” 或 “库存周转是否正常”,非常困难。

数据仓库的出现解决了这个问题:它会从不同的业务系统中定期抽取数据(通常是每天或每周一次),清洗和规整这些数据,比如统一格式、去掉无用字段,然后以适合分析的方式存储到中心仓库里。这个仓库的数据通常是只读的,专门为复杂的报表和分析设计。

举个例子:销售系统的数据会被抽取到数据仓库中,用来统计销售额。客户管理系统的数据也会被抽取过来,用来分析客户的购买习惯。最后,这些数据可以被其他工具利用,比如用来生成销售趋势图,生成预测行为模型等等。

数据仓库过时的原因

文章指出了一些仓库的缺点和局限性:

  1. 实时机制过时,数据仓库中基于 ETL 的批处理系统,没有很好的支持实时数据处理,也就是说数据是 “过期” 的,比如今天的报表只能分析到昨天的数据。如果企业需要实时查看销售请求或者库存变化,传统的数据仓库就没有办法实现。
  2. 批处理的局限性,数据仓库一般是基于批处理查询的基础设施,只适合处理报表和临时性分析,尤其是简单的技术、聚合与过滤。这种结构不支持实时处理需求,例如实时搜索引擎和监控。
  3. 此外文章还提到了 ETL 过程的复杂性和不对称性,以及扩展性的问题。

ETL 是 Extract, Transform, Load 的缩写,中文可以翻译为 提取、转换、加载。它是一种数据集成过程,广泛用于 数据仓库数据集成数据分析 场景。

为了克服这些局限性,作者提出使用 中心化日志管道和数据规范化策略作为改进方案。

  1. 引入一个中心日志系统(其实就是 Kafka)作为整个数据流的核心管道。(这样我想到 Go 中的 channel 也有类似的效果,不过颗粒度小很多就是了)。数据生产者通过结构化的数据通过 API 推送到 Kafka(这里我直接使用 Kafka 代替了,原文用的是中央日志系统)。这样,所有数据就能在一个标准化的环境中被访问和处理。
  2. 数据生产者负责确保其数输出数据的规范化和结构化。这个策略确保了数据在进入 Kafka 之前已经被处理为标准形式,避免了将系统特定的负责遗留到后面的系统,比如数据仓库,或者其他消费系统。(这个策略在如今看来,已经是行业标准,但相信在当时的情景下,这是一个相对新颖且具有挑战性的观点。)

日志文件与事件

这一部分讨论了通过中心化日志系统实现事件驱动架构的优点,特别是在解耦复杂系统中的重要性。从我的理解来看,这种架构方法能够显著提升灵活性和可扩展性。在传统的批处理模式下,数据流通常紧密耦合于特定的处理计划,这限制了系统的动态响应能力。通过将事件数据发布到一个中心化的日志系统(Kafka),不同的系统可以独立于数据生产者来订阅所需的信息,实现了真正的解耦。这就意味着,像职位显示这样的简单功能可以保持简单,因为额外的复杂逻辑被推迟到订阅数据的消费者中处理。这样不仅简化了代码维护,也减少了系统间耦合带来的理解和协作的困难。这种事件驱动的模式有效地支持了多终端和多功能需求,同时能快速适应变化,增强了系统的韧性。

作者举了一个在 LinkedIn 的例子展示了中心化日志系统如何支持事件驱动架构,使复杂的系统得以解耦。

  1. 发送数据到Hadoop和数据仓库中,以做离线数据处理
  2. 浏览计数,确保查看者不是一个内容爬虫
  3. 聚合浏览信息,在职位提交者的分析页面显示
  4. 记录浏览信息,确保合适地设置了用户的推荐职位的展示上限(不想重复地展示同样内容给用户)
  5. 推荐系统可能需要记录浏览,以正确的跟踪职位的流行程度
  6. 等等

这里我举一个更常见的案例,例如,在电商平台的购物车系统中,用户添加商品到购物车这一行为可以作为一个事件被记录到日志系统。不同的消费者系统如库存管理系统、推荐系统和分析系统可以订阅这些事件进行相应的操作。库存系统可以实时更新库存信息,推荐系统可以基于用户的购物偏好调整推荐商品,而分析系统可以在后台进行消费行为分析。购物车系统不需要关心这些消费者的实现细节,只专注于自身的核心功能。

事件驱动架构的优势在于它提供了一种高效、灵活的方式来处理复杂的业务逻辑,使每个组件可以独立发展,并通过松耦合的设计实现更高的可扩展性和维护性。

构建可伸缩的日志

在第二部分的最后一小节,作者分享了 Kafka 可伸缩性的一些核心技术和设计思想。作者提出,把发布者和订阅者分离不是什么新鲜事,但是如果要给一个需要按用户扩展的(consumer-scale)网站提供多个订阅者的实时提交日志, 那么可伸缩性就会成为你所面临的首要挑战。 也就是说,但用户量越来越多,数据越来越庞大的时候,可扩展性(可伸缩性)就必须要得以突破。LinkedIn 的案例展示了 Kafka 如何处理每天超过 600 亿条消息,体现了强大的处理能力和效率。

Kafka 的关键策略包括,

  1. 日志分片
  2. 通过批量读出和写入来优化吞吐量
  3. 规避无用的数据拷贝

如今我们都知道,Kafka 是不支持全局顺序的,这看似是一个局限,但在实际应用中,并没有对系统效率和功能产生重大负面影响,因为大多数处理和消费流程主要依赖于每个分区内部的顺序性。并通过保证同一键的消息到达同一分区,确保了这些消息的顺序交付。Kafka 通过为每个分区实现多个副本来确保数据的高可用性。具体而言,每个分区的日志都有一个主副本 leader,负责处理读写请求,而其他副本(followers)则复制 leader 的数据。在主节点出现故障时, Kafka 会自动选举一个新的主副本,以确保系统的连续性。此外,leader 和 followers 之间,不会部署在同一个 Broker(可以视为一个服务器),从而避免 Broker 出现故障时,该主题的所有副本失效。这种机制提供了强大的容错性,使得 Kafka 可以在硬件或网络故障的情况下维持服务。

Kafka 还通过对顺序读写的优化和批处理操作来提高吞吐量。通过将小的读写操作合并成更大的顺序读写,Kafka 减少了系统的 I/O 开销。而通过 0 拷贝技术等优化措施,Kafka 在网络和磁盘读写时也能保持高效,即便数据量远超内存大小。这些优化措施确保 Kafka 在处理大量数据时既迅速又可靠。

Kafka 的高性能 I/O 是如何实现的?

这是我另外扩展的内容,不属于原文,但却是 Kafka 实现高性能 I/O 的关键。

前面说了,Kafka 通过批量处理和顺序读写来提升服务端的处理能力。

在服务端,Kafka 不会把一批消息再还原成多条消息,再一条一条地处理,这样太慢了。Kafka 这块儿处理的非常聪明,每批消息都会被当做一个“批消息”来处理。也就是说,在 Broker 整个处理流程中,无论是写入磁盘、从磁盘读出来、还是复制到其他副本这些流程中,批消息都不会被解开,一直是作为一条“批消息”来进行处理的。构建批消息和解开批消息分别在发送端和消费端的客户端完成,不仅减轻 Broker 的压力,最重要的是减少 Broker 处理请求的次数,提升了总体的处理能力。这就是 Kafka 用批量消息在网络 I/O 方面提升性能的方法,那在磁盘 I/O 这块,Kafka 是如何做的呢。

对于磁盘来说,它有一个特性,就是顺序读写的性能要远远好于随机读写。因为顺序读写只需一次寻址操作即可连续读写数据,从而减少了繁重的寻址时间开销。这一点在传统机械硬盘上尤为突出,因为机械硬盘需要移动磁头来定位数据位置,而这种机械运动相对较慢。Kafka 利用这一特性,通过设计使其数据存储简单而高效。每个分区收到的消息被顺序地写入日志文件,当文件写满便切换到新文件继续顺序写入。消费者在读取消息时也是从某一位置开始顺序地读取。这样一个简单的设计,充分利用了顺序读写这个特性,极大提升了 Kafka 在使用磁盘时的 I/O 性能。

除了使用这两个方法,Kafka 还利用操作系统的 PageCache 来优化消息读写性能。PageCache 是操作系统用来在内存中缓存磁盘文件的机制,使得程序在读写文件时首先操作的是内存中的缓存副本,而非直接访问磁盘。当程序写入数据时,操作系统会先将数据写入 PageCache,然后再批量写入磁盘。这不仅加快了写操作,还帮助节省了磁盘 I/O 资源。读操作则优先从 PageCache 中读取,如果缓存命中,就能直接返回结果,节省从磁盘读取的时间;否则,操作系统会触发缺页中断,将数据加载到 PageCache,再供应用取用。是不是觉得似曾相识,没错,我们常见的缓存方案也是这么回事儿,比如将数据放在缓存中(Redis、本地缓存),读取的时候先从缓存读取。更新数据的时候,就可以先更新缓存,后面再慢慢刷到数据库中。这个方案再很多地方都使用过,再比如:MySQL 的 Buffer Pool,当读取数据时,先从 Buffer Pool 读取,没有就去磁盘读取。修改数据时,先修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页,最后异步将脏页写入磁盘。这个方案,虽然实现的细节各不相同,但整体的思路都一样,屡试不爽。这里我们有点飘了,回到正题来。Kafka 通过依赖操作系统的 PageCache 特性,大大优化了其消息读写效率,实现了更高的吞吐量和性能。

最后,Kafka 还使用了另一个操作系统特性来提升性能,也就是文章提到的 0 拷贝技术。在传统的数据传输过程中,数据往往需要进行多次复制:从磁盘到 PageCache,从 PageCache 到应用程序内存,再从应用程序内存到 Socket 缓冲区。这种多次复制通常会消耗大量的 CPU 资源。通过零拷贝技术,Kafka 可以直接从 PageCache 将数据传输到 Socket 缓冲区,减少了一次内存复制操作。文章还特别说明 Kafka 是使用 二进制 格式进行编码的,也正是这个原因,Kafka 才可以使用包括 [0 拷贝技术] 在内的大量优化机制。

零拷贝在 Unix/Linux 系统中通常通过 sendfile 系统调用来实现。这个调用允许直接将文件的数据传输到网络套接字,不经过应用程序层的处理。当面对从文件读取数据并发送到网络的操作,且无需对数据进行处理时,使用零拷贝技术可以显著提升性能。

这里思维扩散的有点太多了,我们尽快回到《日志:每个软件工程师都应该知道的有关实时数据的统一抽象》中吧~

日志与实时流处理 | 系统构建

写到这里,我已经花了一两天的时间。下面我就不再大篇幅的进行细致的笔记了。我把第三部份《日志与实时流处理》和第四部份《系统构建(system building)》大致总结一下。

在第三部份,讨论了流处理作为持续处理数据流的基础设施,强调其在现代数据集成中的重要性,并介绍如何通过 Kafka 实现高效的数据流管理与状态恢复。举个例子,我们在逛淘宝的时候,会有实时的推荐系统在工作。Kafka 可以在其中处理和传递用户的行为时间,比如在用户浏览或点击某个商品(一双鞋)时,这个事件就会被收集并立即发送到 Kafka。流处理引擎,比如 Apache Storm 从 Kafka 中消费这个流数据事件,实时分析用户的行为,并生成个性化的商品推荐。你继续逛的时候会发现,类似的商品又一次出现了,大数据杀熟哈哈~ 那通过 Kafka,系统就能够高效、低延迟地传递大量事件数据,确保推荐系统能够迅速响应用户的实时行为变化,提升用户体验。不知道你还记得前面我们讨论到的 “数据仓库” 吗。在上面逛淘宝这个案例过程中,流处理系统可以持续地接受事件流,进行快速的处理和分析,而不需要等到数据成批后进行批量处理。这就是 Kafka 的一个实际应用。(当然,淘宝应该不是用 Kafka,而是用阿里自家的 RocketMQ 或RabbitMQ)

在第四部份,探讨了 Kafka 在 在线数据系统 中的作用,强调其在数据流、一致性与可恢复性中的关键角色。Kafka 类似于大型组织中的数据集成工具,将分布式系统的复杂性简化为可共享的数据流管理。作者通过 LinkedIn 的实时查询系统进行举例,Kafka 作为日志系统用于捕获数据变化。这些变化被不同的服务节点订阅并索引。例如,用户活动数据通过Kafka 流入系统,各个服务节点根据需要将这些数据索引为快速查询结构,如全文搜索索引或图数据库结构,提供给搜索和推荐系统。这种方式使得日志既是数据传输的中枢,也简化了服务节点数据的管理与恢复。

这两个应用都充分利用了 Kafka 处理大量实时数据的高吞吐量、低延迟和高可靠性,在文章中,作者都是以 “日志系统” 来指代 Kafka。虽然其被描述成一种分布式日志系统,但它的核心功能其实更偏向于消息传递和数据流的管理。通过将数据更新和事件记录到主题中,Kafka 允许多个消费者订阅并处理这些日志流。

结束语

感谢你能读到这里,关于这篇文章的分享就到这里就要结束了。

最后我们总结一下,文章的核心观点是:日志不仅是记录数据变更的工具,更是一种强大的系统抽象,用于统一管理分布式系统中的数据流与一致性问题。作者通过日志的应用,展示了它如何解决数据集成的复杂性,支持实时和批处理场景,同时推动像 Kafka 这样的工具成为当前数据架构的基础。简单来说,日志是连接系统、流动数据的 “中枢神经”。