领英是全球领先的职业社交网站,全球会员总数近 7.74 亿,覆盖全球 200 多个国家和地区。主要用于处理网站每天产生的大量用户行为数据而研发的产品。
背景
Kafka是由LinkedIn开发并开源的分布式消息系统,后开源捐给Apache。
Kafka介绍
Kafka是一种分布式的,基于发布/订阅的消息系统。
主要设计目标如下:
以时间复杂度为O(1)的方式提供消息持久化能力,
即使对TB级以上数据也能保证常数时间复杂度的访问性能
高吞吐率:即使在非常廉价的商用机器上也能做到单机支持每秒100K条以上消息的传输
支持Kafka Server间的消息分区,及分布式消费,同时保证每个Partition内的消息顺序传输
同时支持离线数据处理和实时数据处理
核心能力
高吞吐量、可扩展的、永久存储、高可用性
Kafka 为 Java 和 Scala 提供了五个核心 API:
Admin API :管理topics、brokers和其他Kafka对象的API
Producer API:生产者API
Consumer API :消费者API
Kafka Streams API :流处理API
Kafka Connect API :实现关系型数据库连接导入导出的API
核心组成介绍
Producer
生产者可以将数据发布到所选择的topic(主题)中。生产者负责将记录分配到topic的哪一个 partition(分区)中。可以使用循环的方式来简单地实现负载均衡,也可以根据某些语义分区函数(例如:记录中的key)来完成。下面会介绍更多关于分区的使用。
Consumer
消费者使用一个 消费组 名称来进行标识,发布到topic中的每条记录被分配给订阅消费组中的一个消费者实例.消费者实例可以分布在多个进程中或者多个机器上。
在Kafka中实现消费的方式是将日志中的分区划分到每一个消费者实例上,以便在任何时间,每个实例都是分区唯一的消费者。维护消费组中的消费关系由Kafka协议动态处理。如果新的实例加入组,他们将从组中其他成员处接管一些 partition 分区;如果一个实例消失,拥有的分区将被分发到剩余的实例。
Broker
⼀台 Kafka 机器就是⼀个 Broker。⼀个集群(kafka cluster)由多个 Broker 组成。⼀个 Broker 可以容纳多个 Topic。
Topic
可以理解为⼀个队列,Topic 将消息分类,⽣产者和消费者⾯向的是同⼀个 Topic。
Topic是分区的(partitioned), Topic分布在位于不同 Kafka 代理上的多个“buckets”中。数据的这种分布式放置对于可扩展性非常重要,因为它允许客户端应用程序同时从多个代理读取和写入数据。一个Topic通常会有多个Producer和多个Consumer。一个Topic有0个1个或多个Producer发送消息,就像它可能有0个1个或者多个Consumer一样。
Topic 可以设置同步备份的最小数量。
Events
Events被组织并持久存储在Topic中,Topic相当于文件系统中的文件夹,events是文件夹中的文件。Events在消息读取后不会被删除,你可以定义kafka来设置消息的存放时间。Kafka 的性能在数据大小方面实际上是恒定的,因此长时间存储数据是非常好的。
图例种的Topic有4个分区(p1-p4),两个不同的producer客户端,相互独立,通过网络将events写入主题的分区,从而为Topic添加新事件。具有相同键的Events(在图中由它们的颜色表示)被写入同一个分区。
为了使您的数据具有容错性和高可用性,可以replicated每个主题,甚至跨地理区域或数据中心,以便始终有多个代理拥有数据副本,以防万一出现问题,您想要对brokers进行维护,等等。一个常见的生产设置是复制因子为 3,即始终存在三个数据副本。此复制在主题分区级别执行。
深入了解
Producer
Load balancing
生产者直接发送数据到主分区的服务器上,不需要经过任何中间路由。 为了让生产者实现这个功能,所有的 kafka 服务器节点都能响应这样的元数据请求: 哪些服务器是活着的,主题的哪些分区是主分区,分配在哪个服务器上,这样生产者就能适当地直接发送它的请求到服务器上。
客户端控制消息发送数据到哪个分区,这个可以实现随机的负载均衡方式,或者使用一些特定语义的分区函数。 我们有提供特定分区的接口让用于根据指定的键值进行hash分区(当然也有选项可以重写分区函数),例如,如果使用用户ID作为key,则用户相关的所有数据都会被分发到同一个分区上。 这允许消费者在消费数据时做一些特定的本地化处理。这样的分区风格经常被设计用于一些本地处理比较敏感的消费者。
Asynchronous send
批处理是提升性能的一个主要驱动,为了允许批量处理,kafka 生产者会尝试在内存中汇总数据,并用一次请求批次提交信息。 批处理,不仅仅可以配置指定的消息数量,也可以指定等待特定的延迟时间(如64k 或10ms),这允许汇总更多的数据后再发送,在服务器端也会减少更多的IO操作。 该缓冲是可配置的,并给出了一个机制,通过权衡少量额外的延迟时间获取更好的吞吐量。
ACK
producer 也 可以选择是否等待消息被提交,这取决他们的设置在延迟时间和持久性之间的权衡,这个选项是由 producer 使用的 acks 设置控制。
pros.put(“acks”,“0”)//不等待broker返回确认消息
pros.put(“acks”,“1”)//(默认)leader保存成功返回
pros.put(“acks”,“-1”)// 所有备份都保存成功返回 all=ISR 此时可以指定最小的 ISR 集合大小,只有当 ISR 的大小大于最小值,分区才能接受写入操作
consumer
Kafka consumer通过向 broker 发出一个“fetch”请求来获取它想要消费的 partition。consumer 的每个请求都在 log 中指定了对应的 offset,并接收从该位置开始的一大块数据。因此,consumer 对于该位置的控制就显得极为重要,并且可以在需要的时候通过回退到该位置再次消费对应的数据。
Push vs. pull
producer 把数据 push 到 broker,然后 consumer 从 broker 中 pull 数据。
消费者的位置
Kafka 使用完全不同的方式解决消息丢失问题。Kafka的 topic 被分割成了一组完全有序的 partition,其中每一个 partition 在任意给定的时间内只能被每个订阅了这个 topic 的 consumer 组中的一个 consumer 消费。这意味着 partition 中 每一个 consumer 的位置仅仅是一个数字,即下一条要消费的消息的offset。这使得被消费的消息的状态信息相当少,每个 partition 只需要一个数字。这个状态信息还可以作为周期性的 checkpoint。这以非常低的代价实现了和消息确认机制等同的效果。
这种方式还有一个附加的好处。consumer 可以回退到之前的 offset 来再次消费之前的数据,这个操作违反了队列的基本原则,但事实证明对大多数 consumer 来说这是一个必不可少的特性。 例如,如果 consumer 的代码有 bug,并且在 bug 被发现前已经有一部分数据被消费了, 那么 consumer 可以在 bug 修复后通过回退到之前的 offset 来再次消费这些数据。
Replication
Kafka 允许 topic 的 partition 拥有若干副本,你可以在server端配置partition 的副本数量。当集群中的节点出现故障时,能自动进行故障转移,保证数据的可用性。
其他的消息系统也提供了副本相关的特性,但是在我们(带有偏见)看来,他们的副本功能不常用,而且有很大缺点:slaves 处于非活动状态,导致吞吐量受到严重影响,并且还要手动配置副本机制。Kafka 默认使用备份机制,事实上,我们将没有设置副本数 的 topic 实现为副本数为1的 topic 。
创建副本的单位是 topic 的 partition ,正常情况下, 每个分区都有一个 leader 和零或多个 followers 。 总的副本数是包含 leader 的总和。 所有的读写操作都由 leader 处理,一般 partition 的数量都比 broker 的数量多的多,各分区的 leader 均 匀的分布在brokers 中。所有的 followers 节点都同步 leader 节点的日志,日志中的消息和偏移量都和 leader 中的一致。(当然, 在任何给定时间, leader 节点的日志末尾时可能有几个消息尚未被备份完成)。
Followers 节点就像普通的 consumer 那样从 leader 节点那里拉取消息并保存在自己的日志文件中。Followers 节点可以从 leader 节点那里批量拉取消息日志到自己的日志文件中。
在所有时间里,Kafka 保证只要有至少一个同步中的节点存活,提交的消息就不会丢失。
备份管理
优化主从关系的选举过程也是重要的,这是数据不可用的关键窗口。原始的实现是当有节点挂了后,进行主从关系选举时,会对挂掉节点的所有partition 的领导权重新选举。相反,我们会选择一个 broker 作为 “controller”节点。controller 节点负责 检测 brokers 级别故障,并负责在 broker 故障的情况下更改这个故障 Broker 中的 partition 的 leadership 。这种方式可以批量的通知主从关系的变化,使得对于拥有大量partition 的broker ,选举过程的代价更低并且速度更快。如果 controller 节点挂了,其他 存活的 broker 都可能成为新的 controller 节点。
日志压缩
日志压缩可确保 Kafka 始终至少为单个 topic partition 的数据日志中的每个 message key 保留最新的已知值。保证日志包含每一个key的最终值
以上均来此
中文文档kafka.apachecn.org
英文文档kafka.apache.org
本文档仅用来做基础学习和记录。