This commit is contained in:
louzefeng
2024-07-09 18:38:56 +00:00
parent 8bafaef34d
commit bf99793fd0
6071 changed files with 1017944 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
<audio id="audio" title="01 | 消息引擎系统ABC" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/0b/4d/0b4336a9167249cf5e269de27944974d.mp3"></audio>
你好我是胡夕。欢迎你来到“Kafka核心技术与实战”专栏。如果你对Kafka及其背后的消息引擎、流处理感兴趣很高兴我们可以在此相聚并在未来的一段日子里一同学习有关Kafka的方方面面。
毫无疑问你现在对Apache Kafka一定充满了各种好奇那么今天就允许我先来尝试回答下Kafka是什么这个问题。对了先卖个关子在下一期我还将继续回答这个问题而且答案是不同的。那么Kafka是什么呢用一句话概括一下**Apache Kafka是一款开源的消息引擎系统**。
倘若“消息引擎系统”这个词对你来说有点陌生的话那么“消息队列”“消息中间件”的提法想必你一定是有所耳闻的。不过说实话我更愿意使用消息引擎系统这个称谓因为消息队列给出了一个很不明确的暗示仿佛Kafka是利用队列的方式构建的而消息中间件的提法有过度夸张“中间件”之嫌让人搞不清楚这个中间件到底是做什么的。
像Kafka这一类的系统国外有专属的名字叫Messaging System国内很多文献将其简单翻译成消息系统。我个人认为并不是很恰当因为它片面强调了消息主体的作用而忽视了这类系统引以为豪的消息传递属性就像引擎一样具备某种能量转换传输的能力所以我觉得翻译成消息引擎反倒更加贴切。
讲到这里说点题外话。我觉得目前国内在翻译国外专有技术词汇方面做得不够标准化各种名字和提法可谓五花八门。我举个例子比如大名鼎鼎的Raft算法和Paxos算法。了解它的人都知道它们的作用是在分布式系统中让多个节点就某个决定达成共识都属于Consensus Algorithm一族。如果你在搜索引擎中查找Raft算法国内多是称呼它们为一致性算法。实际上我倒觉得翻译成共识算法是最准确的。我们使用“一致性”这个字眼太频繁了国外的Consistency被称为一致性、Consensus也唤作一致性甚至是Coherence都翻译成一致性。
还是拉回来继续聊消息引擎系统,那这类系统是做什么用的呢?我先来个官方严肃版本的答案。
根据维基百科的定义,消息引擎系统是一组规范。企业利用这组规范在不同系统之间传递语义准确的消息,实现松耦合的异步式数据传递。
果然是官方定义,有板有眼。如果觉得难于理解,那么可以试试我下面这个民间版:
系统A发送消息给消息引擎系统系统B从消息引擎系统中读取A发送的消息。
最基础的消息引擎就是做这点事的!不论是上面哪个版本,它们都提到了两个重要的事实:
- 消息引擎传输的对象是消息;
- 如何传输消息属于消息引擎设计机制的一部分。
既然消息引擎是用于在不同系统之间传输消息的,那么如何设计待传输消息的格式从来都是一等一的大事。试问一条消息如何做到信息表达业务语义而无歧义,同时它还要能最大限度地提供可重用性以及通用性?稍微停顿几秒去思考一下,如果是你,你要如何设计你的消息编码格式。
一个比较容易想到的是使用已有的一些成熟解决方案比如使用CSV、XML亦或是JSON又或者你可能熟知国外大厂开源的一些序列化框架比如Google的Protocol Buffer或Facebook的Thrift。这些都是很酷的办法。那么现在我告诉你Kafka的选择它使用的是纯二进制的字节序列。当然消息还是结构化的只是在使用之前都要将其转换成二进制的字节序列。
消息设计出来之后还不够,消息引擎系统还要设定具体的传输协议,即我用什么方法把消息传输出去。常见的有两种方法:
- **点对点模型**也叫消息队列模型。如果拿上面那个“民间版”的定义来说那么系统A发送的消息只能被系统B接收其他任何系统都不能读取A发送的消息。日常生活的例子比如电话客服就属于这种模型同一个客户呼入电话只能被一位客服人员处理第二个客服人员不能为该客户服务。
- **发布/订阅模型**与上面不同的是它有一个主题Topic的概念你可以理解成逻辑语义相近的消息容器。该模型也有发送方和接收方只不过提法不同。发送方也称为发布者Publisher接收方称为订阅者Subscriber。和点对点模型不同的是这个模型可能存在多个发布者向相同的主题发送消息而订阅者也可能存在多个它们都能接收到相同主题的消息。生活中的报纸订阅就是一种典型的发布/订阅模型。
比较酷的是Kafka同时支持这两种消息引擎模型专栏后面我会分享Kafka是如何做到这一点的。
提到消息引擎系统你可能会问JMS和它是什么关系。JMS是Java Message Service它也是支持上面这两种消息引擎模型的。严格来说它并非传输协议而仅仅是一组API罢了。不过可能是JMS太有名气以至于很多主流消息引擎系统都支持JMS规范比如ActiveMQ、RabbitMQ、IBM的WebSphere MQ和Apache Kafka。当然Kafka并未完全遵照JMS规范相反它另辟蹊径探索出了一条特有的道路。
好了,目前我们仅仅是了解了消息引擎系统是做什么的以及怎么做的,但还有个重要的问题是为什么要使用它。
依旧拿上面“民间版”举例我们不禁要问为什么系统A不能直接发送消息给系统B中间还要隔一个消息引擎呢
答案就是“**削峰填谷**”。这四个字简直比消息引擎本身还要有名气。
我翻了很多文献,最常见的就是这四个字。所谓的“削峰填谷”就是指缓冲上下游瞬时突发流量,使其更平滑。特别是对于那种发送能力很强的上游系统,如果没有消息引擎的保护,“脆弱”的下游系统可能会直接被压垮导致全链路服务“雪崩”。但是,一旦有了消息引擎,它能够有效地对抗上游的流量冲击,真正做到将上游的“峰”填满到“谷”中,避免了流量的震荡。消息引擎系统的另一大好处在于发送方和接收方的松耦合,这也在一定程度上简化了应用的开发,减少了系统间不必要的交互。
说了这么多可能你对“削峰填谷”并没有太多直观的感受。我还是举个例子来说明一下Kafka在这中间是怎么去“抗”峰值流量的吧。回想一下你在极客时间是如何购买这个课程的。如果我没记错的话极客时间每门课程都有一个专门的订阅按钮点击之后进入到付费页面。这个简单的流程中就可能包含多个子服务比如点击订阅按钮会调用订单系统生成对应的订单而处理该订单会依次调用下游的多个子系统服务 比如调用支付宝和微信支付的接口、查询你的登录信息、验证课程信息等。显然上游的订单操作比较简单它的TPS要远高于处理订单的下游服务因此如果上下游系统直接对接势必会出现下游服务无法及时处理上游订单从而造成订单堆积的情形。特别是当出现类似于秒杀这样的业务时上游订单流量会瞬时增加可能出现的结果就是直接压跨下游子系统服务。
解决此问题的一个常见做法是我们对上游系统进行限速但这种做法对上游系统而言显然是不合理的毕竟问题并不出现在它那里。所以更常见的办法是引入像Kafka这样的消息引擎系统来对抗这种上下游系统TPS的错配以及瞬时峰值流量。
还是这个例子当引入了Kafka之后。上游订单服务不再直接与下游子服务进行交互。当新订单生成后它仅仅是向Kafka Broker发送一条订单消息即可。类似地下游的各个子服务订阅Kafka中的对应主题并实时从该主题的各自分区Partition中获取到订单消息进行处理从而实现了上游订单服务与下游订单处理服务的解耦。这样当出现秒杀业务时Kafka能够将瞬时增加的订单流量全部以消息形式保存在对应的主题中既不影响上游服务的TPS同时也给下游子服务留出了充足的时间去消费它们。这就是Kafka这类消息引擎系统的最大意义所在。
如果你对Kafka Broker、主题和分区等术语还不甚了解的话也不必担心我会在专栏后面专门花时间介绍一下Kafka的常见概念和术语。
在今天结束之前我还想和你分享一个自己的小故事。在2015年那会儿我花了将近1年的时间阅读Kafka源代码期间多次想要放弃。你要知道阅读将近50万行源码是多么痛的领悟。我还记得当初为了手写源代码注释自己写满了一个厚厚的笔记本。不过幸运的是我坚持了下来之前的所有努力也没有白费以至于后面写书、写极客时间专栏就变成了一件件水到渠成的事情。
最后我想送给你一句话:**聪明人也要下死功夫**。我不记得这是曾国藩说的还是季羡林说的,但这句话对我有很大影响,当我感到浮躁的时候它能帮我静下心来踏踏实实做事情。希望这句话对你也有所启发。切记:聪明人要下死功夫!
<img src="https://static001.geekbang.org/resource/image/8b/26/8bc58bf5bb98db09fd6ef343e0f28826.jpg" alt="">
## 开放讨论
请谈谈你对消息引擎系统的理解,或者分享一下你的公司或组织是怎么使用消息引擎来处理实际问题的。
欢迎写下你的思考和答案,我们一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。

