1、分区机制的gao'高伸缩性
传统的消息系统有两个模块: 队列 和 发布-订阅。而kafka对消息的消费是基于组的。当仅有一个组时,就相当于队列,当有多个组,那就是发布-订阅。所以kafka中,队列和发布订阅的转换很简单,通过增加或减少组即可。所以kafka用一种统一的方式实现了队列和发布订阅。
kafka的实现,还有个巨大的好处,就是高伸缩性:一个topic中的一个分区,可以由群组中的一个consumer进行处理。所以可以通过增加分区和consumer,提高吞吐量。
2、不支持读写分离
具体查看kafka系列3--可靠性与运维这篇文章,看一下为何不支持读写分离能提高性能
3、Leader选举的gao不高性能:ISR
kafka使用ISR提高leader选举的性能
4、高效率的数据读写
kafka的数据以日志形式存储,所以可以采用磁盘线性读写,以及采用时间复杂度为O(1)的算法
5、基于消息块的协议
consumer每次获取一块信息,而不是一条,从而减少网络往返的开销。至于producer,应当也有批量信息发送的API
6、异步消费确认机制
broker无需等待消息被消费确认,而是让消费者提交偏移量,由此实现异步消费确认。异步消费确认和同步消费确认的性能相差很大,前者速度比后者快40倍,有人用mysql做过实验,同步确认能处理的请求约250/s,而用异步则能达到10000/s
7、异步数据发送
生产者有异步数据发送的功能
8、元数据
客户端可以直接发送数据到主分区的服务器上,不需要经过任何中间路由(对生产者来说,数据就是消息了;对消费者来说,发送数据就是提交偏移量)。
为了让生产者实现这个功能,所有的 kafka 服务器节点都能响应这样的元数据请求: 哪些服务器是活着的,主题的哪些分区是主分区,分配在哪个服务器上,这样生产者就能适当地直接发送它的请求到服务器上。而且客户端(生产者和消费者)也会把这些元数据缓存到本地。redis也有采用类似的做法
所有这些节点和客户端都需要时不时地通过发送元数据请求来自己缓存的元数据(刷新的时间间隔通过metadata.max .age.ms 参数来配置),从而知道元数据是否发生了变更
9、IO优化
前面我们讨论了磁盘性能。 一旦消除了磁盘访问模式不佳的情况,该类系统性能低下的主要原因就剩下了两个:大量的小型 I/O 操作,以及过多的字节拷贝。
解决大量小型IO的方案是使用批处理
解决过多的字节拷贝的方案是使用零拷贝技术
10、字节拷贝
现代的unix 操作系统提供了一个高度优化的编码方式,用于将数据从 pagecache 转移到 socket 网络连接中;在 Linux 中系统调用 sendfile 做到这一点。为了理解 sendfile 的意义,了解数据从文件到套接字的常见数据传输路径就非常重要:
操作系统从磁盘读取数据到内核空间的 pagecache
应用程序读取内核空间的数据到用户空间的缓冲区
应用程序将数据(用户空间的缓冲区)写回内核空间到套接字缓冲区(内核空间)
操作系统将数据从套接字缓冲区(内核空间)复制到通过网络发送的 NIC 缓冲区
这显然是低效的,有四次 copy 操作和两次系统调用。使用 sendfile 方法,可以允许操作系统将数据从 pagecache 直接发送到网络,这样避免重新复制数据。所以这种优化方式,只需要最后一步的copy操作,将数据复制到 NIC 缓冲区。
一个 topic 被多消费者消费,使用 zero-copy(零拷贝)优化,数据在使用时只会被复制到 pagecache 中一次,节省了每次拷贝到用户空间内存中,再从用户空间进行读取的消耗。这使得消息能够以接近网络连接速度的上限进行消费。
pagecache 和 sendfile 的组合使用意味着,在一个kafka集群中,大多数 consumer 消费时,您将看不到磁盘上的读取活动,因为数据将完全由缓存提供。
更多零拷贝资料,参考:
https://developer.ibm.com/articles/j-zerocopy/
producer ,broker 和 consumer 都共享的标准化的二进制消息格式,这样数据块不用修改就能在他们之间传递
11、数据压缩,节约带宽,批处理
为提高性能,优先考虑使用批处理操作。比如要发送N个消息,优先考虑把这N个消息打包到一个请求
Kafka 以高效的批处理格式支持一批消息可以压缩在一起发送到服务器。这批消息将以压缩格式写入,并且在日志中保持压缩,只会在 consumer 消费时解压缩。
Kafka 支持 GZIP,Snappy 和 LZ4 压缩协议,更多有关压缩的资料参看这里:https://cwiki.apache.org/confluence/display/KAFKA/Compression