This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View 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&amp;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&amp;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 Kafkas 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&amp;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学习书单、网站、影音像资料以及好的学习方法。
欢迎你在留言区畅所欲言,跟我交流讨论,也欢迎你把今天的内容分享给你的朋友。

View 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 youre 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…

View 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.orgdev对应的是dev-unsubscribe@kafka.apache.org。
## 3.开通Jira权限
当前Kafka使用[Jira](https://issues.apache.org/jira/issues/?filter=-4&amp;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: &lt;your_id&gt;然后发送给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 RequestPR
参与社区的最后一步也是最关键的一步就是向社区提交我们自己的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社区甚至是开源社区的初衷或者你过往参与开源社区的一些有趣经历你觉得做这些事情最大的意义或价值是什么
欢迎你在留言区畅所欲言,跟我交流讨论,也欢迎你把今天的内容分享给你的朋友。

View File

@@ -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并对它上面的分区做善后处理。如果移除了ZooKeeperKafka应该采用什么机制来判断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中的indexepoch对应于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太多或者是一个全新的BrokerKafka甚至可以像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库来实现呢
欢迎你在留言区畅所欲言,跟我交流讨论,也欢迎你把今天的内容分享给你的朋友。

View 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的主题而言我们可以构造一条&lt;Keynull&gt;的消息发送给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是[123]Leader是1当执行副本重分配后副本集合AR被设置成[456]显然Leader必须要变更此时会发生Reassign Partition Leader选举。
- **PreferredReplicaPartition Leader选举**当你手动运行kafka-preferred-replica-election命令或自动触发了Preferred Leader选举时该类策略被激活。所谓的Preferred Leader指的是AR中的第一个副本。比如AR是[321]那么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 PartitioningKafka会怎么样
这道题目能够诱发我们对分布式系统设计、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。这种时间上的错配是造成各种不一致的原因。
好了,今天的面试题分享就先到这里啦。你有遇到过什么经典的面试题吗?或者是有什么好的面试经验吗?
欢迎你在留言区分享。如果你觉得今天的内容对你有所帮助,也欢迎分享给你的朋友。