View File

@@ -0,0 +1,63 @@
<audio id="audio" title="02 | 一篇文章带你快速搞定Kafka术语" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/5f/11/5f66506bc8a6bc5fa821dd8e547bbc11.mp3"></audio>
你好我是胡夕。今天我们正式开启Apache Kafka学习之旅。
在Kafka的世界中有很多概念和术语是需要你提前理解并熟练掌握的这对于后面你深入学习Kafka各种功能和特性将大有裨益。下面我来盘点一下Kafka的各种术语。
在专栏的第一期我说过Kafka属于分布式的消息引擎系统它的主要功能是提供一套完备的消息发布与订阅解决方案。在Kafka中发布订阅的对象是主题Topic你可以为每个业务、每个应用甚至是每类数据都创建专属的主题。
向主题发布消息的客户端应用程序称为生产者Producer生产者程序通常持续不断地向一个或多个主题发送消息而订阅这些主题消息的客户端应用程序就被称为消费者Consumer。和生产者类似消费者也能够同时订阅多个主题的消息。我们把生产者和消费者统称为客户端Clients。你可以同时运行多个生产者和消费者实例这些实例会不断地向Kafka集群中的多个主题生产和消费消息。
有客户端自然也就有服务器端。Kafka的服务器端由被称为Broker的服务进程构成即一个Kafka集群由多个Broker组成Broker负责接收和处理客户端发送过来的请求以及对消息进行持久化。虽然多个Broker进程能够运行在同一台机器上但更常见的做法是将不同的Broker分散运行在不同的机器上这样如果集群中某一台机器宕机即使在它上面运行的所有Broker进程都挂掉了其他机器上的Broker也依然能够对外提供服务。这其实就是Kafka提供高可用的手段之一。
实现高可用的另一个手段就是备份机制Replication。备份的思想很简单就是把相同的数据拷贝到多台机器上而这些相同的数据拷贝在Kafka中被称为副本Replica。好吧其实在整个分布式系统里好像都叫这个名字。副本的数量是可以配置的这些副本保存着相同的数据但却有不同的角色和作用。Kafka定义了两类副本领导者副本Leader Replica和追随者副本Follower Replica。前者对外提供服务这里的对外指的是与客户端程序进行交互而后者只是被动地追随领导者副本而已不能与外界进行交互。当然了你可能知道在很多其他系统中追随者副本是可以对外提供服务的比如MySQL的从库是可以处理读操作的但是在Kafka中追随者副本不会对外提供服务。对了一个有意思的事情是现在已经不提倡使用Master-Slave来指代这种主从关系了毕竟Slave有奴隶的意思在美国这种严禁种族歧视的国度这种表述有点政治不正确了所以目前大部分的系统都改成Leader-Follower了。
副本的工作机制也很简单:生产者总是向领导者副本写消息;而消费者总是从领导者副本读消息。至于追随者副本,它只做一件事:向领导者副本发送请求,请求领导者把最新生产的消息发给它,这样它能保持与领导者的同步。
虽然有了副本机制可以保证数据的持久化或消息不丢失但没有解决伸缩性的问题。伸缩性即所谓的Scalability是分布式系统中非常重要且必须要谨慎对待的问题。什么是伸缩性呢我们拿副本来说虽然现在有了领导者副本和追随者副本但倘若领导者副本积累了太多的数据以至于单台Broker机器都无法容纳了此时应该怎么办呢一个很自然的想法就是能否把数据分割成多份保存在不同的Broker上如果你就是这么想的那么恭喜你Kafka就是这么设计的。
这种机制就是所谓的分区Partitioning。如果你了解其他分布式系统你可能听说过分片、分区域等提法比如MongoDB和Elasticsearch中的Sharding、HBase中的Region其实它们都是相同的原理只是Partitioning是最标准的名称。
Kafka中的分区机制指的是将每个主题划分成多个分区Partition每个分区是一组有序的消息日志。生产者生产的每条消息只会被发送到一个分区中也就是说如果向一个双分区的主题发送一条消息这条消息要么在分区0中要么在分区1中。如你所见Kafka的分区编号是从0开始的如果Topic有100个分区那么它们的分区号就是从0到99。
讲到这里你可能有这样的疑问刚才提到的副本如何与这里的分区联系在一起呢实际上副本是在分区这个层级定义的。每个分区下可以配置若干个副本其中只能有1个领导者副本和N-1个追随者副本。生产者向分区写入消息每条消息在分区中的位置信息由一个叫位移Offset的数据来表征。分区位移总是从0开始假设一个生产者向一个空分区写入了10条消息那么这10条消息的位移依次是0、1、2、......、9。
至此我们能够完整地串联起Kafka的三层消息架构
- 第一层是主题层每个主题可以配置M个分区而每个分区又可以配置N个副本。
- 第二层是分区层每个分区的N个副本中只能有一个充当领导者角色对外提供服务其他N-1个副本是追随者副本只是提供数据冗余之用。
- 第三层是消息层分区中包含若干条消息每条消息的位移从0开始依次递增。
- 最后,客户端程序只能与分区的领导者副本进行交互。
讲完了消息层次我们来说说Kafka Broker是如何持久化数据的。总的来说Kafka使用消息日志Log来保存数据一个日志就是磁盘上一个只能追加写Append-only消息的物理文件。因为只能追加写入故避免了缓慢的随机I/O操作改为性能较好的顺序I/O写操作这也是实现Kafka高吞吐量特性的一个重要手段。不过如果你不停地向一个日志写入消息最终也会耗尽所有的磁盘空间因此Kafka必然要定期地删除消息以回收磁盘。怎么删除呢简单来说就是通过日志段Log Segment机制。在Kafka底层一个日志又进一步细分成多个日志段消息被追加写到当前最新的日志段中当写满了一个日志段后Kafka会自动切分出一个新的日志段并将老的日志段封存起来。Kafka在后台还有定时任务会定期地检查老的日志段是否能够被删除从而实现回收磁盘空间的目的。
这里再重点说说消费者。在专栏的第一期中我提到过两种消息模型即点对点模型Peer to PeerP2P和发布订阅模型。这里面的点对点指的是同一条消息只能被下游的一个消费者消费其他消费者则不能染指。在Kafka中实现这种P2P模型的方法就是引入了消费者组Consumer Group。所谓的消费者组指的是多个消费者实例共同组成一个组来消费一组主题。这组主题中的每个分区都只会被组内的一个消费者实例消费其他消费者实例不能消费它。为什么要引入消费者组呢主要是为了提升消费者端的吞吐量。多个消费者实例同时消费加速整个消费端的吞吐量TPS。我会在专栏的后面详细介绍消费者组机制所以现在你只需要了解消费者组是做什么的即可。另外这里的消费者实例可以是运行消费者应用的进程也可以是一个线程它们都称为一个消费者实例Consumer Instance
消费者组里面的所有消费者实例不仅“瓜分”订阅主题的数据而且更酷的是它们还能彼此协助。假设组内某个实例挂掉了Kafka能够自动检测到然后把这个Failed实例之前负责的分区转移给其他活着的消费者。这个过程就是Kafka中大名鼎鼎的“重平衡”Rebalance。嗯其实既是大名鼎鼎也是臭名昭著因为由重平衡引发的消费者问题比比皆是。事实上目前很多重平衡的Bug社区都无力解决。
每个消费者在消费消息的过程中必然需要有个字段记录它当前消费到了分区的哪个位置上这个字段就是消费者位移Consumer Offset。注意这和上面所说的位移完全不是一个概念。上面的“位移”表征的是分区内的消息位置它是不变的即一旦消息被成功写入到一个分区上它的位移值就是固定的了。而消费者位移则不同它可能是随时变化的毕竟它是消费者消费进度的指示器嘛。另外每个消费者有着自己的消费者位移因此一定要区分这两类位移的区别。我个人把消息在分区中的位移称为分区位移而把消费者端的位移称为消费者位移。
## 小结
我来总结一下今天提到的所有名词术语:
- 消息Record。Kafka是消息引擎嘛这里的消息就是指Kafka处理的主要对象。
- 主题Topic。主题是承载消息的逻辑容器在实际使用中多用来区分具体的业务。
- 分区Partition。一个有序不变的消息序列。每个主题下可以有多个分区。
- 消息位移Offset。表示分区中每条消息的位置信息是一个单调递增且不变的值。
- 副本Replica。Kafka中同一条消息能够被拷贝到多个地方以提供数据冗余这些地方就是所谓的副本。副本还分为领导者副本和追随者副本各自有不同的角色划分。副本是在分区层级下的即每个分区可配置多个副本实现高可用。
- 生产者Producer。向主题发布新消息的应用程序。
- 消费者Consumer。从主题订阅新消息的应用程序。
- 消费者位移Consumer Offset。表征消费者消费进度每个消费者都有自己的消费者位移。
- 消费者组Consumer Group。多个消费者实例共同组成的一个组同时消费多个分区以实现高吞吐。
- 重平衡Rebalance。消费者组内某个消费者实例挂掉后其他消费者实例自动重新分配订阅主题分区的过程。Rebalance是Kafka消费者端实现高可用的重要手段。
最后我用一张图来展示上面提到的这些概念,希望这张图能够帮助你形象化地理解所有这些概念:
<img src="https://static001.geekbang.org/resource/image/58/91/58c35d3ab0921bf0476e3ba14069d291.jpg" alt="">
## 开放讨论
请思考一下为什么Kafka不像MySQL那样允许追随者副本对外提供读服务
欢迎写下你的思考和答案,我们一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。

