总结:
消息队列的性能好坏,其文件存储机制设计是衡量一个消息队列服务技术水平和最关键指标之一。
特性:
高吞吐量、低延迟
可扩展性
持久性,容错性,高并发
设计思想
Zookeeper Kafka Broker Kafka Broker Controller Producer Consumer
consumer && partition
partition 中的每个message只能被consumer group中的一个consumer thread消费。
也可以被其他组中的consumer thread消费。不能一个consumer group的多个consumer thread同时消费一个partition。
对一个topic做多次消费的话,可以启动多个consumer group。
topic里面有多个少个partition,consumer group下面的所有consumer thread一定会消费全部partition因此,最优的设计就是,consumer group下的consumer thread的数量等于partition数量。
当partation>consumer thread 会出现1个consumer thread消费多个partation。
当partation<consumer thread 会出现consumer thread空闲。
Consumer处理partition里面的message的时候是顺序读取的,所以必须维护着上一次读到哪里的offsite信息。high level API,offset存于Zookeeper中,low level API的offset由自己维护。
默认是读完message先commmit(offsite+1)再处理message,auto commit默认是true,一旦处理失败,offsite已经+1,这个时候就会丢message;也可以配置成读完消息处理再commit,这种情况下consumer端的响应就会比较慢(因为期间需要等待处理完成后才可以继续)。
所以线上的分布式多个service服务,每个service里面的kafka consumer数量都小于对应的topic的partition数量,但是所有服务的consumer数量只和等于partition的数量,这是因为分布式service服务的所有consumer都来自一个consumer group,一般这种情况都是两个不同的业务逻辑,才会启动两个consumer group来处理一个topic)。
如果producer的流量增大,当前的topic的parition数量=consumer数量,这时候的应对方式就是很想扩展:增加topic下的partition,同时增加这个consumer group下的consumer。
新添加的partition的时候,原来partition里面的message不会重新进行分配,再新进来的producer的message重新load balance 加入到新的partition.
Partition Replic:每个partition可以在其他的kafka broker节点上存副本,以便某个kafka broker节点宕机不会影响这个kafka集群。(replica副本数目不能大于kafka broker节点的数目,否则报错。)这样如果某个broker宕机,其实整个kafka内数据依然是完整的。但是,replica副本数越高,系统虽然越稳定,但是回来带资源和性能上的下降;replica副本少的话,也会造成系统丢数据的风险。
消息在broker上的可靠性,因为消息会持久化到磁盘上,所以如果正常stop一个broker,其上的数据不会丢失;但是如果不正常stop,可能会使存在页面缓存来不及写入磁盘的消息丢失,
message有效期:Kafka会长久保留其中的消息,以便consumer可以多次消费,当然其中很多细节是可配置的。
push-and-pull : Kafka中的Producer和consumer采用的是push-and-pull模式,即Producer只管向broker push消息,consumer只管从broker pull消息,两者对消息的生产和消费是异步的。
Kafka集群中broker之间的关系:不是主从关系,各个broker在集群中地位一样,我们可以随意的增加或删除任何一个broker节点。
Kafka文件存储机制
一个Kafka将会管理成千上万的topic分区.Kafka尽量的使所有Partition 均匀的分布到集群所有的节点上而不是集中在某些节点上,
对于某个分区来说,保存正分区的"broker"为该分区的"leader",保存备份分区的"broker"为该分区的"follower"。备份分区会完全复制正分区的消息,包括消息的编号等附加属性值。
Kafka中的topic是以partition的形式存放的,每一个topic都可以设置它的partition数量。
kafka需要为每个partition分配一些内存来缓存消息数据,如果partition数量越大,就要为kafka分配更大的heap space。
Kafka判断一个节点是否活着有两个条件:
1. 节点必须可以维护和ZooKeeper的连接,Zookeeper通过心跳机制检查每个节点的连接。
2. 如果节点是个follower,他必须能及时的同步leader的写操作,延时不能太久。
partition && segment
每个partion(目录)相当于一个巨型文件被平均分配到多个大小相等segment(段)数据文件中。但每个段segment file消息数量不一定相等,这种特性方便old segment file快速被删除。每个partiton只需要支持顺序读写就行了,segment文件生命周期由服务端配置参数决定。
segment
segment file组成:由2大部分组成,分别为index file和data file,此2个文件一一对应,成对出现,后缀".index"和“.log”分别表示为segment索引文件、数据文件.每个segment中存储很多条消息,消息id由其逻辑位置决定,即从消息id可直接定位到消息的存储位置,避免id到位置的额外映射。
segment index file采取稀疏索引存储方式(比稠密索引节省了更多的存储空间),它减少索引文件大小,但查找起来需要消耗更多的时间。
partition通过offset查找message
第一步 查找segment file(offset头值)
第二步 在segment file中查找offset
整个流程
producer发message到某个topic,message会被均匀的分布到多个partition上(随机或根据用户指定的回调函数进行分布),kafka broker收到的message往对应partition的最后一个segment上添加该消息,当某个segment上的消息条数达到配置值或消息发布时间超过阈值时,segment上的消息会被flush到磁盘,只有flush到磁盘上的消息consumer才能消费,segment达到一定的大小后将不会再往该segment写数据,broker会创建新的segment。
注意说明:
kafka不是严格的JMS, 因此kafka对消息的重复、丢失、错误以及顺序型没有严格的要求。(这是与AMQ最大的区别)
Kafka为每条消息为每条消息计算CRC校验,用于错误检测,crc校验不通过的消息会直接被丢弃掉。
Kafka支持以集合(batch)为单位发送消息,在此基础上,Kafka还支持对消息集合进行压缩。