Kafka本身是一个高吞吐量的消息容器,而它最大的特点就是会把消息持久化成日志,自然它也可以支持集群,在分布式系统中适当的数据冗余是可以保证系统的高可用。所以适当的了解Kafka一些集群概念是很重要的,使用不当甚至会导致消息丢失。
其实就是集群中的第一个节点,之所以叫集群控制器是因为后续所有的选举以及对节点的监控都是这个节点操作,创建和监控都是基于Zookeeper的特性,创建一个临时节点/controller
,通过这个临时节点保证集群控制器只有一个,很多场景用Zookeeper作为锁也是这个原理。
分区其实在前面讲了,就是将一个主题中的消息分为很多块,持久化到不同的日志上,这也是为了提高性能,因为日志是追加写的方式,整个主题写一个日志和写十个日志肯定是后者效率高。
所以数据冗余其实就是分区的持久化日志进行冗余,前面也说过了Kafka的分区副本只有一个能读写而被称为主副本,剩下的只能当做备份副本,除非主副本宕机了才会选一个新的主副本出来。
所以Kafka集群一般是尽量把每个分区的副本分配在不同的节点上,即使一个节点挂了,其它的节点照样可以成为主副本,当然这种角色的转换就依赖上面的集群控制器来操作了。副本的数量通过复制系数来设置。
正因为一个节点上面会有各种主题的各种分区,比如有3个节点,3个主题,每个主题3个副本,那可能A节点上是有主题a的分区0,主题的b的分区2,主题c的分区1。假设A节点挂了,而主题a的分区0是一个主副本,那主题a这个时候就要再选出一个主副本了,不然主题a是不可用的。
这就牵扯到一个问题,假如剩下的两个副本数据和主副本不同步怎么办?这是有可能的,比如其它副本所在的节点宕机了,然后丢失宕机期间的的数据,现在主副本也宕机了,它们又恢复了,这个时候有两种选择,第一种是不同步的副本也可以让它成为主副本,这有个术语叫做不完全的首领选举,会造成消息丢失,反之则是完全首领选举,但是会影响Kafka集群的高0可用。所以有unclean.leader.election.enable
参数控制,是否允许不同本的副本也可以成为主副本,为true
就是允许,这就是AP和CP之间的取舍了,如果是银行金融数据肯定是选择CP,如果是不重要的日志则选择AP。
由 min.insync.replicas
参数设置,作用是必须要超过指定数量的同步副本才可以继续写入消息,比如3个副本,宕机1个,设置的参数为2,此时就可以写入,宕机两个时就会提示NotEnoughReplicasException
异常,所以这也是AP和CP的取舍,看场景是需要冗余数据还是高流量。
Kafka生产者发送消息是会接收到一个确认消息的。不过它有3种确认机制,可靠性依次提高,效率当然也是一次下降。
- acks=0,不管收没收到,发出去就算成功
- acks=1,主副本所在的节点收到消息就算成功
- acks=2,所有副本都收到消息才算成功。
下面有一些情况看似完美无缺,实在是有潜在的问题,都是需要注意的。
-
生产者
一个有3个节点的集群,为一个主题配置3个副本,禁用不完全首领选举,生产者acks设置为1。此时可能主副本写入成功但是还没来得及通知其它副本就宕机了,因为还没来得及通知,所以其它的副本还被认为是同步副本,被选为主副本,消息丢了。
设置acks为all可以解决,但是如果生产者自己没有重试机制或者是丢弃了异常消息,本质上来说,消息也丢了。
当然这都是极端情况,不过这样说明需要根据场景配置Kafka和编写生产者的代码。
-
消费者
如果一个消费者没有处理完消息提交偏移量就会导致后面的消费者也读不到这个消息,加入消费者A处理偏移量30的消息,B处理偏移量31的消息,A失败了,B成功了,提交偏移量31,偏移量30的消息也丢了。
这种情况下就要适当的使用手动提交,将失败的消息缓存起来或者发送到新的主题进行消费。