View File

@@ -0,0 +1,62 @@
<audio id="audio" title="03 | Kafka只是消息引擎系统吗" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/9a/3e/9a70e41801c1cb2d3a50307eb1df6d3e.mp3"></audio>
你好我是胡夕。今天我们来聊一个老生常谈的话题Kafka只是消息引擎系统吗
要搞清楚这个问题我们不可避免地要了解一下Apache Kafka的发展历程。有的时候我们会觉得说了解一个系统或框架的前世今生似乎没什么必要直接开始学具体的技术不是更快更好吗其实不论是学习哪种技术直接扎到具体的细节中亦或是从一个很小的点开始学习你很快就会感到厌烦。为什么呢因为你虽然快速地搞定了某个技术细节但无法建立全局的认知观这会导致你只是在单个的点上有所进展却没法将其串联成一条线进而扩展成一个面从而实现系统地学习。
我这么说是有依据的因为这就是我当初学习Kafka的方式。你可能不会相信我阅读Kafka源码就是从utils包开始的。显然我们不用看源码也知道这玩意是干什么用的对吧就是个工具类包嘛而且这种阅读源码的方式是极其低效的。就像我说的我是在一个点一个点地学习但全部学完之后压根没有任何感觉依然不了解Kafka因为不知道这些包中的代码组合在一起能达成什么效果。所以我说它是很低效的学习方法。
后来我修改了学习的方法转而从自上而下的角度去理解Kafka竟然发现了很多之前学习过程中忽略掉的东西。更特别的是我发现这种学习方法能够帮助我维持较长时间的学习兴趣不会阶段性地产生厌烦情绪。特别是在了解Apache Kafka整个发展历史的过程中我愉快地学到了很多运营大型开源软件社区的知识和经验可谓是技术之外的一大收获。
纵观Kafka的发展脉络它的确是从消息引擎起家的但正如文章标题所问**Apache Kafka真的只是消息引擎吗**?通常,在回答这个问题之前很多文章可能就要这样展开了:那我们先来讨论下什么是消息引擎以及消息引擎能做什么事情。算了,我还是直给吧,就不从“唐尧虞舜”说起了。这个问题的答案是,**Apache Kafka是消息引擎系统也是一个分布式流处理平台**Distributed Streaming Platform。如果你通读全篇文字但只能记住一句话我希望你记住的就是这句。再强调一遍Kafka是消息引擎系统也是分布式流处理平台。
众所周知Kafka是LinkedIn公司内部孵化的项目。根据我和Kafka创始团队成员的交流以及查阅到的公开信息显示LinkedIn最开始有强烈的数据强实时处理方面的需求其内部的诸多子系统要执行多种类型的数据处理与分析主要包括业务系统和应用程序性能监控以及用户行为数据处理等。
当时他们碰到的主要问题包括:
- 数据正确性不足。因为数据的收集主要采用轮询Polling的方式如何确定轮询的间隔时间就变成了一个高度经验化的事情。虽然可以采用一些类似于启发式算法Heuristic来帮助评估间隔时间值但一旦指定不当必然会造成较大的数据偏差。
- 系统高度定制化,维护成本高。各个业务子系统都需要对接数据收集模块,引入了大量的定制开销和人工成本。
为了解决这些问题LinkedIn工程师尝试过使用ActiveMQ来解决这些问题但效果并不理想。显然需要有一个“大一统”的系统来取代现有的工作方式而这个系统就是Kafka。
Kafka自诞生伊始是以消息引擎系统的面目出现在大众视野中的。如果翻看0.10.0.0之前的官网说明你会发现Kafka社区将其清晰地定位为一个分布式、分区化且带备份功能的提交日志Commit Log服务。
这里引出一个题外话你可能好奇Kafka这个名字的由来实际上Kafka作者之一Jay Kreps曾经谈及过命名的原因。
>
因为Kafka系统的写性能很强所以找了个作家的名字来命名似乎是一个好主意。大学期间我上了很多文学课非常喜欢Franz Kafka这个作家另外为开源软件起这个名字听上去很酷。
言归正传Kafka在设计之初就旨在提供三个方面的特性
- 提供一套API实现生产者和消费者
- 降低网络传输和磁盘存储开销;
- 实现高伸缩性架构。
在专栏后面的课程中我们将陆续探讨Kafka是如何做到以上三点的。总之随着Kafka的不断完善Jay等大神们终于意识到将其开源惠及更多的人是一个非常棒的主意因此在2011年Kafka正式进入到Apache基金会孵化并于次年10月顺利毕业成为Apache顶级项目。
开源之后的Kafka被越来越多的公司应用到它们企业内部的数据管道中特别是在大数据工程领域Kafka在承接上下游、串联数据流管道方面发挥了重要的作用所有的数据几乎都要从一个系统流入Kafka然后再流向下游的另一个系统中。这样的使用方式屡见不鲜以至于引发了Kafka社区的思考与其我把数据从一个系统传递到下一个系统中做处理我为何不自己实现一套流处理框架呢基于这个考量Kafka社区于0.10.0.0版本正式推出了流处理组件Kafka Streams也正是从这个版本开始Kafka正式“变身”为分布式的流处理平台而不仅仅是消息引擎系统了。今天Apache Kafka是和Apache Storm、Apache Spark和Apache Flink同等级的实时流处理平台。
诚然目前国内对Kafka是流处理平台的认知还尚不普及其核心的流处理组件Kafka Streams更是少有大厂在使用。但我们也欣喜地看到随着在Kafka峰会上各路大神们的鼎力宣传如今利用Kafka构建流处理平台的案例层出不穷而了解并有意愿使用Kafka Streams的厂商也是越来越多因此我个人对于Kafka流处理平台的前景也是非常乐观的。
你可能会有这样的疑问作为流处理平台Kafka与其他主流大数据流式计算框架相比优势在哪里呢我能想到的有两点。
**第一点是更容易实现端到端的正确性Correctness**。Google大神Tyler曾经说过流处理要最终替代它的“兄弟”批处理需要具备两点核心优势**要实现正确性和提供能够推导时间的工具。实现正确性是流处理能够匹敌批处理的基石**。正确性一直是批处理的强项,而实现正确性的基石则是要求框架能提供精确一次处理语义,即处理一条消息有且只有一次机会能够影响系统状态。目前主流的大数据流处理框架都宣称实现了精确一次处理语义,但这是有限定条件的,即它们只能实现框架内的精确一次处理语义,无法实现端到端的。
这是为什么呢因为当这些框架与外部消息引擎系统结合使用时它们无法影响到外部系统的处理语义所以如果你搭建了一套环境使得Spark或Flink从Kafka读取消息之后进行有状态的数据计算最后再写回Kafka那么你只能保证在Spark或Flink内部这条消息对于状态的影响只有一次。但是计算结果有可能多次写入到Kafka因为它们不能控制Kafka的语义处理。相反地Kafka则不是这样因为所有的数据流转和计算都在Kafka内部完成故Kafka可以实现端到端的精确一次处理语义。
**可能助力Kafka胜出的第二点是它自己对于流式计算的定位**。官网上明确标识Kafka Streams是一个用于搭建实时流处理的客户端库而非是一个完整的功能系统。这就是说你不能期望着Kafka提供类似于集群调度、弹性部署等开箱即用的运维特性你需要自己选择适合的工具或系统来帮助Kafka流处理应用实现这些功能。
读到这你可能会说这怎么算是优点呢坦率来说这的确是一个“双刃剑”的设计也是Kafka社区“剑走偏锋”不正面PK其他流计算框架的特意考量。大型公司的流处理平台一定是大规模部署的因此具备集群调度功能以及灵活的部署方案是不可或缺的要素。但毕竟这世界上还存在着很多中小企业它们的流处理数据量并不巨大逻辑也并不复杂部署几台或十几台机器足以应付。在这样的需求之下搭建重量级的完整性平台实在是“杀鸡焉用牛刀”而这正是Kafka流处理组件的用武之地。因此从这个角度来说未来在流处理框架中Kafka应该是有一席之地的。
除了消息引擎和流处理平台Kafka还有别的用途吗当然有你能想象吗Kafka能够被用作分布式存储系统。Kafka作者之一Jay Kreps曾经专门写过一篇文章阐述为什么能把[Kafka用作分布式存储](https://www.confluent.io/blog/okay-store-data-apache-kafka/)。不过我觉得你姑且了解下就好了我从没有见过在实际生产环境中有人把Kafka当作持久化存储来用 。
说了这么多我只想阐述这样的一个观点Apache Kafka从一个优秀的消息引擎系统起家逐渐演变成现在分布式的流处理平台。你不仅要熟练掌握它作为消息引擎系统的非凡特性及使用技巧最好还要多了解下其流处理组件的设计与案例应用。
<img src="https://static001.geekbang.org/resource/image/ea/59/eafc2d9315a8ba858649c1ecd4201459.jpg" alt="">
## 开放讨论
你觉得Kafka未来的演进路线是怎么样的如果你是Kafka社区的“掌舵人”你准备带领整个社区奔向什么方向呢提示下你可以把自己想象成Linus再去思考
欢迎写下你的思考和答案,我们一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。

View File

@@ -0,0 +1,89 @@
<audio id="audio" title="04 | 我应该选择哪种Kafka" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/05/63/05f8cce80e5af8f38f7b4b75dc5ee463.mp3"></audio>
在专栏上一期中我们谈了Kafka当前的定位问题Kafka不再是一个单纯的消息引擎系统而是能够实现精确一次Exactly-once处理语义的实时流处理平台。
你可能听说过Apache Storm、Apache Spark Streaming亦或是Apache Flink它们在大规模流处理领域可都是响当当的名字。令人高兴的是Kafka经过这么长时间不断的迭代现在已经能够稍稍比肩这些框架了。我在这里使用了“稍稍”这个字眼一方面想表达Kafka社区对于这些框架心存敬意另一方面也想表达目前国内鲜有大厂将Kafka用于流处理的尴尬境地毕竟Kafka是从消息引擎“半路出家”转型成流处理平台的它在流处理方面的表现还需要经过时间的检验。
如果我们把视角从流处理平台扩展到流处理生态圈Kafka更是还有很长的路要走。前面我提到过Kafka Streams组件正是它提供了Kafka实时处理流数据的能力。但是其实还有一个重要的组件我没有提及那就是Kafka Connect。
我们在评估流处理平台的时候框架本身的性能、所提供操作算子Operator的丰富程度固然是重要的评判指标但框架与上下游交互的能力也是非常重要的。能够与之进行数据传输的外部系统越多围绕它打造的生态圈就越牢固因而也就有更多的人愿意去使用它从而形成正向反馈不断地促进该生态圈的发展。就Kafka而言Kafka Connect通过一个个具体的连接器Connector串联起上下游的外部系统。
整个Kafka生态圈如下图所示。值得注意的是这张图中的外部系统只是Kafka Connect组件支持的一部分而已。目前还有一个可喜的趋势是使用Kafka Connect组件的用户越来越多相信在未来会有越来越多的人开发自己的连接器。
<img src="https://static001.geekbang.org/resource/image/0e/3d/0ecc8fe201c090e7ce514d719372f43d.png" alt="">
说了这么多你可能会问这和今天的主题有什么关系呢其实清晰地了解Kafka的发展脉络和生态圈现状对于指导我们选择合适的Kafka版本大有裨益。下面我们就进入今天的主题——如何选择Kafka版本
## 你知道几种Kafka
咦? Kafka不是一个开源框架吗什么叫有几种Kafka啊 实际上Kafka的确有好几种这里我不是指它的版本而是指存在多个组织或公司发布不同的Kafka。你一定听说过Linux发行版吧比如我们熟知的CentOS、RedHat、Ubuntu等它们都是Linux系统但为什么有不同的名字呢其实就是因为它们是不同公司发布的Linux系统即不同的发行版。虽说在Kafka领域没有发行版的概念但你姑且可以这样近似地认为市面上的确存在着多个Kafka“发行版”。
下面我就来梳理一下这些所谓的“发行版”以及你应该如何选择它们。当然了“发行版”这个词用在Kafka框架上并不严谨但为了便于我们区分这些不同的Kafka我还是勉强套用一下吧。不过切记当你以后和别人聊到这个话题的时候最好不要提及“发行版”这个词 因为这种提法在Kafka生态圈非常陌生说出来难免贻笑大方。
**1. Apache Kafka**
Apache Kafka是最“正宗”的Kafka也应该是你最熟悉的发行版了。自Kafka开源伊始它便在Apache基金会孵化并最终毕业成为顶级项目它也被称为社区版Kafka。咱们专栏就是以这个版本的Kafka作为模板来学习的。更重要的是它是后面其他所有发行版的基础。也就是说后面提到的发行版要么是原封不动地继承了Apache Kafka要么是在此之上扩展了新功能总之Apache Kafka是我们学习和使用Kafka的基础。
**2. Confluent Kafka**
我先说说Confluent公司吧。2014年Kafka的3个创始人Jay Kreps、Naha Narkhede和饶军离开LinkedIn创办了Confluent公司专注于提供基于Kafka的企业级流处理解决方案。2019年1月Confluent公司成功融资D轮1.25亿美元估值也到了25亿美元足见资本市场的青睐。
这里说点题外话, 饶军是我们中国人清华大学毕业的大神级人物。我们已经看到越来越多的Apache顶级项目创始人中出现了中国人的身影另一个例子就是Apache Pulsar它是一个以打败Kafka为目标的新一代消息引擎系统。至于在开源社区中活跃的国人更是数不胜数这种现象实在令人振奋。
还说回Confluent公司它主要从事商业化Kafka工具开发并在此基础上发布了Confluent Kafka。Confluent Kafka提供了一些Apache Kafka没有的高级特性比如跨数据中心备份、Schema注册中心以及集群监控工具等。
**3. Cloudera/Hortonworks Kafka**
Cloudera提供的CDH和Hortonworks提供的HDP是非常著名的大数据平台里面集成了目前主流的大数据框架能够帮助用户实现从分布式存储、集群调度、流处理到机器学习、实时数据库等全方位的数据处理。我知道很多创业公司在搭建数据平台时首选就是这两个产品。不管是CDH还是HDP里面都集成了Apache Kafka因此我把这两款产品中的Kafka称为CDH Kafka和HDP Kafka。
当然在2018年10月两家公司宣布合并共同打造世界领先的数据平台也许以后CDH和HDP也会合并成一款产品但能肯定的是Apache Kafka依然会包含其中并作为新数据平台的一部分对外提供服务。
## 特点比较
Okay说完了目前市面上的这些Kafka我来对比一下它们的优势和劣势。
**1. Apache Kafka**
对Apache Kafka而言它现在依然是开发人数最多、版本迭代速度最快的Kafka。在2018年度Apache基金会邮件列表开发者数量最多的Top 5排行榜中Kafka社区邮件组排名第二位。如果你使用Apache Kafka碰到任何问题并提交问题到社区社区都会比较及时地响应你。这对于我们Kafka普通使用者来说无疑是非常友好的。
但是Apache Kafka的劣势在于它仅仅提供最最基础的组件特别是对于前面提到的Kafka Connect而言社区版Kafka只提供一种连接器即读写磁盘文件的连接器而没有与其他外部系统交互的连接器在实际使用过程中需要自行编写代码实现这是它的一个劣势。另外Apache Kafka没有提供任何监控框架或工具。显然在线上环境不加监控肯定是不可行的你必然需要借助第三方的监控框架实现对Kafka的监控。好消息是目前有一些开源的监控框架可以帮助用于监控Kafka比如Kafka manager
**总而言之如果你仅仅需要一个消息引擎系统亦或是简单的流处理应用场景同时需要对系统有较大把控度那么我推荐你使用Apache Kafka。**
**2. Confluent Kafka**
下面来看Confluent Kafka。Confluent Kafka目前分为免费版和企业版两种。前者和Apache Kafka非常相像除了常规的组件之外免费版还包含Schema注册中心和REST proxy两大功能。前者是帮助你集中管理Kafka消息格式以实现数据前向/后向兼容后者用开放HTTP接口的方式允许你通过网络访问Kafka的各种功能这两个都是Apache Kafka所没有的。
除此之外免费版包含了更多的连接器它们都是Confluent公司开发并认证过的你可以免费使用它们。至于企业版它提供的功能就更多了。在我看来最有用的当属跨数据中心备份和集群监控两大功能了。多个数据中心之间数据的同步以及对集群的监控历来是Kafka的痛点Confluent Kafka企业版提供了强大的解决方案帮助你“干掉”它们。
不过Confluent Kafka的一大缺陷在于Confluent公司暂时没有发展国内业务的计划相关的资料以及技术支持都很欠缺很多国内Confluent Kafka使用者甚至无法找到对应的中文文档因此目前Confluent Kafka在国内的普及率是比较低的。
**一言以蔽之如果你需要用到Kafka的一些高级特性那么推荐你使用Confluent Kafka。**
**3. CDH/HDP Kafka**
最后说说大数据云公司发布的KafkaCDH/HDP Kafka。这些大数据平台天然集成了Apache Kafka通过便捷化的界面操作将Kafka的安装、运维、管理、监控全部统一在控制台中。如果你是这些平台的用户一定觉得非常方便因为所有的操作都可以在前端UI界面上完成而不必去执行复杂的Kafka命令。另外这些平台提供的监控界面也非常友好你通常不需要进行任何配置就能有效地监控 Kafka。
但是凡事有利就有弊这样做的结果是直接降低了你对Kafka集群的掌控程度。毕竟你对下层的Kafka集群一无所知你怎么能做到心中有数呢这种Kafka的另一个弊端在于它的滞后性。由于它有自己的发布周期因此是否能及时地包含最新版本的Kafka就成为了一个问题。比如CDH 6.1.0版本发布时Apache Kafka已经演进到了2.1.0版本但CDH中的Kafka依然是2.0.0版本显然那些在Kafka 2.1.0中修复的Bug只能等到CDH下次版本更新时才有可能被真正修复。
**简单来说如果你需要快速地搭建消息引擎系统或者你需要搭建的是多框架构成的数据平台且Kafka只是其中一个组件那么我推荐你使用这些大数据云公司提供的Kafka。**
## 小结
总结一下我们今天讨论了不同的Kafka“发行版”以及它们的优缺点根据这些优缺点我们可以有针对性地根据实际需求选择合适的Kafka。下一期我将带你领略Kafka各个阶段的发展历程这样我们选择Kafka功能特性的时候就有了依据在正式开启Kafka应用之路之前也夯实了理论基础。
最后我们来复习一下今天的内容:
- Apache Kafka也称社区版Kafka。优势在于迭代速度快社区响应度高使用它可以让你有更高的把控度缺陷在于仅提供基础核心组件缺失一些高级的特性。
- Confluent KafkaConfluent公司提供的Kafka。优势在于集成了很多高级特性且由Kafka原班人马打造质量上有保证缺陷在于相关文档资料不全普及率较低没有太多可供参考的范例。
- CDH/HDP Kafka大数据云公司提供的Kafka内嵌Apache Kafka。优势在于操作简单节省运维成本缺陷在于把控度低演进速度较慢。
<img src="https://static001.geekbang.org/resource/image/a2/11/a2ec80dceb9ba6eeaaeebc662f439211.jpg" alt="">
## 开放讨论
设想你是一家创业公司的架构师公司最近准备改造现有系统引入Kafka作为消息中间件衔接上下游业务。作为架构师的你会怎么选择合适的Kafka发行版呢
欢迎你写下自己的思考或疑问,我们一起讨论 。如果你觉得有所收获,也欢迎把文章分享给你的朋友。

View File

@@ -0,0 +1,61 @@
<audio id="audio" title="05 | 聊聊Kafka的版本号" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/0a/d9/0a2078eee0647452a6fe68e5861dead9.mp3"></audio>
你好我是胡夕。今天我想和你聊聊如何选择Kafka版本号这个话题。今天要讨论的内容实在是太重要了我觉得它甚至是你日后能否用好Kafka的关键。
上一期我介绍了目前流行的几种Kafka发行版其实不论是哪种Kafka本质上都内嵌了最核心的Apache Kafka也就是社区版Kafka那今天我们就来说说Apache Kafka版本号的问题。在开始之前我想强调一下后面出现的所有“版本”这个词均表示Kafka具体的版本号而非上一篇中的Kafka种类这一点切记切记
那么现在你可能会有这样的疑问我为什么需要关心版本号的问题呢直接使用最新版本不就好了吗当然了这的确是一种有效的选择版本的策略但我想强调的是这种策略并非在任何场景下都适用。如果你不了解各个版本之间的差异和功能变化你怎么能够准确地评判某Kafka版本是不是满足你的业务需求呢因此在深入学习Kafka之前花些时间搞明白版本演进实际上是非常划算的一件事。
## Kafka版本命名
当前Apache Kafka已经迭代到2.2版本社区正在为2.3.0发版日期进行投票相信2.3.0也会马上发布。但是稍微有些令人吃惊的是很多人对于Kafka的版本命名理解存在歧义。比如我们在官网上下载Kafka时会看到这样的版本
<img src="https://static001.geekbang.org/resource/image/c1/23/c10df9e6f72126e9c721fba38e27ac23.png" alt="">
于是有些同学就会纳闷难道Kafka版本号不是2.11或2.12吗其实不然前面的版本号是编译Kafka源代码的Scala编译器版本。Kafka服务器端的代码完全由Scala语言编写Scala同时支持面向对象编程和函数式编程用Scala写成的源代码编译之后也是普通的“.class”文件因此我们说Scala是JVM系的语言它的很多设计思想都是为人称道的。
事实上目前Java新推出的很多功能都是在不断向Scala语言靠近罢了比如Lambda表达式、函数式接口、val变量等。一个有意思的事情是Kafka新版客户端代码完全由Java语言编写于是有些人展开了“Java VS Scala”的大讨论并从语言特性的角度尝试分析Kafka社区为什么放弃Scala转而使用Java重写客户端代码。其实事情远没有那么复杂仅仅是因为社区来了一批Java程序员而已而以前老的Scala程序员隐退罢了。可能有点跑题了但不管怎样我依然建议你有空去学学Scala语言。
回到刚才的版本号讨论。现在你应该知道了对于kafka-2.11-2.1.1的提法真正的Kafka版本号实际上是2.1.1。那么这个2.1.1又表示什么呢前面的2表示大版本号即Major Version中间的1表示小版本号或次版本号即Minor Version最后的1表示修订版本号也就是Patch号。Kafka社区在发布1.0.0版本后特意写过一篇文章宣布Kafka版本命名规则正式从4位演进到3位比如0.11.0.0版本就是4位版本号。
坦率说这里我和社区的意见是有点不同的。在我看来像0.11.0.0这样的版本虽然有4位版本号但其实它的大版本是0.11而不是0所以如果这样来看的话Kafka版本号从来都是由3个部分构成即“大版本号 - 小版本号 - Patch号”。这种视角可以统一所有的Kafka版本命名也方便我们日后的讨论。我们来复习一下假设碰到的Kafka版本是0.10.2.2你现在就知道了它的大版本是0.10小版本是2总共打了两个大的补丁Patch号是2。
## Kafka版本演进
Kafka目前总共演进了7个大版本分别是0.7、0.8、0.9、0.10、0.11、1.0和2.0其中的小版本和Patch版本很多。哪些版本引入了哪些重大的功能改进关于这个问题我建议你最好能做到如数家珍因为这样不仅令你在和别人交谈Kafka时显得很酷而且如果你要向架构师转型或者已然是架构师那么这些都是能够帮助你进行技术选型、架构评估的重要依据。
我们先从0.7版本说起,实际上也没什么可说的,这是最早开源时的“上古”版本了,以至于我也从来都没有接触过。这个版本只提供了最基础的消息队列功能,甚至连副本机制都没有,我实在想不出有什么理由你要使用这个版本,因此一旦有人向你推荐这个版本,果断走开就好了。
Kafka从0.7时代演进到0.8之后正式引入了**副本机制**至此Kafka成为了一个真正意义上完备的分布式高可靠消息队列解决方案。有了副本备份机制Kafka就能够比较好地做到消息无丢失。那时候生产和消费消息使用的还是老版本的客户端API所谓的老版本是指当你用它们的API开发生产者和消费者应用时你需要指定ZooKeeper的地址而非Broker的地址。
如果你现在尚不能理解这两者的区别也没关系我会在专栏的后续文章中详细介绍它们。老版本客户端有很多的问题特别是生产者API它默认使用同步方式发送消息可以想见其吞吐量一定不会太高。虽然它也支持异步的方式但实际场景中可能会造成消息的丢失因此0.8.2.0版本社区引入了**新版本Producer API**即需要指定Broker地址的Producer。
据我所知国内依然有少部分用户在使用0.8.1.1、0.8.2版本。**我的建议是尽量使用比较新的版本。如果你不能升级大版本我也建议你至少要升级到0.8.2.2这个版本因为该版本中老版本消费者API是比较稳定的。另外即使你升到了0.8.2.2也不要使用新版本Producer API此时它的Bug还非常多。**
时间来到了2015年11月社区正式发布了0.9.0.0版本。在我看来这是一个重量级的大版本更迭0.9大版本增加了基础的安全认证/权限功能同时使用Java重写了新版本消费者API另外还引入了Kafka Connect组件用于实现高性能的数据抽取。如果这么多眼花缭乱的功能你一时无暇顾及那么我希望你记住这个版本的另一个好处那就是**新版本Producer API在这个版本中算比较稳定了**。如果你使用0.9作为线上环境不妨切换到新版本Producer这是此版本一个不太为人所知的优势。但和0.8.2引入新API问题类似不要使用新版本Consumer API因为Bug超多的绝对用到你崩溃。即使你反馈问题到社区社区也不会管的它会无脑地推荐你升级到新版本再试试因此千万别用0.9的新版本Consumer API。对于国内一些使用比较老的CDH的创业公司鉴于其内嵌的就是0.9版本,所以要格外注意这些问题。
0.10.0.0是里程碑式的大版本,因为该版本**引入了Kafka Streams**。从这个版本起Kafka正式升级成分布式流处理平台虽然此时的Kafka Streams还基本不能线上部署使用。0.10大版本包含两个小版本0.10.1和0.10.2它们的主要功能变更都是在Kafka Streams组件上。如果你把Kafka用作消息引擎实际上该版本并没有太多的功能提升。不过在我的印象中自0.10.2.2版本起新版本Consumer API算是比较稳定了。**如果你依然在使用0.10大版本我强烈建议你至少升级到0.10.2.2然后使用新版本Consumer API。还有个事情不得不提0.10.2.2修复了一个可能导致Producer性能降低的Bug。基于性能的缘故你也应该升级到0.10.2.2。**
在2017年6月社区发布了0.11.0.0版本引入了两个重量级的功能变更一个是提供幂等性Producer API以及事务Transaction API另一个是对Kafka消息格式做了重构。
前一个好像更加吸引眼球一些毕竟Producer实现幂等性以及支持事务都是Kafka实现流处理结果正确性的基石。没有它们Kafka Streams在做流处理时无法向批处理那样保证结果的正确性。当然同样是由于刚推出此时的事务API有一些Bug不算十分稳定。另外事务API主要是为Kafka Streams应用服务的实际使用场景中用户利用事务API自行编写程序的成功案例并不多见。
第二个重磅改进是消息格式的变化。虽然它对用户是透明的但是它带来的深远影响将一直持续。因为格式变更引起消息格式转换而导致的性能问题在生产环境中屡见不鲜所以你一定要谨慎对待0.11版本的这个变化。不得不说的是这个版本中各个大功能组件都变得非常稳定了国内该版本的用户也很多应该算是目前最主流的版本之一了。也正是因为这个缘故社区为0.11大版本特意推出了3个Patch版本足见它的受欢迎程度。我的建议是如果你对1.0版本是否适用于线上环境依然感到困惑那么至少将你的环境升级到0.11.0.3,因为这个版本的消息引擎功能已经非常完善了。
最后我合并说下1.0和2.0版本吧因为在我看来这两个大版本主要还是Kafka Streams的各种改进在消息引擎方面并未引入太多的重大功能特性。Kafka Streams的确在这两个版本有着非常大的变化也必须承认Kafka Streams目前依然还在积极地发展着。如果你是Kafka Streams的用户至少选择2.0.0版本吧。
去年8月国外出了一本书叫Kafka Streams in Action中文版《Kafka Streams实战》它是基于Kafka Streams 1.0版本撰写的。最近我用2.0版本去运行书中的例子,居然很多都已经无法编译了,足见两个版本变化之大。不过如果你在意的依然是消息引擎,那么这两个大版本都是适合于生产环境的。
最后还有个建议不论你用的是哪个版本都请尽量保持服务器端版本和客户端版本一致否则你将损失很多Kafka为你提供的性能优化收益。
## 小结
我希望现在你对如何选择合适的Kafka版本能做到心中有数了。每个Kafka版本都有它恰当的使用场景和独特的优缺点切记不要一味追求最新版本。事实上我周围的很多工程师都秉承这样的观念不要成为最新版本的“小白鼠”。了解了各个版本的差异之后我相信你一定能够根据自己的实际情况做出最正确的选择。
<img src="https://static001.geekbang.org/resource/image/9b/d1/9be3f8c5c2930f6482fb43d8bca507d1.jpg" alt="">
## 开放讨论
如何评估Kafka版本升级这件事呢你和你所在的团队有什么独特的见解
欢迎你写下自己的思考或疑问,我们一起讨论 。如果你觉得有所收获,也欢迎把文章分享给你的朋友。