所有的讨论都是基于KIP-291展开的。抱歉,这又是一篇没有图的文字。


目前Kafka broker对所有发过来的请求都是一视同仁的,不会区别对待。不管是用于生产消费的PRODUCE和FETCH请求,还是controller端发送的LeaderAndIsr/StopReplica/UpdateMetadata请求,亦或是其他类型的请求也是一样。通常我们这里把PRODUCE/FETCH请求称为数据类请求;把controller发送的那3种请求称为控制类请求或controller类请求——在源码中前者被称为data plane request,后者称为controller plane request。

这种公平处理原则在很多场合下都是不合理的。为什么?简单来说控制类请求具有直接令数据类请求失效的能力。举个例子,如果我有个topic,单分区双副本,其中broker0上保存leader副本,broker1上保存follower副本。当broker0上积压了大量的PRODUCE请求时,此时用户执行了重分区或preferred分区选举将broker1变更成了leader,那么controller会向broker0发送LeaderAndIsr请求告诉它现在是一个follower了,而broker1上的follower已经停止向leader拉取数据(因为它要成为leader了)——此时一个比较尴尬的情形出现了:如果producer的acks设置的是all,那么这些在LeaderAndIsr请求之前积压的PRODUCE请求就无法正常完成——要么一直缓存在purtagory中要么请求超时返回给client。设想一下,如果Kafka能够及时地处理LeaderAndIsr请求,那么这些积压的PRODUCE请求就能立即失败(NOT_LEADER_FOR_PARTITION),马上返回给client。Client不用等到 purgatory中的请求超时,降低了请求的处理时间。即使acks不是all,纵然积压的PRODUCE请求写入本地日志后成功返回,但处理过LeaderAndIsr请求后broker0上副本变为follower,还要执行截断(truncation),因此在client看来这些消息就丢失了。

再举一个例子,同样是在积压大量数据类请求的broker上,如果用户删除了topic,那么StopReplica请求无法及时处理,导致topic无法真正删除,增加了删除topic的延时。

最后还可以举个例子说明对UpdateMetadata的影响。如果UpdateMetadata不能及时处理,broker上保存的就是过期的元数据,当client获取到这些数据时,不管是producer还是consumer都可能无法正常工作,直到获取到最新的元数据信息。

通过上面3个例子可以看出通常情况下我们希望controller类请求的处理优先级要高于数据类请求,这也是社区做KIP-291的初衷 。可喜的是Kafka 2.2正式实现了这个功能,下面我们来看看社区是怎么做的:

其实在KIP-291之前,我也思考过这个问题。当时我提出的想法是这样的:在broker的KafkaRequestHandlerPool中实现一个优先级队列,当controller类请求到达时,它能够”抢占式“地排在处理队列的最前部——这是很自然的想法,所以我本以为KIP-291也是这么实现的,但通篇看下来我尴尬地发现我这个解决思路记录在“Rejected Alternatives"中。这个方案最大的问题在于它无法处理队列已满的情形,即当处理队列已经无法容纳任何新的请求时该如何支持优先处理controller类请求?纵然有优先级队列也无法解决这个问题。

KIP-291是怎么解决的呢?很简单,Kafka重新为controller类请求做了专属的监听器+请求队列+acceptor+processor线程。监听器通过Kafka的listeners和advertised.listeners设置,新的请求队列则专门保存controller类请求,而acceptor和processor线程负责接收网络发送过来的以及处理队列中的controller类请求。我们一个一个说吧。

当前,用户可以在listeners中指定多套监听器,比如PLAINTEXT://kafka1:9092, SSL://kafka1:9093。你其实也可以自定义你的监听器,比如INTERNAL://kafka1:9094。用户可以指定broker端参数inter.broker.listener.name或security.inter.broker.protocol(两个不能同时指定)来设定,同时你还需要在listener.security.protocol.map中指定这个自定义listener使用的安全协议,比如: listener.security.protocol.map=INTERNAL:PLAINTEXT。KIP-291复用了这个设计,如果你设置了inter.broker.listener.name或security.inter.broker.protocol,Kafka会默认使用这个listener专属服务controller类请求。同时社区还引入了一个新的参数:control.plane.listener.name,用来专门让你设置服务controller类请求的监听器名称。这个参数的优先级要高于前面那两个参数,因此还是推荐用户直接设置此参数,比如设置control.plane.listener.name=CONTROLLER,同时更新listener.security.protocol.map,增加CONTROLLER:PLAINTEXT匹配对(假设你用的是PLAINTEXT)。这就是为controller类请求创建监听器的方法。

下面说请求队列和acceptor、processor线程。 其实也不用细说,和现有的设计一模一样,只是默认的队列大小不再是500,而是20,默认的线程数不再是8而是2,因为我们假设controller类请求通常不应该有积压。具体的实现原理有兴趣的话直接读KafkaRequestHandlerPool.scala、RequestChannel.scala和SocketServer.scala源码吧。还需要修改的地方是controller代码,特别是在ControllerChannelManager.scala中增加新的broker时一定要使用controller类请求专属的监听器。

除了以上这些,该KIP也引入了很多监控controller类请求处理的JMX指标,如队列请求数、线程空闲程度等,这些和之前的指标都是一样的,只是仅监控controller plane监听器之用。再说一点,当前Kafka支持动态地调整请求处理线程数。在对请求进行区分处理后,我估计后续也要支持对controller类请求线程数的动态调整吧。

