最近项目开始使用kafka作为消息中间件,理由是支持更高的吞吐量和轻量级(相对传统的mq,如rabbit)。
与rabbitmq的不同
重broker与重consumer
kafka跟rabbit的设计上有很多不同,rabbit上存在exchange、queue以及两者binding,生产者根据需要需要发送给不同类型exchange,经exchange的绑定关系路由到特定的queue上,然后由消费者在指定的queue上消费消息,整个流程由rabbit进行分配,因此是重broker的。而kafka是重视consumer,消费哪种消息由客户端自己控制,broker上只是简单的存储下消息体。kafka通过客户端自己记录下的offset在每个队列(实际是分区partition)中的读取的最后一个索引,下次读取则在当前的offset上做文章。
消息持久化
kafka和rabbit都支持消息的持久化,但是两者说的不是一回事。rabbit是将开启了持久化的队列保存到磁盘中,以便宕机后能恢复到队列中。rabbit的消息由消费者消费后手动或者自动应答ask,rabbit才将消息从队列中删除,而这个点,也是跟kafka一个很大不同的地方。在kafka上,消息被消费者消费后,不会从队列中删除,而是继续保存在队列中,当然这个会有一个过期时间。因此可以将kafka当成一个日志管理系统,这样做还有个优点,消费者可以重新消费历史记录(利用上述的offset)。
综合以上,一般在互联网的应用上,kafka可能会更受青睐,因为不需要实现像rabbit这样笨重的协议AMQP,更加轻量级;还有着更高的吞吐量,rabbit默认的吞吐量上限是10W,大于这个数运维就拒绝消息了。而kafka远不止这个数字。但是如果应用上的消息需要支持事务型,不能丢消息的场景下,使用rabbit会更适合,比如营收系统,少一条都是一次纠纷。同时rabbit还有如延迟队列等优点。
kafka分区partition、topic、replication
之前一直对于kafka的分区不是很理解,其实我觉得叫分片可能更适合,对于有学习过一些nosql的同学可能更容易对号上座。kafka将所有数据进行分片,所以每个分片上的数据都是不同,所有分片上的消息合在一起就是整个topic的消息。而replication针对的粒度,也是一个partition。所以当看到topic的配置信息为partition=10,replication=2的时候,理论上该topic上的partition的消息就是10*2。
刚学习kafka的时候还有一个疑惑,官网的例子中使用了三个broker节点,同时replication也是3个,于是一股脑认为broker的个数(一般为机器)就是replication的数量,因为这样每个broker就会有在另外两台机器是上有个备份。但是自从看了下面这张图后,就打破了原有的认知。会产生这种错误的分歧,主要是没理解好分片partition的概念,replication的粒度是partition,而不是一台机器!
消费组
当一个partition有多个消费者的时候,这个时候消息是被其中一个消费了,还是广播给所有消费者呢?下面这张图是最好的答案。如果消费者是在不同的消费组consumer group中,那么每个消费者都会收到广播。如果都在同一个消费组中(即消费组的名字一样),那么只会在消费组中的任一个消费者消费,这可以用作负载均衡。当然可以同时支持上述两种情况,如图所示。图中consumer groupB有四个消费者,刚好有四个分区,从负载去看,每个消费者消费一个partition刚刚好,但是假如C3挂了,那p0将有哪个消费呢,根据负载,将随机在C4、C5、C6中选择一个。这里就涉及到消费组中客户端的数量和分区大小的关系了。