背景
工作中日日在扮演CRUD boy的角色,少有机会去实践高性能,高并发,高可用之地。所以突发奇想,能否通过解读业内如雷贯耳,但又经常接触到的开源中间件redis,kafka 等,去反推这里面的高性能,高并发,高可用的流程和设计,以及这里面的技术抉择的思想。
kafka 高性能和高并发的文章见
kafka 数据高可靠的文章见
中间件 高可用的概念模型见
kafka为什么需要去做高可用?
大概有两点
硬件故障常态化
当集群规模上升到一定程度后,一台或者多台机器出现宕机或者物理故障,而不能继续提供服务,是一个常态。
在这种故障常态性的情况下;上层软件层面 势必需要一套failover机制,来保证中间件服务的持续和高可用的稳定运行。翻译成人话就是 机器多了,机器出故障的概率就高了,可能这种出故障的概率已经和软件自身的bug一样多了,不得不去解决这种问题了。(让我想到了某IT大神说的,万恶的硬件故障,很多硬件人员不去解决或者兼容硬件的问题,他们只会把问题和矛盾转移到上层,由软件层面来兜底底层的硬件故障)
数据丢失风险
在0.8版本之前,kafka是不提供高可用机制的;某个broker所在机器宕机后,如果服务不能恢复,那么在broker上面的消息数据就丢失了。数据丢失的问题,倒逼kafka 必须提供服务高可用。
比如你的订单消费服务正在消费订单数据,突然kafka集群中某台机器的硬盘坏了,导致在这上面的分区订单消息丢失了,此时的你还敢用kafka吗?
kafka 是如何实现高可用的
借用上篇文章《中间件是如何做到高可用的(上)》 分析一般中间件高可用的解决方法可知: 实现高可用关键流程
- 冗余
- 故障检测
- 切主
- 外部通知
高可用里涉及到的设计点和详细流程可参见这位大佬的总结,此处不详讲了:www.jasongj.com/2015/04/24/...
既然分区提供了冗余,kafka 为什么不提供读写分离?
常用中间件redis,mysql,都可以提供读写分离模式;即主提供写,从提供读,以此来充分的使用机器的资源;并且也是提高系统处理性能的法宝之一。但是为什么kafka也有主从类似的模式,却不提供读写分离了?比如生产者往leader分区写入消息;消费者从其它follower分区读取消息了? **大概有如下几个原因 **
消息的消费并不是单纯的读
消息的消费看起来是一个单纯的读数据的操作,但其实包含了写操作。比如我们消费消息时的代码模式如下:
java
while(true){
consumer.poll(); #①拉取消息
XXX #②处理消息;
consumer.commit();
}
在消费完消息时,一般会手动commit;而这个commit动作,其实是告诉broker端,记录该topic分区上已成功消费消息的位置。这是个写入操作。
主从数据同步的简单性
假设kafka支持了读写分离,即生产端写入消息到leader分区,消费端从follower分区读取消息,并提交位移到follower分区;此时会发现本来follower只需要单纯的从leader拉数据进行处理的单向过程,变的非常复杂。
因为follower保存了分区消息的位置,那么这一数据必须要同步给leader分区,或者其它的follower分区。一个分区的数据同步链路变成了n*n;大大增加了leader和follower间数据同步的复杂性,并且这个同步逻辑还更容易出错。 而单向的同步逻辑,只需要leader保证写入数据的顺序性;follower单向从leader拉取数据即可。
单向数据同步过程
n*n 数据同步过程
消息消费的及时性
如果kafka提供了读写分离,并且规避了n*n的同步过程,和不单纯的读过程 (生产端写入消息到leader分区,消费端从follower分区读取消息,消息成功消费的位移在保存到leader分区)是不是提供读写分离就没啥问题了?
貌似看起来没啥大问题。
但是我们知道使用读写分离,读到的数据,是有一定的延迟的,这是读写分离方案固有的一个缺陷吧。相比较主节点提供写和读的服务,如果写主读从,读势必会存在一定的延迟,而这种延迟取决于主从同步之间的延迟。
总结
kafka 实现高可用的原因:硬件故障常态化和为了解决数据丢失的风险
kafka 实现高可用的核心思想:冗余,故障检测,切主,外部通知
kafka 为什么不提供读写分离:消息的消费并不是单纯的读,主从同步功能的简单性,消息消费的及时性
参考资料:
kafka.apache.org/0102/docume... kafka.apache.org/0102/docume... kafka.apache.org/0102/docume... www.jasongj.com/2015/04/24/...