mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-10-19 16:33:46 +08:00
mod
This commit is contained in:
105
极客时间专栏/Kafka核心源码解读/特别放送/特别放送(一)| 经典的Kafka学习资料有哪些?.md
Normal file
105
极客时间专栏/Kafka核心源码解读/特别放送/特别放送(一)| 经典的Kafka学习资料有哪些?.md
Normal file
@@ -0,0 +1,105 @@
|
||||
<audio id="audio" title="特别放送(一)| 经典的Kafka学习资料有哪些?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/89/0e/8959b8e7cb714bba239f4a60ac1ba60e.mp3"></audio>
|
||||
|
||||
你好,我是胡夕。我们的课程已经更新一段时间了,你每节课都按时学了吗?如果你一直跟着学习的话,相信你一定会有很多收获的。
|
||||
|
||||
当然了,我也知道,在学习源码的过程中,除了有进步的快乐,可能还会有一些痛苦,毕竟,源码并不是那么容易就可以掌握的。
|
||||
|
||||
如果你在学习的过程中遇到任何问题,都可以给我留言,我会尽快回复你,帮助你解决问题。如果你发现自己被一些不好的情绪包围了,除了要努力坚持以外,我建议你学着从这种情绪中暂时跳脱出来,让自己转换到一些轻松的话题上。今天,我要讲的特别放送的内容就非常让人放松,因为我会给你分享一些Kafka的学习资料。
|
||||
|
||||
实际上,在更新的这段时间里,经常有同学问我:“老师,我想更多地了解下Kafka,你能给我推荐一些相关的学习资料吗?”今天,我就借着这个特别放送的环节,专门为你搜罗了各种Kafka学习资料,包括书籍、视频、博客等一切影音像资料,我还把它们做成了清单,一起分享给你。
|
||||
|
||||
这些资料的深浅程度不一样,有的偏重于基础理论,有的深入底层架构,有的侧重于实际案例,有的是分享最佳实践。
|
||||
|
||||
如果你期望得到实际使用上的指导,那么可以重点关注下我提到的社区维护的文档以及各类Kafka实战书籍。如果你对Kafka源码的学习兴趣更加浓厚,那么,这节课里的各类大神级的博客以及视频资料是你需要重点关注的。因为他们经常会直接给出源码级的分析,学习这类资料既能开拓我们的思路与视野,也能加深我们对源码知识的理解,可以说是具有多重好处。
|
||||
|
||||
总之,我建议你基于自身的学习目标与兴趣,有针对性地利用这些资料。
|
||||
|
||||
我把这份清单大体分为英文资料和中文资料两大部分,我先给出收集到的所有英文资料清单。
|
||||
|
||||
## 英文资料
|
||||
|
||||
1.[Apache Kafka官方网站](https://kafka.apache.org/documentation/)
|
||||
|
||||
我不知道你有没有认真地读过官网上面的文字,这里面的所有内容都是出自Kafka Committer之手,文字言简意赅,而且内容翔实丰富。我推荐你重点研读一下其中的**Configuration篇**、**Operations篇**以及**Security篇**,特别是Configuration中的参数部分。熟练掌握这些关键的参数配置,是进阶学习Kafka的必要条件。
|
||||
|
||||
2.Confluent公司自己维护的[官方文档](http://docs.confluent.io/current/)
|
||||
|
||||
Confluent公司是Kafka初创团队创建的商业化公司,主要是为了提供基于Kafka的商业化解决方案。我们经常把他们提供的产品称为Confluent Kafka。就我个人的感觉而言,这个公司的官网质量要比社区版(即Apache Kafka官网)上乘,特别是关于Security和Kafka Streams两部分的介绍,明显高出社区版一筹。因此,我推荐你重点学习Confluent官网上关于[Security配置](https://docs.confluent.io/current/security/index.html)和[Kafka Streams组件](https://docs.confluent.io/current/streams/index.html)的文档。
|
||||
|
||||
3.Kafka的[Jira列表](https://issues.apache.org/jira/issues/?filter=-4&jql=project%20%3D%20KAFKA%20ORDER%20BY%20created%20DESC),也就是我们俗称的Bug列表
|
||||
|
||||
你可以在这个页面上搜索自己在实际环境中碰到的Kafka异常名称,然后结合自己的Kafka版本来看,这样的话,你通常能判断出该异常是不是由已知Bug造成的,从而避免浪费更多的时间去定位问题原因。另外,你还可以通过认领Jira的方式来为社区贡献代码。后面我会单独再用一节课的时间,给你具体介绍一下为社区贡献代码的完整流程。
|
||||
|
||||
4.Kafka的[KIP网站](https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Improvement+Proposals)
|
||||
|
||||
KIP的完整名称是Kafka Improvement Proposals,即Kafka的新功能提案。在这里你能够了解到Kafka社区关于新功能的所有提案与相关讨论。有意思的是,有些KIP的讨论要比KIP本身精彩得多。针对各种新功能,全球开发者在这里审思明辨,彼此讨论,有时协同互利,有时针锋相对,实在是酣畅淋漓。KIP的另一大魅力则在于它非常民主——**任何人都能申请新功能提案,将自己的想法付诸实践**。
|
||||
|
||||
5.StackOverflow的[Kafka专区](https://stackoverflow.com/questions/tagged/apache-kafka?sort=newest&pageSize=15)
|
||||
|
||||
大名鼎鼎的StackOverflow网站我就不过多介绍了。这上面的Kafka问题五花八门,而且难度参差不齐,不过你通常都能找到你想要的答案。同时,如果你对Kafka非常了解,不妨尝试回答一些问题,不仅能赚取一些积分,还能和全球的使用者一起交流,实在是一举两得。
|
||||
|
||||
6.[Confluent博客](https://www.confluent.io/blog/)
|
||||
|
||||
这里面的文章含金量特别高,你一定要仔细研读下。举个简单的例子,我已经被太多人问过这样的问题了:“一个Kafka集群到底能支撑多少分区?”其实我们都知道这种问题是没有标准答案的,你需要了解的是原理!碰巧,Confluent博客上就有一篇这样的原理性解释[文章](https://www.confluent.jp/blog/apache-kafka-supports-200k-partitions-per-cluster/),是Kafka创始人饶军写的,你不妨看一看。
|
||||
|
||||
7.Kafka社区非公开的各种资料,这包括社区维护的[Confluence文档](https://cwiki.apache.org/confluence/display/KAFKA/Index)和Google Docs
|
||||
|
||||
你几乎能在Confluence Space中找到所有的Kafka设计文档,其中关于Controller和新版Clients设计的文章非常值得一读;而Google Docs主要是两篇:一篇是Kafka事务的[详细设计文档](https://docs.google.com/document/d/11Jqy_GjUGtdXJK94XGsEIK7CP1SnQGdp2eF0wSw9ra8/edit),另一篇是[Controller重设计文档](https://docs.google.com/document/d/1rLDmzDOGQQeSiMANP0rC2RYp_L7nUGHzFD9MQISgXYM/edit)。这两篇是我目前所见过的最详细的Kafka设计文档。国内的很多Kafka书籍和博客多是援引这两篇文章,甚至是直接翻译的,足见它们的价值非凡。
|
||||
|
||||
8.Kafka社区的[Twitter首页](https://twitter.com/apachekafka)和Confluent的[Twitter首页](https://twitter.com/confluentinc)
|
||||
|
||||
你可能会说,Twitter算哪门子学习资料啊?但实际上,很多时候,你就是能够在这上面搜罗到有价值的Kafka文章,特别是Confluent的Twitter,它会定期推送关于Kafka最佳实践方面的内容。每次看到这类文章, 我都有一种意外淘到宝藏的感觉。我给你举个例子,Kafka Twitter在2019年10月12日转载了一篇名为[**Exploit Apache Kafka’s Message Format to Save Storage and Bandwidth**](https://medium.com/swlh/exploit-apache-kafkas-message-format-to-save-storage-and-bandwidth-7e0c533edf26) 的文章,这里面的内容水准很高,读起来非常过瘾,我建议你好好读一读。
|
||||
|
||||
9.YouTube上的[Kafka视频](https://www.youtube.com/results?search_query=apache+kafka&sp=EgIIAw%253D%253D)
|
||||
|
||||
这些视频内容主要包括Kafka原理的讲解、业界牛人分享等。有的时候,你会发现,我们对文字类资料的掌握程度远不如看视频来得深入。如果你的英语基础还不错的话,我推荐你重点关注下YouTube上的这些分享视频。
|
||||
|
||||
好了,上面这九个资料就是我总结的Kafka英文学习资料。总体上看,这些资料都不要求太高的英文基础。即使是像YouTube上的英文视频,也是支持实时翻译的,你不用担心出现无法理解内容的情况。
|
||||
|
||||
接下来,我来给出中文资料清单。
|
||||
|
||||
## 中文资料
|
||||
|
||||
首先,我给出我认为比较好的五本Apache Kafka书籍。
|
||||
|
||||
1.[《Kafka权威指南》](https://book.douban.com/subject/27665114/)
|
||||
|
||||
这本书是“Kafka Definitive Guide”的中译本。实际上,这本书的中英两个版本我都看过,应该说中文版翻译得很棒,你直接看中译本就行了。这本书虽然很薄,但它包含的内容几乎囊括了Kafka的方方面面,而且这本书由Committer执笔,质量上无可挑剔。
|
||||
|
||||
2.[《Kafka技术内幕》](https://book.douban.com/subject/27179953/)
|
||||
|
||||
这本书出版后一跃成为市面上能见到的Kafka最好书籍。这本书当得起“技术内幕”这四个字,里面很多Kafka原理的讲解清晰而深入,我自己读起来觉得收获很大。
|
||||
|
||||
3.[《深入理解Kafka:核心设计与实践原理》](https://book.douban.com/subject/30437872/)
|
||||
|
||||
我与这本书的作者相识,他同时精通Kafka和RabbitMQ,可以说是消息中间件领域内的大家。这本书成书于2019年,是目前市面上最新的一本Kafka书籍。我推荐你买来读一下。
|
||||
|
||||
4.[《Kafka Streams实战》](https://book.douban.com/subject/33425155/)
|
||||
|
||||
这本书是“Kafka Streams in action”的中译本,由Kafka Committer撰写而成。该书是我见到的**最深入讲解Kafka Streams的书籍**。如果你想学习基于Kafka Streams的实时流处理,那么这本书是不能不看的。
|
||||
|
||||
5.[《Apache Kafka实战》](https://book.douban.com/subject/30221096/)
|
||||
|
||||
我这本书是2018年出版的,和之前那些面向Kafka设计原理的国内佳作不同的是,该书以讨论Kafka实际应用为主。我在里面分享了我这几年参与Kafka社区以及在使用Kafka的过程中积累的各种“江湖杂技”。如果你以使用为主,那么我推荐你看下这本书。
|
||||
|
||||
书籍的推荐告一段落,下面,我再介绍三个网站给你。
|
||||
|
||||
第一个是OrcHome。据我所知,OrcHome是国人自己维护的一个Kafka教程网站。这个网站最具特色的是它有个[Kafka问答区](https://www.orchome.com/kafka/issues),你可以在这上面提问,会有人专门负责解答你提出的问题。
|
||||
|
||||
第二个是我本人的[博客](https://www.cnblogs.com/huxi2b/)。这个博客里大多是关于Kafka或者是其他大数据技术的原创文章。另外,我也会定期分享转载一些国内外的优秀博客。
|
||||
|
||||
第三个是知乎的[Kafka专区](https://www.zhihu.com/topic/20012159/newest)。和StackOverflow不同的是,这个专区上的问题多以理论探讨为主。通常大家对于这类问题的解答还是很踊跃的,我也经常在这里回复问题。如果你对Kafka的某些原理想要做深入的了解,不妨在知乎的这个专区上提出你的问题,我相信很快就会有人回复的。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,上面的这些内容就是我总结的Kafka学习资料清单,希望它们对你是有帮助的。我把它们整理在了一张表格里,你可以重点看下。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4d/b9/4d773e45c4a3f86c5d9e86bb4a7ac7b9.jpg" alt="">
|
||||
|
||||
另外,我强烈建议你把社区官网和Confluent官网文档仔仔细细地读几遍,我保证你一定会有很大的收获,毕竟,相比于清单上的其他项,官网文档是最最权威的第一手资料。
|
||||
|
||||
## 课后讨论
|
||||
|
||||
最后,我也请你分享一下你自己的Kafka学习书单、网站、影音像资料以及好的学习方法。
|
||||
|
||||
欢迎你在留言区畅所欲言,跟我交流讨论,也欢迎你把今天的内容分享给你的朋友。
|
87
极客时间专栏/Kafka核心源码解读/特别放送/特别放送(三)| 我是怎么度过日常一天的?.md
Normal file
87
极客时间专栏/Kafka核心源码解读/特别放送/特别放送(三)| 我是怎么度过日常一天的?.md
Normal file
@@ -0,0 +1,87 @@
|
||||
<audio id="audio" title="特别放送(三)| 我是怎么度过日常一天的?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/7d/42/7dd05b26e49465f76f1d1ce5c4d24342.mp3"></audio>
|
||||
|
||||
你好,我是胡夕。
|
||||
|
||||
今天,我们暂时抛开冗长的代码,轻松一下,我和你分享一个课程以外的话题——我是怎么度过日常的一天的。
|
||||
|
||||
当然了,这并不是一节说教课。也许,你看完之后,会有一种看“老干部”的既视感:每日在固定的时辰起床和睡觉,午后清茶一杯,再加上老旧钢笔留下的几抹笔迹,无论寒暑。
|
||||
|
||||
很多人说,自律是最顶级的自由。我并不敢轻言说我的这种生活就叫自律,但我的的确确乐在其中,不能自拔。我很享受这种规律的生活带给我的安全感和节奏感。我很感谢这样的日复一日,也感谢我自己。
|
||||
|
||||
子曰:“己所不欲,勿施于人。”但我认为,**己之所欲,亦勿施于人**。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/95/32/95c29962376394299e944aa3b7a06532.png" alt="">
|
||||
|
||||
“每个人应该有属于自己的人生,过自己想要的生活。”我对这句话深以为然。因此,我告诫自己,今天的分享绝非是要向你推销某种生活方式。它就是一种经历、一段总结,希望你能从中获得一些灵感,得到一点启迪。我尽力保证把它写得生动有趣,不至于让你直接跳到晚上11点上床睡觉的那部分。毕竟,睡觉好像也没什么可写的,哈哈。
|
||||
|
||||
### 早餐时补充足够的蛋白质是高效工作的关键
|
||||
|
||||
“When your dreams come alive you’re unstoppable. Take a shot, chase the sun, find the beautiful.”清晨6:30,伴随着 **Dream it possible** 的音乐闹钟,我开启了新的一天。穿上衣服洗漱完毕后,开始吃早餐。
|
||||
|
||||
我建议你一定要好好对待早餐。有些人认为,早餐吃多了,上午容易困。在我看来,这是不成立的,因为即使你不吃早餐,上午也是会困的。**瞌睡与否取决于你要做的工作,与早餐无关**。
|
||||
|
||||
早餐的种类请尽量丰富一些,最起码要有一些肉类或蛋白质,因为对于我们这些脑力工作者来说,补充足够的蛋白质是维持上午高效脑力工作的基础。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/54/27/5408922d21a558a770fc7fdfc1ef7227.jpg" alt="">
|
||||
|
||||
吃过了早餐,时间大约来到了7点半。面对北京早高峰拥挤的车流,我已然放弃了开车去上班的念头。60分钟的地铁时光不长不短,正好可以让我补个回笼觉。哦,不,是正好让我有足够的时间去学点别的东西。
|
||||
|
||||
绝大多数情况下,在我踏上地铁车厢的那一刻,我就习惯打开手机里的英语学习软件,来一个10分钟的考研单词速记。之后是个固定节目:听3集EnglishPod,唤醒一下早晨还未彻底清醒的耳朵。待这些都做完之后,剩下的时间就比较随性了。大体上,我都是在Kindle中度过的。
|
||||
|
||||
我很喜欢看书,在地铁上,手拿着Kindle,用食指滑屏翻书的动作会让我有种“自己是个知识分子”的感觉,虽然我觉得我本来就是。当然,我并不排斥纸质书。事实上,最近我在地铁上看得最多的就是一本名为《狄仁杰传》的纸质书。
|
||||
|
||||
平素里我到公司很早,一般在8点40左右。如果你是在国企或机关单位,那么请忽略这里的“很早”,这是针对互联网行业而言的。我个人非常珍视早晨的这段时间,因为在这段时间内,我的工作效率是最高的。所以,无论在哪里工作,我都愿意很早到公司。
|
||||
|
||||
一般情况下,这么早到公司的人应该是很“孤单”的,毕竟,可能很多同事依然还在路上,离公司近的甚至还在床上。安静的氛围能够让我从地铁站的喧嚣中解脱出来,身心快速得到放松。此刻,有利于专心工作的客观条件均已形成,因而我会立即进入工作状态。
|
||||
|
||||
令人遗憾的是,对于工作,我本人尚未修炼出那种如痴如醉的专注状态。站如松、坐如钟似的钉在座位上好几个小时忙于工作,我暂时还做不到。幸好,世间有一种巨高效的工作方法:**番茄钟工作法**,也就是每工作25分钟,再休息5分钟,然后开始新一轮的25分钟,如此循环往复。
|
||||
|
||||
现在,对于非会议类的任何工作,我都谨守番茄钟法则。这套工作理念再配以合适的App,真是无往而不利,帮助我极大地提升了专注力和执行力,因此,我总能完成预定的工作目标。
|
||||
|
||||
### 高效的会议,是与会人都聚焦于核心议题,而不是进行发散讨论
|
||||
|
||||
由于职位的缘故,在一天当中,我经常要参加很多公司级的多人会议。即使是在没什么人来的8、9点钟,一两个这样的会议就可能填满本就已经非常短暂的上午时间了 。于是,研究高效的会议组织方式,就成了摆在我面前的重要课题。
|
||||
|
||||
根据平日的实践,我比较推崇**亚马逊会议模式**。这是亚马逊创始人杰夫·贝索斯发明的。它的最大特点是:**静默开场**。
|
||||
|
||||
什么叫静默开场呢?简单来说就是,在会议开始前,会议组织者要把即将讨论的主要议题及内容以文档的方式发给所有与会者。会议开始后,所有与会者仔细阅读这些议题和内容,这就是所谓的静默开场。
|
||||
|
||||
这通常会持续20~30分钟,在这段时间里,与会者针对讨论议题,实时给出评审意见,并通过文字回复的方式与其他与会者互动。得益于目前先进的多人在线文档编辑工具,亚马逊会议模式能够让所有与会者很好地聚焦会议议题,从而保证了在座所有人的注意力始终关注在核心内容上,而不是进行发散式讨论。
|
||||
|
||||
另外,开会结束后,一定要创建具有明确负责人的待办项。一个有意思的现象是,如果待办项不指定由谁来完成,那么,最后“倒霉的”就是那个会议组织者,谁让ta组织会议的呢?因此,在我们公司,4人以上的会议结束后,必须要明确后续待办项以及相应的负责人。
|
||||
|
||||
### 如果每天的工作只是循规蹈矩、萧规曹随,又怎么能在芸芸众生之中脱颖而出呢?
|
||||
|
||||
不论是日常工作还是开会,中午一般都能很快地到来。经过一上午的饱满工作,我多半早已饥肠辘辘了。我个人是没有午睡习惯的,因此,在饱餐战饭之后,我通常会利用这段时间学点工作以外的东西,比如学习Kafka源码,一是为了换换脑子,二是充分利用这段时间去提高自己。
|
||||
|
||||
有人说,超越别人的时间是在工作的8小时之外,我深表赞同。如果每天的工作只是循规蹈矩、萧规曹随,我们又怎么能在芸芸众生之中脱颖而出呢?当然,这里有一句毒鸡汤给到你:纵然我们拼命努力,大概率我们也不会有多大成功。然而就像哈维尔的名言所说:“我们坚持一件事情,并不是因为这样做了会有效果,而是坚信,这样做是对的。”
|
||||
|
||||
我很珍惜午后的这段闲暇时光。通常,我会泡上最喜欢的绿茶,拿出老旧钢笔和A4空白纸,翻出最近喜爱的技术文档或商业报告,一笔一划地记录下此刻的学习心得。
|
||||
|
||||
我一直认为自己不算是个聪明人,我发现,只有把要理解的知识写下来,我才会记得牢固。我也很喜欢这样的学习方式。书写记录的过程会诱发我对所学知识的思考,这也算是难得的学习收获了。另外,日复一日的书写,帮我练就了一手好字。有时候,我会觉得,这是比学习本身更大的成就。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ae/74/aea0e818a38cf776ccf705d61f5d2274.jpeg" alt="">
|
||||
|
||||
### 很多决定哪有正确与否,我们要做的就是尽力使我们的决定变得正确
|
||||
|
||||
短暂的午休结束之后,繁忙而冗长的下午工作便开始了。
|
||||
|
||||
通常来说,我要一直忙到6点半左右。这中间充斥着各类会议,将原本整整齐齐的4个多小时切割得七零八落。不过,我想说的是,这才是工作本身的模样。坦率地说,之前我会因为没有整块的时间去做事而感到沮丧,现在每每想来,都觉得自己过于矫情。在战场上,哪有时间让你准备充分再去战斗的呢?
|
||||
|
||||
同理,我们在公司业务上快速做的每个决定,哪有什么正确与否,无一不是通过后续的努力奋斗让它们变得正确罢了。现在我非常感恩这种快节奏、碎片化的业务驱动型工作,因为它让我能够尽可能快速地做业务决策。
|
||||
|
||||
我个人不太喜欢制定详尽的计划之后再下场干活的按部就班的做事风格,尤其是在瞬息万变的互联网环境中。当下,市场压根没给业务决策人员深思熟虑的时间窗口。事儿是干出来的,路是蹚出来的,而不是做计划做出来的。
|
||||
|
||||
其实,技术也是这么个道理。想学什么技术,卷起袖子立马学就好了,不用去搞什么学习路线图,也不用花精力去思考什么捷径,更不用对这个决定患得患失。很多时候,我们都没有到拼理论拼方法的阶段,我们只需要比别人多努力一点点,就已经能够领先他们很多了。
|
||||
|
||||
吃过晚饭之后,我大致会复制中饭后的自主学习模式。
|
||||
|
||||
待时钟越过了7点半,我会重新投入到工作中。如果没有特别的事情需要加班,我会在晚上8点左右结束工作,收工回家。
|
||||
|
||||
与来时在地铁用Kindle读书不同,每天的归家路上,我通常会花一些时间反思下当天的言行。比如,一天当中哪些话说得不好,哪些事儿办得不美,哪些人未好好对待。虽远未及“每日三省吾身”的境界,但这的的确确是我的每日必修课。
|
||||
|
||||
可能因为是水瓶座的关系吧,我特别喜欢独处的时光。《百年孤独》里的那句话太令人认同了:“生命中曾经有过的所有喧嚣,都将用寂寞来偿还。”拥有对抗孤独的能力是一个人成熟的重要标志。我喜欢在独处的时光中提升自己的成熟度。
|
||||
|
||||
时钟拨到22点时,街道寂静,一天之中我最喜欢的1个小时到来了。我会在这一小时里面做很多种类的事情:研究技术、学习金融,当然还有专栏的写稿与录音。有的时候,我甚至什么都不做,只是打开手机的冥想软件,呆呆地想上许久……一小时倏然而逝,但我会期盼着它第二日的准时到达。
|
||||
|
||||
好了,终于要说到23点睡觉了。那我去睡了,我们下节课见,Zzzzz…
|
82
极客时间专栏/Kafka核心源码解读/特别放送/特别放送(二)| 一篇文章带你了解参与开源社区的全部流程.md
Normal file
82
极客时间专栏/Kafka核心源码解读/特别放送/特别放送(二)| 一篇文章带你了解参与开源社区的全部流程.md
Normal file
@@ -0,0 +1,82 @@
|
||||
<audio id="audio" title="特别放送(二)| 一篇文章带你了解参与开源社区的全部流程" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/50/f8/50e6d5e29bb7039e5acf0077a921a8f8.mp3"></audio>
|
||||
|
||||
你好,我是胡夕。从课程上线开始,我就经常被问到这样一个问题:“我想参与到Apache Kafka社区,应该怎么做呢?”今天,我就为你梳理一下参与Apache开源社区,特别是Kafka社区的最佳实践步骤。
|
||||
|
||||
参照着这套最佳实践,你能够轻松地参与到社区的日常开发中,甚至是成为社区Contributor中的一员。即使你暂时不打算加入社区开发,在你遇到Kafka难题时,这套实践法则也可以帮助你快速地找到适当的资源,节省你的时间成本。比如说,在诊断很多Kafka问题时,社区邮件组和Jira列表往往是比搜索引擎更好的工具。
|
||||
|
||||
大体上说,我们参与开源社区通常需要完成5步,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/a0/11/a025813482db2a3e93fb6b4574e38011.jpg" alt="">
|
||||
|
||||
虽然我在上图为每一步都标记了序号,但这并不表示它们之间是有先后关联顺序的,你完全可以按照任意顺序去实现它们。接下来,我就带你一步步梳理这五个方面。
|
||||
|
||||
## 1.精通Kafka源代码
|
||||
|
||||
你需要非常了解Kafka的源代码,毕竟,我们参与到开源社区的目的就是贡献我们自己的代码。不管是要修复Bug,还是想要为Kafka新增任何功能,你都要提前了解相关的源码才能进行。我们目前的这门课就是帮你完成此事的。认真学完这个课程,你至少可以对Kafka服务器端的源代码有一个深入而广泛的了解,为你后续贡献这部分代码奠定基础。
|
||||
|
||||
## 2.订阅Kafka邮件组
|
||||
|
||||
在我看来,这是参与开源社区最重要的一步,没有之一!**订阅邮件组是及时了解社区动态最快速、最有效的手段**。Kafka邮件组的活跃程度在整个Apache社区名列前茅。
|
||||
|
||||
根据[Apache社区2018年度报告](https://blogs.apache.org/foundation/entry/the-apache-software-foundation-announces37),我们可以知道,Kafka的两个邮件组users和dev分别排在最活跃邮件组Top5的第4名和第2名,足见社区的人气之高。
|
||||
|
||||
Kafka邮件组主要包含两个:users@kafka.apache.org和dev@kafka.apache.org。Kafka用户在使用过程中碰到任何问题,都可以向第一个邮件组发送邮件询问,而第二个邮件组主要用于进行Kafka开发的各种讨论。就我个人的经验而言,dev这个邮件组的含金量要更高一些,因为上面有很多针对Kafka设计以及改进建议的讨论和交流,非常值得一看。
|
||||
|
||||
订阅这些邮件组的方法很简单,你需要给这两个邮件组对应的订阅邮件地址发送邮件。比如你要订阅dev邮件组,那么可以发送一封名为“Subscribe to Kafka dev mailing list”的邮件给dev-subscribe@kafka.apache.org,这样你就每天都能收到dev邮件组的邮件了。同理,你需要发送邮件给users-subscribe@kafka.apache.org来订阅users邮件组。
|
||||
|
||||
订阅成功之后,你就可以给users和dev邮件组发送邮件、询问问题了。不过,你要记住这两个邮件组的区别。
|
||||
|
||||
- users:讨论Kafka**使用**方面的问题。
|
||||
- dev:讨论Kafka**开发**方面的问题。
|
||||
|
||||
需要注意的是,这两个邮件组每天的邮件数量非常多,如果你觉得不胜其烦,可以取消订阅。取消方法与订阅方法类似,只是你要发送邮件给对应的取消订阅邮件地址,users对应的取消订阅邮件地址是users-unsubscribe@kafka.apache.org;dev对应的是dev-unsubscribe@kafka.apache.org。
|
||||
|
||||
## 3.开通Jira权限
|
||||
|
||||
当前,Kafka使用[Jira](https://issues.apache.org/jira/issues/?filter=-4&jql=project%20%3D%20KAFKA%20ORDER%20BY%20created%20DESC)进行项目管理,负责Kafka的Bug管理和新功能提案的追踪。如果你要参与到Kafka社区,Jira权限是不能不开通的。开通权限是什么意思呢?这主要是指你要申请一个Jira的账号。账号申请完成之后,你还需要发送邮件给users@kafka.apache.org,申请将你的Jira ID加入到Kafka的Contributor列表中。只有Jira ID被加入到Contributor列表,你才有资格认领Jira ticket,也就是我们常说的修Bug。
|
||||
|
||||
## 4.开通KIP权限
|
||||
|
||||
在之前的特别放送里,我提到过[KIP](https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Improvement+Proposals),也就是Kafka新功能提案。通常情况下,你不需要任何权限,就能浏览这些新功能提案。不过,如果你要提交自己的提案,那你就必须要提前申请KIP账号权限了,具体的做法是向dev@kafka.apache.org邮箱发送申请邮件。
|
||||
|
||||
我举个例子,你可以编写一封邮件,名字为“Granting permission for Create KIP”,正文是“Please grant permission for Create KIP to wiki ID: <your_id>”,然后发送给dev邮件组。大约1到2个工作日之后,你会收到一封邮件,告知你的ID已被赋予了权限。
|
||||
|
||||
这个时候,你再次进入到[KIP页面](https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Improvement+Proposals),点击Create KIP按钮,按照页面目录结构撰写新功能提案即可。值得注意的是,**一旦你创建了自己的提案页面,在主KIP页面,你还需要修改两个地方**。
|
||||
|
||||
首先,你必须更新**下一个KIP序号**,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ff/cd/ffa044b45fa05f5065b45cf72b95f2cd.png" alt="">
|
||||
|
||||
其次,你必须把你的提案页面地址增加到**KIPs under discussion**表格下,并注明状态Under Discussion。
|
||||
|
||||
除此之外,你还需要发送一封邮件给dev邮件组,向社区声明你创建了一个KIP,想要发起新一轮的讨论。下图展示的是一封我之前负责某KIP时发起的讨论邮件:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ce/b6/cebc8828a9f6070a48beb60554c5c6b6.png" alt="">
|
||||
|
||||
把这些都做完之后,剩下的事情就是等待社区开发者对此KIP的讨论了,你需要做的就是随时回答大家提出的各种问题,然后向大家解释为什么这个KIP是很重要的功能。
|
||||
|
||||
## 5.提交Pull Request(PR)
|
||||
|
||||
参与社区的最后一步,也是最关键的一步,就是向社区提交我们自己的Pull Request,即PR。目前社区的PR大体分为两类:普通PR和MINOR PR。
|
||||
|
||||
我先说下MINOR PR。顾名思义,MINOR PR就是改动微不足道的那类PR,比如,你在阅读Kafka源码注释时,发现某个单词拼写错了,或者是变量命名不清晰,那么针对这类问题,你就可以直接给社区提一个PR。这类PR在命名时,社区有个约定俗成的规范就是,**它们要以“MINOR:”开头**,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/c5/03/c5db8ef3ed8e3a038086e3adb66ceb03.png" alt="">
|
||||
|
||||
给社区贡献MINOR PR是不需要事先创建Jira ticket的,这也是这类PR的一个特点。
|
||||
|
||||
另一类PR就是普通PR了。要提交这类PR前,你必须保证要修复的问题在Jira中存在对应的ticket,并且最好确保Jira的Assignee是你自己。如果Assignee不是你自己,那说明社区中有其他人正在研究这个问题,你最好不要抢别人家的劳动果实。如果你知道了如何修复该问题,可以在对应的Jira ticket下留言礼貌地询问是否可以把这个ticket让你来修复。如果原Assignee同意了你的请求,你再提交自己的PR也不迟。
|
||||
|
||||
一旦提交了PR之后,你的代码会被社区开发者进行Code Review,并提出很多修改意见,你需要小心谨慎地对待这些Comment并处理它们。当Committer认为你的代码满足了要求之后,他们会留言LGTM的字样,表明Look Good To Me,然后通知你代码可以被合并到主干分支了。这个时候,你就正式成为了Apache Kafka的Contributor。
|
||||
|
||||
## 总结
|
||||
|
||||
今天,我给你介绍了参与Kafka社区的最佳实践。我希望在学完这节课之后,你可以根据这个教程一步一步地实现成为Kafka Contributor的目标,甚至是成为下一个社区Committer!当然,每个人自身的实际目标和期望不同,你也可以有针对性、有限度地参与到社区中,以满足你的实际需求。
|
||||
|
||||
最后,我还想跟你分享一个国人参与开源社区的建议:**不要只和国内开发者进行对话,要多多和国外开发者进行交流合作**。我发现,很多国内开发者只会去找Kafka社区中的华人帮忙解决问题,其实,社区中的国外开发人员也是非常友善和易于沟通的,我建议你也多和他们聊一聊,相信你会有更多不一样的收获。
|
||||
|
||||
## 课后讨论
|
||||
|
||||
你想参与Kafka社区甚至是开源社区的初衷,或者你过往参与开源社区的一些有趣经历,你觉得做这些事情最大的意义或价值是什么?
|
||||
|
||||
欢迎你在留言区畅所欲言,跟我交流讨论,也欢迎你把今天的内容分享给你的朋友。
|
@@ -0,0 +1,181 @@
|
||||
<audio id="audio" title="特别放送(五) | Kafka 社区的重磅功能:移除 ZooKeeper 依赖" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/da/53/da7d86cf8e73ab0e0144a5f550d57753.mp3"></audio>
|
||||
|
||||
你好,我是胡夕。今天,我们来聊聊Kafka社区的一个重磅功能:**移除ZooKeeper依赖**。
|
||||
|
||||
Kafka从诞生开始,就跟ZooKeeper紧紧地绑在了一起。可以这么说,没有ZooKeeper,就没有Kafka今天的成功。
|
||||
|
||||
但是,随着Kafka的不断完善和演进,社区逐渐发现,在ZooKeeper和Kafka结合使用的过程中,一些问题慢慢地显现了出来。比如说,ZooKeeper并不适合于频繁的写操作,但Kafka 0.8时代的消费者就是利用ZooKeeper来保存其位移信息的。因此,移除ZooKeeper并使用Kafka内部主题的方式保存位移,就从根本上规避了ZooKeeper的这个弊病。
|
||||
|
||||
摆脱ZooKeeper依赖的另一个好处在于,这**能让Kafka变成一个独立的框架**。这样,以后在使用Kafka时,就不需要再额外维护一套ZooKeeper集群了。显然,安装、运维和调优一套分布式集群的代价是很高的,能够去除这样的依赖当然是一件好事。
|
||||
|
||||
讲到这里,我猜你一定很想知道,社区究竟打算怎么移除ZooKeeper呢?别急,我带你一步步来看下社区的计划。
|
||||
|
||||
## Clients演进
|
||||
|
||||
首先,我们来看两张图。这两张图总结了0.8.x版本和0.11.x版本(是否真的是从0.11版本开始的变化并不重要)及后续版本的功能变迁。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f3/3a/f362b8977ab64c1b086862a42c049f3a.jpg" alt="">
|
||||
|
||||
在Kafka 0.8时代,Kafka有3个Clients端,分别是:
|
||||
|
||||
- Producer,负责向Kafka写消息;
|
||||
- Consumer,负责从Kafka读消息;
|
||||
- Admin Tool,执行各种运维任务,比如创建或删除主题等。
|
||||
|
||||
其中,Consumer的位移数据保存在ZooKeeper上,因此,Consumer端的位移提交和位移获取操作都需要访问ZooKeeper。另外,Admin Tool执行运维操作也要访问ZooKeeper,比如在对应的ZooKeeper znode上创建一个临时节点,然后由预定义的Watch触发相应的处理逻辑。
|
||||
|
||||
后来,随着Kafka的演进,社区引入了位移主题(__consumer_offsets),同时定义了OffsetFetch和OffsetCommit等新的RPC协议。这样一来,Consumer的位移提交和位移获取操作与位移主题直接交互,从而避免了对ZooKeeper的访问。
|
||||
|
||||
除此之外,社区还引入了新的运维工具AdminClient以及相应的CreateTopics、DeleteTopics、AlterConfigs等RPC协议,替换了原先的Admin Tool。于是,创建和删除主题这样的运维操作也完全移动到Kafka这一端来做,就像上面的第二张图展示的那样。
|
||||
|
||||
到这里,Kafka的3个Clients端基本上都不需要和ZooKeeper交互了。应该说,移除ZooKeeper的工作完成了一大半,不过,依然还有一部分工作要在ZooKeeper的帮助下完成,那就是Consumer的Rebalance操作。
|
||||
|
||||
在0.8时代,Consumer Group的管理是交由ZooKeeper完成的,包括**组成员的管理**和**订阅分区的分配**。这个设计在新版的Consumer中也得到了修正——**全部的Group管理操作交由Kafka Broker端新引入的Coordinator组件来完成**。要完成这些工作,Broker端新增了很多RPC协议,比如JoinGroup、SyncGroup、Heartbeat、LeaveGroup等。
|
||||
|
||||
此时,Kafka的Java Clients端除了AdminClient还要依赖ZooKeeper之外,所有其他的组件全部摆脱了对ZooKeeper的依赖。
|
||||
|
||||
之后,社区引入了Kafka安全层,实现了对用户的认证和授权。这个额外的安全层也是不需要访问ZooKeeper的,因此,之前依赖ZooKeeper的Clients端是无法“享用”这个安全层的。一旦启用,新版Clients都需要首先接入这一层,而且要在通过审核之后才能访问到Broker,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/3a/1a/3a11e19b0072b880ef5e13d296bb751a.jpg" alt="">
|
||||
|
||||
这么做的好处就是**统一了Clients端访问Broker端的模式**,即通过定义一套跨语言RPC协议栈,实现Clients端与Broker端的服务连接。这样一来,不同的语言开发者只需要按照这套规范开发自己语言的RPC协议,就能实现与Kafka Broker端的交互了。如果后面需要实现更多的功能,社区只需要定义新的RPC协议就行了。同时,新引入的安全层负责对这套RPC协议进行安全校验,统一了访问模式。另外,这些协议都是版本化的(versioned),能够独立地进行演进,同时也兼顾了兼容性方面的考量。
|
||||
|
||||
## Broker间交互
|
||||
|
||||
说完了Clients端,我们说下Broker端的现状。目前,应该说Kafka Broker端对ZooKeeper是重度依赖的,主要表现在以下几个方面:
|
||||
|
||||
- Broker注册管理;
|
||||
- ACL安全层配置管理;
|
||||
- 动态参数管理;
|
||||
- 副本ISR管理;
|
||||
- Controller选举。
|
||||
|
||||
我们拿一张图来说明。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/36/e7/36d1738674d272c01af86f2c5e06f6e7.png" alt="">
|
||||
|
||||
图中有4个Broker节点和1个ZooKeeper,左上角的Broker充当Controller的角色。当前,所有的Broker启动后都必须维持与ZooKeeper的会话。Kafka依赖于这个会话实现Broker端的注册。而且,Kafka集群中的所有配置信息、副本信息、主题信息也都保存在ZooKeeper上。最后,Controller与集群中的每个Broker都维持了一个TCP长连接,用于向这些Broker发送RPC请求。当前的Controller RPC类型主要有3大类:
|
||||
|
||||
1. LeaderAndIsr:主要用于向集群广播主题分区Leader和ISR的变更情况,比如对应的Broker应该是特定分区的Leader还是Follower;
|
||||
1. StopReplica:向集群广播执行停止副本的命令;
|
||||
1. UpdateMetadata:向集群广播执行变更元数据信息的命令。
|
||||
|
||||
图中还新增了一个AlterISR RPC,这是KIP-497要实现的新RPC协议。现阶段,Kafka各个主题的ISR信息全部保存在ZooKeeper中。如果后续要舍弃ZooKeeper,就必须将这些信息从ZooKeeper中移出来,放在Controller端来做。同时,还要在程序层面支持对ISR的管理。因此,社区计划在KIP-497上增加AlterISR协议。对了,还要提一句,当前Controller的选举也是依靠ZooKeeper完成的。
|
||||
|
||||
所以,后面Broker端的演进可能和Clients端的路线差不多:首先是把Broker与ZooKeeper的交互全部干掉,只让Controller与ZooKeeper进行交互,而其他所有Broker都只与Controller交互,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/2f/e9/2fb41e8ab62cdf402c7cb56d681627e9.png" alt="">
|
||||
|
||||
看上去,这种演进路线社区已经走得轻车熟路了,但实际上还有一些遗留问题,需要解决。
|
||||
|
||||
### Broker Liveness
|
||||
|
||||
首先就是Broker的liveness问题,也就是,Kafka如何判断一个Broker到底是否存活?在目前的设计中,Broker的生存性监测完全依赖于与ZooKeeper之间的会话。一旦会话超时或断开,Controller自动触发ZooKeeper端的Watch来移除该Broker,并对它上面的分区做善后处理。如果移除了ZooKeeper,Kafka应该采用什么机制来判断Broker的生存性是一个问题。
|
||||
|
||||
### Network Partition
|
||||
|
||||
**如何防范网络分区(Network Partition)**也是一个需要讨论的话题。当前可能出现的Network Partition有4种:
|
||||
|
||||
1. 单个Broker完全与集群隔离;
|
||||
1. Broker间无法通讯;
|
||||
1. Broker与ZooKeeper无法通讯;
|
||||
1. Broker与Controller无法通讯。
|
||||
|
||||
下面4张图分别展示了这4种情况:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/24/c7/24df41ac85ca244b674dbe84f4d6bcc7.png" alt=""><br>
|
||||
<img src="https://static001.geekbang.org/resource/image/c2/88/c27c86320d961816516b75634fd67d88.png" alt="">
|
||||
|
||||
我们分别来讨论下。
|
||||
|
||||
情况一:单Broker与集群的其他Broker隔离,这其实并不算太严重的问题。当前的设计已经能够保证很好地应对这种情况了。一旦Broker被隔离,Controller会把它从集群中摘除,虽然可用性降低了,但是整个集群的一致性依然能够得到保证。
|
||||
|
||||
情况二:Broker间无法通讯,可能的后果是消息的备份机制无法执行,Kafka要收缩ISR,**依然是可用性上的降低,但是一致性状态并没有被破坏**。
|
||||
|
||||
情况三:Broker无法与ZooKeeper通讯。Broker能正常运转,它只是无法与ZooKeeper进行通讯。这个时候,我们说该Broker处于僵尸状态,即所谓的Zoobie状态。在社区的Jira中,因Zoobie状态引入的一致性Bug一直没有断过,社区这几年也一直在修正这方面的问题,主要对抗的机制就是**fencing**,比如Leader Epoch。
|
||||
|
||||
情况四:Broker无法与Controller通讯。在这种情况下,所有的元数据更新通道被堵死,即使这个Broker依然是healthy的,它保存的元数据信息也可能是非常过期的。这样的话,连接这个Broker的Clients端可能会看到各种非常古怪的问题。我之前回答过类似的问题,你可以点击[链接](https://www.zhihu.com/question/313683699/answer/609887054)看一下。
|
||||
|
||||
这种情况比较复杂,我就再多唠叨几句。实际上,针对这种情况,目前社区也没有太好的解决办法,主要的原因是,Broker的liveness完全是交由ZooKeeper来做的。一旦Broker与ZooKeeper之间的交互没有问题,其他原因导致的liveness问题就无法彻底规避。
|
||||
|
||||
第四类Network Partition引入了一个经典的场景:**元数据不一致**。目前,每个Broker都缓存了一份集群的元数据信息,这份数据是异步更新的。当第四类Partition发生的时候,Broker端缓存的元数据信息必然与Controller的不同步,这就会造成各种各样的问题。
|
||||
|
||||
下面,我简单介绍一下元数据更新的过程。主要流程就是,Controller启动时会同步从ZooKeeper上拉取集群全量的元数据信息,之后再以异步的方式同步给其他Broker。其他Broker与Controller之间的同步往往有一个时间差,也就是说,Clients访问的元数据可能并不是最新的。我个人认为,现在社区很多flaky test failure都是这个原因导致的。
|
||||
|
||||
事实上,在实际使用过程中,有很多场景是Broker端的元数据与Controller端永远不同步。通常情况下,如果我们不重启Broker的话,那么这个Broker上的元数据将永远“错误”下去。
|
||||
|
||||
好在社区还给出了一个最后的“大招”: **登录到ZooKeeper SHELL,手动执行rmr /controller,强迫Controller重选举,然后重新加载元数据,并给所有Broker重刷一份**。不过,我怀疑,在实际生产环境中是否有人真的要这么干,毕竟这样做的代价不小,而且最关键的是,这么做依然可能存在两个问题:
|
||||
|
||||
1. 我们如何确保Controller和Broker的数据是一致的?
|
||||
1. 加载元数据的过程通常很慢。
|
||||
|
||||
这里我详细说说第二点,即加载元数据的性能问题。
|
||||
|
||||
总体来说,加载元数据是一个O(N)时间复杂度的过程,这里的N就是你集群中总的分区数。考虑到Controller从ZooKeeper加载之后还要推给其他的Broker,那么做这件事的总的时间复杂度就是O(N * M),其中M是集群中Broker的数量。可以想见,当M和N都很大时,在集群中广播元数据不是一个很快的过程。
|
||||
|
||||
考虑到刚刚我们提到的所有问题,当Kafka抛弃了ZooKeeper之后,社区如何解决它们呢?总体的思路就是**Metadata as an Event Log + Controller quorum**。我们先说metadata as an event log。
|
||||
|
||||
## Metadata as an Event Log
|
||||
|
||||
如果你读过Jay Kreps的《I ❤️ Logs》,你应该有感触,整个Kafka的架构其实都是构建在Log上的。每个Topic的分区本质上就是一个Commit Log,但元数据信息的保存却不是Log形式。在现有的架构设计中,你基本上可以认为元数据的数据结构是KV形式的。这一次,社区采用了与消息相同的数据保存方式,也就是将元数据作为Log的方式保存起来,如下表所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/7y/d2/7yyce6c9266a6814c82b95623de5ced2.jpg" alt="">
|
||||
|
||||
利用Kafka自身的Log机制保存元数据的做法,有以下4个优点:
|
||||
|
||||
- **高可用性**:每次元数据的变更都被当作是一条消息保存在Log中,而这个Log可以被视为一个普通的Kafka主题被备份到多台Broker上。
|
||||
- **顺序性**:Log的一个好处在于它有清晰的前后顺序关系,即**每个事件发生的时间是可以排序的**,配合以恰当的处理逻辑,我们就能保证,对元数据变更的处理是按照变更发生的时间进行顺序处理的,不出现乱序的情形。
|
||||
- **增量同步性**:利用Log机制之后,Broker间同步元数据能够采用同步增量数据(delta)的方式,无需每次都同步全量数据。目前,Kafka Broker间同步元数据都是全量状态同步的。前面说过了,当集群分区数很大时,这个开销是很可观的。如果我们能够只同步增量状态,势必能极大地降低同步成本。
|
||||
- **可监控性**:Log提供了丰富的监控指标。我们根据这些指标能够轻易地获取到元数据同步的进度。
|
||||
|
||||
采用Log机制后,其他Broker像是一个普通的Consumer,从Controller拉取元数据变更消息或事件。由于每个Broker都是一个Consumer,所以它们会维护自己的消费位移,如下图所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/6f/a7/6fed3629c35f413f8fa1bda543610fa7.png" alt="">
|
||||
|
||||
在这种设计下,Controller所在的Broker必须要承担起所有元数据Topic的管理工作,包括创建Topic、管理Topic分区的Leader以及为每个元数据变更创建相应的事件等。既然社区选择和__consumer_offsets类似的处理方式,一个很自然的问题就是,这个元数据Topic的管理是否能够复用Kafka现有的副本机制?答案是:不可行。理由是现有的副本机制依赖于Controller,因此,Kafka没法依靠现有的副本机制来实现Controller。按照我们的俗语来说,这有点“鸡生蛋、蛋生鸡“的问题,属于典型的循环依赖。
|
||||
|
||||
为了实现这个,Kafka需要一套Leader选举协议,而这套协议或算法是不依赖于Controller的,即它是一个自管理的集群quorum(抱歉,在分布式领域内,特别是分布式共识算法领域中,针对quorum的恰当翻译我目前还未找到,因此直接使用quorum原词了)。最终,社区决定采用Raft来实现这组quorum。这就是上面我们提到的第二个解决思路:Controller quorum。
|
||||
|
||||
## Controller Quorum
|
||||
|
||||
与借助Controller帮忙选择Leader不同,Raft是让自己的节点自行选择Leader,并最终令所有节点达成共识。对选择Controller而言,这是一个很好的特性。其实,Kafka现有的备份机制已经跟Raft很接近了。你可以看一下下面这张表格,简单对它们进行下对比。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/2b/73/2bb605df5969f7160ec3b0e7b1cce273.jpeg" alt="">
|
||||
|
||||
一眼扫过去,你会发现,其实Kafka的备份机制和Raft很类似,比如,Kafka中的offset其实就是Raft中的index,epoch对应于term。当然,Raft中采用半数机制来确保消息被提交以及Leader选举,而Kafka设计了ISR机制来实现这两点。总体来说,社区认为只需要对备份机制做一些小改动,应该就可以很容易地切换到Raft-based算法了。
|
||||
|
||||
下面这张图展示的Controller quorum可能更加直观:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e7/fd/e7b060b49yy1ba7776879e90bc672dfd.jpg" alt="">
|
||||
|
||||
整个Controller quorum类似于一个小的集群。和ZooKeeper类似,这个quorum通常是3台或5台机器,不需要让Kafka中的每个Broker都自动成为这个quorum中的一个节点。
|
||||
|
||||
该quorum里面有一个Leader负责处理Clients端发来的读写请求,这个Leader就是Kafka中的active Controller。根据ZooKeeper的Zab协议,Leader处理所有的写请求,而Follower是可以处理读请求的。当写请求发送给Follower后,Follower会将该请求转发给Leader处理。
|
||||
|
||||
不过,我猜Kafka应该不会这样实现,它应该只会让Leader(即active Controller)处理所有的读写请求,而Clients端(也就是其他Broker)压根就不会发送读写请求给Follower。在这一点上,这种设计和现有的Kafka请求处理机制是一致的。
|
||||
|
||||
现在还需要解决一个问题,即Leader是怎么被选出来的?既然是Raft-based,那么采用的也是Raft算法中的Leader选举策略。让Raft选出的Leader称为active Controller。网上有很多关于Raft选主的文章,我就不再赘述了,有兴趣的可以读一读Raft的论文:[**In Search of an Understandable Consensus Algorithm(Extended Version)**](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf)。
|
||||
|
||||
这套Raft quorum有2个好处。
|
||||
|
||||
第一个好处就是,它天然提供了低延时的Failover,因此,Leader的切换会非常得迅速和及时,因为理论上不再有元数据加载的过程了,所有的元数据现在都同步保存Follower节点的内存中,它已经有其他Broker需要拉取的所有元数据信息了!
|
||||
|
||||
更酷的是,它避免了现在机制中一旦Controller切换,就要全量拉取元数据的低效行为,Broker不需要重新拉取之前已经“消费”的元数据变更消息,只需要从新Leader继续“消费”即可。
|
||||
|
||||
另一个好处在于,采用了这套机制后,Kafka可以**做元数据的缓存**了(metadata caching),即Broker能够把元数据保存在磁盘上。同时,就像刚才说的,Broker只需读取它关心的那部分数据即可。另外,和现在的snapshot机制类似,如果一个Broker保存的元数据落后Controller太多,或者是一个全新的Broker,Kafka甚至可以像Raft那样直接发送一个snapshot文件,快速令其追上进度。当然,在大多数情况下,Broker只需要拉取delta增量数据就行了。
|
||||
|
||||
## 总结
|
||||
|
||||
基于以上的这些解决方案,社区打算分三步来完成对ZooKeeper的依赖:
|
||||
|
||||
1. 第一步:移除Clients端对ZooKeeper的依赖。这一步基本上已经完成了,除了目前AdminClient还有少量的API依赖ZooKeeper之外,其他Clients端应该说都不需要访问ZooKeeper了。
|
||||
1. 第二步:移除Broker端的ZooKeeper依赖。这主要包括移除Broker端需要访问ZooKeeper的代码,以及增加新的Broker端API,比如前面说的AlterISR等,最后是将对ZooKeeper的访问全部集中在controller端。
|
||||
1. 最后一步:实现controller quorum,也就是实现Raft-based的quorum负责controller的选举。
|
||||
|
||||
应该说,移除ZooKeeper的功能算是近几年社区最为重磅的提案了。这个提案涉及组件之广、历时之长、复杂程度之高在社区中非常罕见。一旦后续完整地实现了这个功能,Apache Kafka将极大地提升自己的可维护性,以一个更加“清爽”的形象出现在我们面前。至于最后的效果如何,就让我们拭目以待吧。
|
||||
|
||||
## 课后讨论
|
||||
|
||||
我在前面提到,社区打算自己写一套Raft-based的算法来实现Controller的选举,你觉得,为什么社区不直接采用第三方成熟的Raft库来实现呢?
|
||||
|
||||
欢迎你在留言区畅所欲言,跟我交流讨论,也欢迎你把今天的内容分享给你的朋友。
|
205
极客时间专栏/Kafka核心源码解读/特别放送/特别放送(四)| 20道经典的Kafka面试题详解.md
Normal file
205
极客时间专栏/Kafka核心源码解读/特别放送/特别放送(四)| 20道经典的Kafka面试题详解.md
Normal file
@@ -0,0 +1,205 @@
|
||||
<audio id="audio" title="特别放送(四)| 20道经典的Kafka面试题详解" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a8/0b/a82d1f9a1c21f46d4f9350ba6574f10b.mp3"></audio>
|
||||
|
||||
你好,我是胡夕。这一期的“特别放送”,我想跟你分享一些常见的Kafka面试题。
|
||||
|
||||
无论是作为面试官,还是应聘者,我都接触过很多Kafka面试题。有的题目侧重于基础的概念考核,有的关注实际场景下的解决方案,有的属于“炫技式”,有的可算是深入思考后的“灵魂拷问”。“炫技”类的问题属于冷门的Kafka组件知识考核,而“灵魂拷问”类的问题大多是对Kafka设计原理的深入思考,有很高的技术难度。
|
||||
|
||||
每类题目的应对方法其实不太一样。今天,我就按照这4种类别,具体讲解20道面试题。不过,我不打算只给出答案,我会把面试题的考核初衷也一并写出来。同时,我还会给你分享一些面试小技巧,希望能够帮你更顺利地获取心仪的offer。
|
||||
|
||||
那么,话不多说,我们现在开始吧。
|
||||
|
||||
## 基础题目
|
||||
|
||||
### 1.Apache Kafka是什么?
|
||||
|
||||
这是一道很常见的题目,看似很无聊,其实考核的知识点很多。
|
||||
|
||||
首先,它考验的是,你对Kafka的定位认知是否准确。Apache Kafka一路发展到现在,已经由最初的分布式提交日志系统逐渐演变成了实时流处理框架。因此,这道题你最好这么回答:**Apach Kafka是一款分布式流处理框架,用于实时构建流处理应用。它有一个核心的功能广为人知,即作为企业级的消息引擎被广泛使用。**
|
||||
|
||||
其实,这里暗含了一个小技巧。Kafka被定位为实时流处理框架,在国内的接受度还不是很高,因此,在回答这道题的时候,你一定要先明确它的流处理框架地位,这样能给面试官留下一个很专业的印象。
|
||||
|
||||
### 2.什么是消费者组?
|
||||
|
||||
从某种程度上说,这可是个“送命题”。消费者组是Kafka独有的概念,如果面试官问这个,就说明他对此是有一定了解的。我先给出标准答案:**关于它的定义,官网上的介绍言简意赅,即消费者组是Kafka提供的可扩展且具有容错性的消费者机制。**切记,一定要加上前面那句,以显示你对官网很熟悉。
|
||||
|
||||
另外,你最好再解释下消费者组的原理:**在Kafka中,消费者组是一个由多个消费者实例构成的组。多个实例共同订阅若干个主题,实现共同消费。同一个组下的每个实例都配置有相同的组ID,被分配不同的订阅分区。当某个实例挂掉的时候,其他实例会自动地承担起它负责消费的分区。**
|
||||
|
||||
此时,又有一个小技巧给到你:消费者组的题目,能够帮你在某种程度上掌控下面的面试方向。
|
||||
|
||||
- 如果你擅长**位移值原理**,就不妨再提一下消费者组的位移提交机制;
|
||||
- 如果你擅长Kafka **Broker**,可以提一下消费者组与Broker之间的交互;
|
||||
- 如果你擅长与消费者组完全不相关的**Producer**,那么就可以这么说:“消费者组要消费的数据完全来自于Producer端生产的消息,我对Producer还是比较熟悉的。”
|
||||
|
||||
使用这个策略的话,面试官可能会被你的话术所影响,偏离他之前想问的知识路径。当然了,如果你什么都不擅长,那就继续往下看题目吧。
|
||||
|
||||
### 3.在Kafka中,ZooKeeper的作用是什么?
|
||||
|
||||
这是一道能够帮助你脱颖而出的题目。碰到这个题目,请在心中暗笑三声。
|
||||
|
||||
先说标准答案:**目前,Kafka使用ZooKeeper存放集群元数据、成员管理、Controller选举,以及其他一些管理类任务。之后,等KIP-500提案完成后,Kafka将完全不再依赖于ZooKeeper。**
|
||||
|
||||
记住,**一定要突出“目前”**,以彰显你非常了解社区的演进计划。“存放元数据”是指主题分区的所有数据都保存在ZooKeeper中,且以它保存的数据为权威,其他“人”都要与它保持对齐。“成员管理”是指Broker节点的注册、注销以及属性变更,等等。“Controller选举”是指选举集群Controller,而其他管理类任务包括但不限于主题删除、参数配置等。
|
||||
|
||||
不过,抛出KIP-500也可能是个双刃剑。碰到非常资深的面试官,他可能会进一步追问你KIP-500是做的。一言以蔽之:**KIP-500思想,是使用社区自研的基于Raft的共识算法,替代ZooKeeper,实现Controller自选举**。你可能会担心,如果他继续追问的话,该怎么办呢?别怕,在下一期“特别发送”,我会专门讨论这件事。
|
||||
|
||||
### 4.解释下Kafka中位移(offset)的作用
|
||||
|
||||
这也是一道常见的面试题。位移概念本身并不复杂,你可以这么回答:**在Kafka中,每个主题分区下的每条消息都被赋予了一个唯一的ID数值,用于标识它在分区中的位置。这个ID数值,就被称为位移,或者叫偏移量。一旦消息被写入到分区日志,它的位移值将不能被修改。**
|
||||
|
||||
答完这些之后,你还可以把整个面试方向转移到你希望的地方。常见方法有以下3种:
|
||||
|
||||
- 如果你深谙Broker底层日志写入的逻辑,可以强调下消息在日志中的存放格式;
|
||||
- 如果你明白位移值一旦被确定不能修改,可以强调下“Log Cleaner组件都不能影响位移值”这件事情;
|
||||
- 如果你对消费者的概念还算熟悉,可以再详细说说位移值和消费者位移值之间的区别。
|
||||
|
||||
### 5.阐述下Kafka中的领导者副本(Leader Replica)和追随者副本(Follower Replica)的区别
|
||||
|
||||
这道题表面上是考核你对Leader和Follower区别的理解,但很容易引申到Kafka的同步机制上。因此,我建议你主动出击,一次性地把隐含的考点也答出来,也许能够暂时把面试官“唬住”,并体现你的专业性。
|
||||
|
||||
你可以这么回答:**Kafka副本当前分为领导者副本和追随者副本。只有Leader副本才能对外提供读写服务,响应Clients端的请求。Follower副本只是采用拉(PULL)的方式,被动地同步Leader副本中的数据,并且在Leader副本所在的Broker宕机后,随时准备应聘Leader副本。**
|
||||
|
||||
通常来说,回答到这个程度,其实才只说了60%,因此,我建议你再回答两个额外的加分项。
|
||||
|
||||
- **强调Follower副本也能对外提供读服务**。自Kafka 2.4版本开始,社区通过引入新的Broker端参数,允许Follower副本有限度地提供读服务。
|
||||
- **强调Leader和Follower的消息序列在实际场景中不一致**。很多原因都可能造成Leader和Follower保存的消息序列不一致,比如程序Bug、网络问题等。这是很严重的错误,必须要完全规避。你可以补充下,之前确保一致性的主要手段是高水位机制,但高水位值无法保证Leader连续变更场景下的数据一致性,因此,社区引入了Leader Epoch机制,来修复高水位值的弊端。关于“Leader Epoch机制”,国内的资料不是很多,它的普及度远不如高水位,不妨大胆地把这个概念秀出来,力求惊艳一把。上一季专栏的[第27节课](https://time.geekbang.org/column/article/112118)讲的就是Leader Epoch机制的原理,推荐你赶紧去学习下。
|
||||
|
||||
## 实操题目
|
||||
|
||||
### 6.如何设置Kafka能接收的最大消息的大小?
|
||||
|
||||
这道题除了要回答消费者端的参数设置之外,一定要加上Broker端的设置,这样才算完整。毕竟,如果Producer都不能向Broker端发送数据很大的消息,又何来消费一说呢?因此,你需要同时设置Broker端参数和Consumer端参数。
|
||||
|
||||
- Broker端参数:message.max.bytes、max.message.bytes(主题级别)和replica.fetch.max.bytes。
|
||||
- Consumer端参数:fetch.message.max.bytes。
|
||||
|
||||
Broker端的最后一个参数比较容易遗漏。我们必须调整Follower副本能够接收的最大消息的大小,否则,副本同步就会失败。因此,把这个答出来的话,就是一个加分项。
|
||||
|
||||
### 7.监控Kafka的框架都有哪些?
|
||||
|
||||
其实,目前业界并没有公认的解决方案,各家都有各自的监控之道。所以,面试官其实是在考察你对监控框架的了解广度,或者说,你是否知道很多能监控Kafka的框架或方法。下面这些就是Kafka发展历程上比较有名气的监控系统。
|
||||
|
||||
- **Kafka Manager**:应该算是最有名的专属Kafka监控框架了,是独立的监控系统。
|
||||
- **Kafka Monitor**:LinkedIn开源的免费框架,支持对集群进行系统测试,并实时监控测试结果。
|
||||
- **CruiseControl**:也是LinkedIn公司开源的监控框架,用于实时监测资源使用率,以及提供常用运维操作等。无UI界面,只提供REST API。
|
||||
- **JMX监控**:由于Kafka提供的监控指标都是基于JMX的,因此,市面上任何能够集成JMX的框架都可以使用,比如Zabbix和Prometheus。
|
||||
- **已有大数据平台自己的监控体系**:像Cloudera提供的CDH这类大数据平台,天然就提供Kafka监控方案。
|
||||
- **JMXTool**:社区提供的命令行工具,能够实时监控JMX指标。答上这一条,属于绝对的加分项,因为知道的人很少,而且会给人一种你对Kafka工具非常熟悉的感觉。如果你暂时不了解它的用法,可以在命令行以无参数方式执行一下`kafka-run-class.sh kafka.tools.JmxTool`,学习下它的用法。
|
||||
|
||||
### 8.Broker的Heap Size如何设置?
|
||||
|
||||
如何设置Heap Size的问题,其实和Kafka关系不大,它是一类非常通用的面试题目。一旦你应对不当,面试方向很有可能被引到JVM和GC上去,那样的话,你被问住的几率就会增大。因此,我建议你简单地介绍一下Heap Size的设置方法,并把重点放在Kafka Broker堆大小设置的最佳实践上。
|
||||
|
||||
比如,你可以这样回复:**任何Java进程JVM堆大小的设置都需要仔细地进行考量和测试。一个常见的做法是,以默认的初始JVM堆大小运行程序,当系统达到稳定状态后,手动触发一次Full GC,然后通过JVM工具查看GC后的存活对象大小。之后,将堆大小设置成存活对象总大小的1.5~2倍。对于Kafka而言,这个方法也是适用的。不过,业界有个最佳实践,那就是将Broker的Heap Size固定为6GB。经过很多公司的验证,这个大小是足够且良好的**。
|
||||
|
||||
### 9.如何估算Kafka集群的机器数量?
|
||||
|
||||
这道题目考查的是**机器数量和所用资源之间的关联关系**。所谓资源,也就是CPU、内存、磁盘和带宽。
|
||||
|
||||
通常来说,CPU和内存资源的充足是比较容易保证的,因此,你需要从磁盘空间和带宽占用两个维度去评估机器数量。
|
||||
|
||||
在预估磁盘的占用时,你一定不要忘记计算副本同步的开销。如果一条消息占用1KB的磁盘空间,那么,在有3个副本的主题中,你就需要3KB的总空间来保存这条消息。显式地将这些考虑因素答出来,能够彰显你考虑问题的全面性,是一个难得的加分项。
|
||||
|
||||
对于评估带宽来说,常见的带宽有1Gbps和10Gbps,但你要切记,**这两个数字仅仅是最大值**。因此,你最好和面试官确认一下给定的带宽是多少。然后,明确阐述出当带宽占用接近总带宽的90%时,丢包情形就会发生。这样能显示出你的网络基本功。
|
||||
|
||||
### 10.Leader总是-1,怎么破?
|
||||
|
||||
在生产环境中,你一定碰到过“某个主题分区不能工作了”的情形。使用命令行查看状态的话,会发现Leader是-1,于是,你使用各种命令都无济于事,最后只能用“重启大法”。
|
||||
|
||||
但是,有没有什么办法,可以不重启集群,就能解决此事呢?这就是此题的由来。
|
||||
|
||||
我直接给答案:**删除ZooKeeper节点/controller,触发Controller重选举。Controller重选举能够为所有主题分区重刷分区状态,可以有效解决因不一致导致的Leader不可用问题**。我几乎可以断定,当面试官问出此题时,要么就是他真的不知道怎么解决在向你寻求答案,要么他就是在等你说出这个答案。所以,**千万别一上来就说“来个重启”之类的话**。
|
||||
|
||||
## 炫技式题目
|
||||
|
||||
### 11.LEO、LSO、AR、ISR、HW都表示什么含义?
|
||||
|
||||
在我看来,这纯属无聊的炫技。试问我不知道又能怎样呢?!不过既然问到了,我们就统一说一说。
|
||||
|
||||
- **LEO**:Log End Offset。日志末端位移值或末端偏移量,表示日志下一条待插入消息的位移值。举个例子,如果日志有10条消息,位移值从0开始,那么,第10条消息的位移值就是9。此时,LEO = 10。
|
||||
- **LSO**:Log Stable Offset。这是Kafka事务的概念。如果你没有使用到事务,那么这个值不存在(其实也不是不存在,只是设置成一个无意义的值)。该值控制了事务型消费者能够看到的消息范围。它经常与Log Start Offset,即日志起始位移值相混淆,因为有些人将后者缩写成LSO,这是不对的。在Kafka中,LSO就是指代Log Stable Offset。
|
||||
- **AR**:Assigned Replicas。AR是主题被创建后,分区创建时被分配的副本集合,副本个数由副本因子决定。
|
||||
- **ISR**:In-Sync Replicas。Kafka中特别重要的概念,指代的是AR中那些与Leader保持同步的副本集合。在AR中的副本可能不在ISR中,但Leader副本天然就包含在ISR中。关于ISR,还有一个常见的面试题目是**如何判断副本是否应该属于ISR**。目前的判断依据是:**Follower副本的LEO落后Leader LEO的时间,是否超过了Broker端参数replica.lag.time.max.ms值**。如果超过了,副本就会被从ISR中移除。
|
||||
- **HW**:高水位值(High watermark)。这是控制消费者可读取消息范围的重要字段。一个普通消费者只能“看到”Leader副本上介于Log Start Offset和HW(不含)之间的所有消息。水位以上的消息是对消费者不可见的。关于HW,问法有很多,我能想到的最高级的问法,就是让你完整地梳理下Follower副本拉取Leader副本、执行同步机制的详细步骤。这就是我们的第20道题的题目,一会儿我会给出答案和解析。
|
||||
|
||||
### 12.Kafka能手动删除消息吗?
|
||||
|
||||
其实,Kafka不需要用户手动删除消息。它本身提供了留存策略,能够自动删除过期消息。当然,它是支持手动删除消息的。因此,你最好从这两个维度去回答。
|
||||
|
||||
- 对于设置了Key且参数cleanup.policy=compact的主题而言,我们可以构造一条<Key,null>的消息发送给Broker,依靠Log Cleaner组件提供的功能删除掉该Key的消息。
|
||||
- 对于普通主题而言,我们可以使用kafka-delete-records命令,或编写程序调用Admin.deleteRecords方法来删除消息。这两种方法殊途同归,底层都是调用Admin的deleteRecords方法,通过将分区Log Start Offset值抬高的方式间接删除消息。
|
||||
|
||||
### 13.__consumer_offsets是做什么用的?
|
||||
|
||||
这是一个内部主题,公开的官网资料很少涉及到。因此,我认为,此题属于面试官炫技一类的题目。你要小心这里的考点:该主题有3个重要的知识点,你一定要全部答出来,才会显得对这块知识非常熟悉。
|
||||
|
||||
- 它是一个内部主题,无需手动干预,由Kafka自行管理。当然,我们可以创建该主题。
|
||||
- 它的主要作用是负责注册消费者以及保存位移值。可能你对保存位移值的功能很熟悉,但其实**该主题也是保存消费者元数据的地方。千万记得把这一点也回答上**。另外,这里的消费者泛指消费者组和独立消费者,而不仅仅是消费者组。
|
||||
- Kafka的GroupCoordinator组件提供对该主题完整的管理功能,包括该主题的创建、写入、读取和Leader维护等。
|
||||
|
||||
### 14.分区Leader选举策略有几种?
|
||||
|
||||
分区的Leader副本选举对用户是完全透明的,它是由Controller独立完成的。你需要回答的是,在哪些场景下,需要执行分区Leader选举。每一种场景对应于一种选举策略。当前,Kafka有4种分区Leader选举策略。
|
||||
|
||||
- **OfflinePartition Leader选举**:每当有分区上线时,就需要执行Leader选举。所谓的分区上线,可能是创建了新分区,也可能是之前的下线分区重新上线。这是最常见的分区Leader选举场景。
|
||||
- **ReassignPartition Leader选举**:当你手动运行kafka-reassign-partitions命令,或者是调用Admin的alterPartitionReassignments方法执行分区副本重分配时,可能触发此类选举。假设原来的AR是[1,2,3],Leader是1,当执行副本重分配后,副本集合AR被设置成[4,5,6],显然,Leader必须要变更,此时会发生Reassign Partition Leader选举。
|
||||
- **PreferredReplicaPartition Leader选举**:当你手动运行kafka-preferred-replica-election命令,或自动触发了Preferred Leader选举时,该类策略被激活。所谓的Preferred Leader,指的是AR中的第一个副本。比如AR是[3,2,1],那么,Preferred Leader就是3。
|
||||
- **ControlledShutdownPartition Leader选举**:当Broker正常关闭时,该Broker上的所有Leader副本都会下线,因此,需要为受影响的分区执行相应的Leader选举。
|
||||
|
||||
这4类选举策略的大致思想是类似的,即从AR中挑选首个在ISR中的副本,作为新Leader。当然,个别策略有些微小差异。不过,回答到这种程度,应该足以应付面试官了。毕竟,微小差别对选举Leader这件事的影响很小。
|
||||
|
||||
### 15.Kafka的哪些场景中使用了零拷贝(Zero Copy)?
|
||||
|
||||
Zero Copy是特别容易被问到的高阶题目。在Kafka中,体现Zero Copy使用场景的地方有两处:**基于mmap的索引**和**日志文件读写所用的TransportLayer**。
|
||||
|
||||
先说第一个。索引都是基于MappedByteBuffer的,也就是让用户态和内核态共享内核态的数据缓冲区,此时,数据不需要复制到用户态空间。不过,mmap虽然避免了不必要的拷贝,但不一定就能保证很高的性能。在不同的操作系统下,mmap的创建和销毁成本可能是不一样的。很高的创建和销毁开销会抵消Zero Copy带来的性能优势。由于这种不确定性,在Kafka中,只有索引应用了mmap,最核心的日志并未使用mmap机制。
|
||||
|
||||
再说第二个。TransportLayer是Kafka传输层的接口。它的某个实现类使用了FileChannel的transferTo方法。该方法底层使用sendfile实现了Zero Copy。对Kafka而言,如果I/O通道使用普通的PLAINTEXT,那么,Kafka就可以利用Zero Copy特性,直接将页缓存中的数据发送到网卡的Buffer中,避免中间的多次拷贝。相反,如果I/O通道启用了SSL,那么,Kafka便无法利用Zero Copy特性了。
|
||||
|
||||
## 深度思考题
|
||||
|
||||
### 16.Kafka为什么不支持读写分离?
|
||||
|
||||
这道题目考察的是你对Leader/Follower模型的思考。
|
||||
|
||||
Leader/Follower模型并没有规定Follower副本不可以对外提供读服务。很多框架都是允许这么做的,只是Kafka最初为了避免不一致性的问题,而采用了让Leader统一提供服务的方式。
|
||||
|
||||
不过,在开始回答这道题时,你可以率先亮出观点:**自Kafka 2.4之后,Kafka提供了有限度的读写分离,也就是说,Follower副本能够对外提供读服务。**
|
||||
|
||||
说完这些之后,你可以再给出之前的版本不支持读写分离的理由。
|
||||
|
||||
- **场景不适用**。读写分离适用于那种读负载很大,而写操作相对不频繁的场景,可Kafka不属于这样的场景。
|
||||
- **同步机制**。Kafka采用PULL方式实现Follower的同步,因此,Follower与Leader存在不一致性窗口。如果允许读Follower副本,就势必要处理消息滞后(Lagging)的问题。
|
||||
|
||||
### 17.如何调优Kafka?
|
||||
|
||||
回答任何调优问题的第一步,就是**确定优化目标,并且定量给出目标**!这点特别重要。对于Kafka而言,常见的优化目标是吞吐量、延时、持久性和可用性。每一个方向的优化思路都是不同的,甚至是相反的。
|
||||
|
||||
确定了目标之后,还要明确优化的维度。有些调优属于通用的优化思路,比如对操作系统、JVM等的优化;有些则是有针对性的,比如要优化Kafka的TPS。我们需要从3个方向去考虑。
|
||||
|
||||
- **Producer端**:增加batch.size、linger.ms,启用压缩,关闭重试等。
|
||||
- **Broker端**:增加num.replica.fetchers,提升Follower同步TPS,避免Broker Full GC等。
|
||||
- **Consumer**:增加fetch.min.bytes等
|
||||
|
||||
### 18.Controller发生网络分区(Network Partitioning)时,Kafka会怎么样?
|
||||
|
||||
这道题目能够诱发我们对分布式系统设计、CAP理论、一致性等多方面的思考。不过,针对故障定位和分析的这类问题,我建议你首先言明“实用至上”的观点,即不论怎么进行理论分析,永远都要以实际结果为准。一旦发生Controller网络分区,那么,第一要务就是查看集群是否出现“脑裂”,即同时出现两个甚至是多个Controller组件。这可以根据Broker端监控指标ActiveControllerCount来判断。
|
||||
|
||||
现在,我们分析下,一旦出现这种情况,Kafka会怎么样。
|
||||
|
||||
由于Controller会给Broker发送3类请求,即LeaderAndIsrRequest、StopReplicaRequest和UpdateMetadataRequest,因此,一旦出现网络分区,这些请求将不能顺利到达Broker端。这将影响主题的创建、修改、删除操作的信息同步,表现为集群仿佛僵住了一样,无法感知到后面的所有操作。因此,网络分区通常都是非常严重的问题,要赶快修复。
|
||||
|
||||
### 19.Java Consumer为什么采用单线程来获取消息?
|
||||
|
||||
在回答之前,如果先把这句话说出来,一定会加分:**Java Consumer是双线程的设计。一个线程是用户主线程,负责获取消息;另一个线程是心跳线程,负责向Kafka汇报消费者存活情况。将心跳单独放入专属的线程,能够有效地规避因消息处理速度慢而被视为下线的“假死”情况。**
|
||||
|
||||
单线程获取消息的设计能够避免阻塞式的消息获取方式。单线程轮询方式容易实现异步非阻塞式,这样便于将消费者扩展成支持实时流处理的操作算子。因为很多实时流处理操作算子都不能是阻塞式的。另外一个可能的好处是,可以简化代码的开发。多线程交互的代码是非常容易出错的。
|
||||
|
||||
### 20.简述Follower副本消息同步的完整流程
|
||||
|
||||
首先,Follower发送FETCH请求给Leader。接着,Leader会读取底层日志文件中的消息数据,再更新它内存中的Follower副本的LEO值,更新为FETCH请求中的fetchOffset值。最后,尝试更新分区高水位值。Follower接收到FETCH响应之后,会把消息写入到底层日志,接着更新LEO和HW值。
|
||||
|
||||
Leader和Follower的HW值更新时机是不同的,Follower的HW更新永远落后于Leader的HW。这种时间上的错配是造成各种不一致的原因。
|
||||
|
||||
好了,今天的面试题分享就先到这里啦。你有遇到过什么经典的面试题吗?或者是有什么好的面试经验吗?
|
||||
|
||||
欢迎你在留言区分享。如果你觉得今天的内容对你有所帮助,也欢迎分享给你的朋友。
|
Reference in New Issue
Block a user