总体来说,将请求做区分处理后对于繁忙Kafka集群将能够更迅速地处理控制类请求,表现为状态的更新更加及时,集群不一致状态窗口将会缩小,同时还提升了整体可用性。目前该KIP还只是对请求做两类处理,也许日后会做一些更加细粒度的区分——比如Metadata请求是否也应该享有更高的优先级处理。

最后还想提一句,KIP-291是我认为近期社区改动影响比较大的两个KIP之一。另一个则是KIP-392——还记得Kafka不能从follower副本读数据的限制吧?这个KIP要打破这个限制!只是目前该KIP还在讨论中,我们后面拭目以待吧。

关于Kafka区分请求处理优先级的讨论的更多相关文章

  1. kafka学习笔记(五)kafka的请求处理模块

    概述 现在介绍学习一下kafka的请求处理模块,请求处理模块就是网络请求处理和api处理,这是kafka无论是对客户端还是集群内部都是非常重要的模块.现在我们对他进行源码深入探讨.当我们说到 Kafk ...

  2. Kafka设计解析(二十一)关于Kafka幂等producer的讨论

    转载自 huxihx,原文链接 关于Kafka幂等producer的讨论 众所周知,Kafka 0.11.0.0版本正式支持精确一次处理语义(exactly once semantics,下称EOS) ...

  3. 关于Kafka日志留存策略的讨论

    关于Kafka日志留存(log retention)策略的介绍,网上已有很多文章.不过目前其策略已然发生了一些变化,故本文针对较新版本的Kafka做一次统一的讨论.如果没有显式说明,本文一律以Kafk ...

  4. 关于Kafka幂等producer的讨论

    众所周知,Kafka 0.11.0.0版本正式支持精确一次处理语义(exactly once semantics,下称EOS).Kafka的EOS主要体现在3个方面: 幂等producer:保证发送单 ...

  5. Kafka Streams | 流,实时处理和功能

    1.目标 在我们之前的Kafka教程中,我们讨论了Kafka中的ZooKeeper.今天,在这个Kafka Streams教程中,我们将学习Kafka中Streams的实际含义.此外,我们将看到Kaf ...

  6. Kafka处理请求的全流程分析

    大家好,我是 yes. 这是我的第三篇Kafka源码分析文章,前两篇讲了日志段的读写和二分算法在kafka索引上的应用 今天来讲讲 Kafka Broker端处理请求的全流程,剖析下底层的网络通信是如 ...

  7. Kafka资源汇总

    终于下定决心写一点普及类的东西.很多同学对Kafka的使用很感兴趣.如果你想参与到Kafka的项目开发中,很多资源是你必须要提前准备好的.本文罗列了一些常用的Kafka资源,希望对这些develope ...

  8. 【转】apache kafka技术分享系列(目录索引)

    转自:  http://blog.csdn.net/lizhitao/article/details/39499283   估计大神会不定期更新,所以还是访问这个链接看最新的目录list比较好 apa ...

  9. kafka的高可用和一致性探究

    一.kafka基础 本篇文章讨论的kafka版本是目前最新版 0.10.1.0. 1.1 kafka种的KafkaController 所有broker会通过ZooKeeper选举出一个作为Kafka ...

随机推荐

  1. day6常用模块,数据库操作

    一.循环调用函数    map() 二.列表推导式和生成器 三.filter过滤器 四.os模块 五.datetime模块 六.random模块 七.写日志,导入nnlog模块 八,发邮件 九,操作数 ...

  2. Redis开启AOF导致的删库事件

    事件背景 Redis主从开启AOF,错误操作导致数据被清空. Redis主要作用:缓存.队列. 事故过程 Redis搭建了主从,持久化方式为RDB,RDB没有定时备份,且AOF都没有开启. 考虑到开启 ...

  3. Vue(一)创建第一个Vue程序

    一.下载安装nodeJs 基于node.js,利用淘宝npm镜像安装相关依赖.由于国内使用npm会很慢,这里推荐使用淘宝NPM镜像 -- npm install -g cnpm --registry= ...

  4. python每日笔记

    9.28 查看python包路径: sys.path 9.4  sorted高级用法: >>> class Student: def __init__(self, name, gra ...

  5. JSAP106

    JSAP106 一.clientX.clientY 点击位置距离当前body可视区域的x,y坐标 二.pageX.pageY 对于整个页面来说,包括了被卷去的body部分的长度 三.screenX.s ...

  6. ASP.NET WebApi服务接口如何防止重复请求实现HTTP幂等性

    一.背景描述与课程介绍 明人不说暗话,跟着阿笨一起玩WebApi.在我们平时开发项目中可能会出现下面这些情况; 1).由于用户误操作,多次点击网页表单提交按钮.由于网速等原因造成页面卡顿,用户重复刷新 ...

  7. Linux之清理linux内存cache

    转自:https://www.cnblogs.com/madsnotes/articles/5740495.html 频繁的文件访问会导致系统的Cache使用量大增.例如:在使用grep从很多文件中搜 ...

  8. MySQL匹配指定字符串的查询

    MySQL匹配指定字符串的查询 使用正则表达式查询时,正则表达式可以匹配字符串.当表中的记录包含这个字符串时,就可以将该记录查询出来.如果指定多个字符串时,需要用“|”符号隔开,只要匹配这些字符串中的 ...

  9. js-将一个对象转换成一个新的对象

    /** * 对象转换成一个新的对象 * @param object * @private */ function _yh_tranformObject(object){ if(object == nu ...

  10. 获得最近一天的提交,并使用winscp上传到服务器

    @echo off D:\dev\Git\bin\git.exe pull origin master D:\dev\Git\bin\git.exe add -A D:\dev\Git\bin\git ...