22.神说:Kafka其实是个数据库
1 楔子
中国人都知道,自古马家出神人。在互联网领域,凡是姓马的,必须要礼让三分,什么马云、马化腾、马斯克。而Martin Kleppmann就是分布式系统领域的活着的神人,最近一直看他的书。。。主要是为了陶冶情操。
上周看了他在Kafka Summit 2018上的一场演讲《Is Kafka a Database》,介绍了怎么把Kafka当作数据库使用的一些探索。
Kafka一直是MQ领域的事实标准,但我还是头一次听说Kafka的隐藏身份竟然是数据库,难道我家MySQL要失宠了嘛?吓得我赶紧搬来小板凳,摆好姿势。
Martin从AICD的角度讲述怎么使用Kafka,观点比较有趣,不少想法值得进一步探讨:
2 Atomicty
原子性的核心是容错,当发生错误(宕机、崩溃、断网)时,保证事务中多个写操作要么全部生效要么全部回滚。在单机时代,通常使用undo log以回滚未提交操作的方式来保证事务原子性。
然而,如果涉及到分布式事务呢?比如用户在一次操作中想同时更新DB, Cache和Index中的数据,该如何保证分布式事务的原子性呢?我们以前聊过两阶段提交《19.分布式事务之2PC:两阶段结婚》,但2PC的性能和可靠性实际上是比较感人的。
事件流(event stream)提供了一种新的思路。以Kafka为例,应用server将操作以事件的方式追加log到消息队列中,待修改的DB, Cache和Index分别在不同的消费组内消费相同的event log。如果在消费过程中,其中某一个进程crash了,则等待进程重启后,从最后一次消费的offset处继续消费就可以了。
跟单机的undo方式不同,这里通过redo的方式来达到多对象事务一致性的目的,同样满足原子性要求。
3 Consistency
一致性的核心是约束,保持数据满足逻辑一致性。这个特性在ACID中是打酱油的,连正经的数据库也没有正经对待的,全靠程序员撑着,所以不聊也罢,就当Kafka实现了。
4 Isolation
隔离性的核心是并发,单机事务通过定义隔离级别,来平衡高并发与隔离性。Kafka使用分区解决并发问题:单分区内严格按先后顺序处理,不同分区之间则互不干扰,就像结婚多年的夫妻一样,坐在床头各看各的手机。同一个分区内,同一时刻只允许单个线程消费,因此,在恰当使用的前提下,Kafak可以做到最高级别的隔离性:Serializable(可串行化)。
以注册唯一名为例。假定有两个玩家都想在Touch游戏中注册名字为jane,应用server以jane为partition key将消息投递到kafka的同一个分区中,这样同一个分区内的两条消息无论如何都会有一个先后顺序。排在前面的消息会处理成功,插入到数据库中,而排在后面的消息会处理失败,因为它会发现数据库中已经存在一条名字为jane的数据了。
Touch是多年前我参与研制的一款舞蹈游戏,那时候我还有颜值
同样的例子,在DB的流程中,Martin使用Serializable隔离级别来衬托Kafka事务的优越性。对于这一点,我是不太认同的,因为我们可以使用相对较低的隔离级别(比如RC),配合unique index,然后在事务开始的时候执行insert into user(name) values('jane')
,减少锁的粒度,从而获得比Searializable隔离级别高得多的并发性。
但即便如此,这仍然是一件非常amazing的事情,因为Kafka的分区是天然多线程+无锁的,甚至也不需要DB配合创建unique index以确保唯一性,这可以极大提高事务的并发能力,让应用可以在事务前期就可以通过无锁的plain select做一些预判之类的事情,同时几乎不消耗DB性能。
5 Durability
持久性的核心是数据安全。单机时代,DB通过WAL落盘的方式实现持久性;分布式时代,集群通过副本的方式实现持久性。
Kafka的ISR方式,可以兼顾集群高性能与高可用的目标。其持久能力一直有口皆碑,用过的都直呼好棒。
MySQL集群通常使用一主二从三副本的方式达到类似的目标。
6 等等,还不到抛弃MySQL的时候
在中国传统文化里,愚公是能移山的,精卫是能填海的,曹冲是能称象的,男人是靠不住的。。。但这些都是个别现象。
说出来你们可能不信,愚公和精卫其实偷偷合作多年
虽然Kafka在一些方面做的还不错,但还远未到完全代替关系型DB的时候,比如实时在线查询方面,Kafka就不是MySQL的一合之敌。这么看的话,MySQL老是老了一点儿,但老夫老妻嘛,在一起这么多年了,知根知底的,还不到抛弃的时候。。。想啥呢?我可是坚定的一夫一妻制支持者,我上网学习的时候,连美女照片都从来不看,像什么苍井空,武藤兰,小泽玛利亚我一个也不认识。
7 再稍等一下
客官,才艺都展示完了,你好歹点个赞再走嘛?