Kafka 源码解析:消费者运行机制

与上一篇介绍的 KafkaProducer 一样,Kafka 消费者 KafkaConsumer 同样是 Kafka 与开发者交互的媒介之一,负责从 Kafka 集群拉取消息给应用程序消费,并提交已经消费完成的 offset 值。此外,考虑到消费者上下线、topic 分区数目变更等情况,KafkaConsumer 还需要负责与服务端交互执行分区再分配操作,以保证消费者能够更加均衡的消费 topic 分区,从而提升消费的性能。

Kafka 定义了 group 的概念,将多个消费者实例组织成为一个 group,以丰富 Kafka 的应用场景。一个 group 名下可以包含任意数量的消费者实例,并从这些消费者中选择一个消费者担任 group 中的 Leader 消费者角色,负责管理 group 和其它 Follower 角色消费者的状态。当有消费者加入或离开当前 group 时,Group Leader 会依据集群确定的分区分配策略,为 group 名下所有消费者重新分配分区,以保证消息消费的均衡性。

阅读全文

Kafka 源码解析:生产者运行机制

Kafka 生产者 KafkaProducer 是 Kafka 与开发者交互的媒介之一,肩负接收用户自定义消息(这里的消息指代往 Kafka 发送的各类数据),并投递给目标 topic 分区的职责。在设计上为了提升消息吞吐量,考量降低与服务端交互的压力等,每次发送消息的请求并非是直接与 Kafka 集群进行交互,而是一个异步的过程。

当调用 KafkaProducer#send 方法发送消息时,实际上只是将消息缓存到了本地的消息收集器中,Kafka 定义了一个 RecordAccumulator 收集器用于收集用户提交的消息数据,同时又在后台维护了一个 Sender 线程,以异步的方式不断将收集器中缓存的消息定期定量地投递给 Kafka 集群。

阅读全文

Kafka 源码解析:架构与核心概念

Apache Kafka 作为分布式消息引擎系统,已经被各大互联网公司广泛引入到生产环境中,主要用于消息的发布订阅、日志数据的采集等,以充当一个公司的数据总线角色。因其具备优良的性能和近乎实时的消息投递能力,并且能够保证消息的顺序性、持久性和完整性(不丢消息),同时引入 topic、partition,以及 group 等精妙的设计理念,所以自开源以来社区一直非常活跃。大厂在引入 Kafka 时,一般会结合公司自身的业务特点在具体落地形式上有所区别(包括在 Kafka 原有基础上扩展和优化,或沿用 Kafka 的设计思想重新设计实现等),但是在思想上仍然是相通的,所以了解 Kafka 的核心设计与实现可以对这些系统举一反三。

阅读全文

基于 CAS 机制的 ConcurrentHashMap 实现内幕

曾经写过一篇《基于锁分段机制的 ConcurrentHashMap 实现内幕》的文章,介绍了在 JDK 1.7 之前 ConcurrentHashMap 的实现机制。文章的结尾我们提及到在 JDK 1.8 之后,ConcurrentHashMap 在实现上抛弃了锁分段机制,转而采用 CAS(Compare-And-Swap) 策略,并和 HashMap 一样引入了红黑树的支持。本文我们将基于 JDK 1.8 源码,分析基于 CAS 机制的 ConcurrentHashMap 实现。

阅读全文

JMockit:单元测试利器

单元测试(UT: Unit Test)是保证服务质量的基础。在实际项目的 UT 开发中,我们通常需要执行第三方服务调用、连接数据库等操作,为了让 UT 能够正常运行起来,我们需要执行大量的环境准备工作,这些工作有时比 UT 本身还要费时费力很多,而 mock 机制则能够帮助我们绕开这些必要但不一定要真正需要去做的事情,隔离 UT 与服务的依赖,模拟我们期望的行为和数据。

阅读全文

CGLib:The Missing Guide

CGLib(Code Generation Library) 是一个强大、高效,以及高质量的字节码生成库,能够在运行时动态生成字节码,从而实现一些比较极客的功能。CGLib 被许多开源软件采用,我们在写一些基础库时也很青睐,但是官方给到的文档比较简单,所以本文参考 CGLib: The missing manual,并结合自己的使用经验,总结了一个中文版本。

阅读全文

JStorm 源码解析:ACK 机制

Ack 机制是 Storm 能够保证消息至少被处理一次(at least once)的核心,从而保证消息不丢失。在 topology 有向无环图中,spout 向 bolt 发射消息,上游 bolt 也会向下游 bolt 发射消息。Storm 设置了一类 acker 类型的系统 bolt 组件用于接收所有组件发送的 ack 消息,监控数据在 topology 中的处理情况。如果处理成功则发送 **acker_ack 消息给 spout,否则发送 **acker_fail 消息给 spout,然后 spout 依据相应的消息类型采取一定的应对措施(例如消息重发等)。

阅读全文

JStorm 源码解析:Worker 的启动和运行机制

上一篇我们分析了 supervisor 节点的启动和运行过程,提及到 supervisor 的核心工作就是基于 ZK 从 nimbus 节点领取分配给它的任务,并启动 worker 执行。一个 worker 就是一个 JVM 进程,运行在 supervisor 节点上,多个 task 可以同时运行在一个 worker 进程之中,每个 task 都对应一个线程。

Worker 进程的启动位于 Worker 类中,前面我们在分析 supervisor 节点的启动过程时提及到了对于 Worker 类 main 函数的触发,supervisor 在启动相应 worker 进程时会指定 topologyId、supervisorId、workerPort、workerId,以及 classpath 等参数,worker 在拿到这些参数之后会先获取当前机器上端口对应的老进程,并逐一 kill 掉,然后调用 Worker#mk_worker 方法创建并启动对应的 worker 实例,

阅读全文

JStorm 源码解析:Supervisor 的启动和运行机制

Supervisor 节点可以理解为单机任务调度器,它负责监听 nimbus 节点的任务资源分配,启动相应的 worker 进程执行 nimbus 分配给当前节点的任务,同时监测 worker 的运行状态,一旦发现有 worker 运行异常,就会杀死该 worker 进程,并将原先分配给 worker 的任务交还给 nimbus 节点进行重新分配。

Supervisor 节点的启动过程位于 Supervisor 类中,main 方法的实现比较简单,主要就是创建了一个 Supervisor 类对象,并调用实例方法

阅读全文

JStorm 源码解析:Nimbus 的启动和运行机制

本篇我们一起分析一下 nimbus 节点的启动和运行机制。Nimbus 节点是 Storm 集群的调度者和管理者,它是集群与用户交互的窗口,负责 topology 任务的分配、启动和运行,也管理着集群中所有的 supervisor 节点的运行,监控着整个集群的运行状态,并将集群运行信息汇集给 UI 进行展示。

Nimbus 节点的启动过程位于 NimbusServer 类中,这是一个驱动类,main 方法中会加载集群配置文件,包括 default.yaml 和 storm.yaml,并将配置文件内容与启动时的命令行参数一起封装成 map 对象便于后续使用,真正的启动逻辑位于 NimbusServer#launchServer 方法中:

阅读全文