最近思路有些枯竭,找些务虚的话题来凑。本文内容完全来自于Martin Kelppmann在2019年Kafka伦敦峰会上的演讲。顺便提一句,Kelppmann是《Designing Data-Intensive Applications》的作者。提起DDIA的大名想必各位应该是有所耳闻的。

Apache Kafka是数据库吗?你可能会觉得奇怪,Kafka怎么可能是数据库呢?它没有schema,也没有表,更没有索引。它仅仅是生产消息流、消费消息流而已。从这个角度来说Kafka的确不像数据库,至少不像我们熟知的关系型数据库。那么到底什么是数据库呢?或者说什么特性使得一个系统可以被称为数据库?经典的教科书是这么说的:数据库是提供 ACID 特性的,即atomicity、consistency、isolation和durability。好了,现在问题演变成了Apache Kafka支持ACID吗?如果它支持,Kafka又是怎么支持的呢?要回答这些问题,我们依次讨论下ACID。

1、持久性(durability)

我们先从最容易的持久性开始说起,因为持久性最容易理解。在80年代持久性指的是把数据写入到磁带中,这是一种很古老的存储设备,现在应该已经绝迹了。目前实现持久性更常见的做法是将数据写入到物理磁盘上,而这也只能实现单机的持久性。当演进到分布式系统时代后,持久性指的是将数据通过备份机制拷贝到多台机器的磁盘上。很多数据库厂商都有自己的分布式系统解决方案,如GreenPlum和Oracle RAC。它们都提供了这种多机备份的持久性。和它们类似,Apache Kafka天然也是支持这种持久性的,它提供的副本机制在实现原理上几乎和数据库厂商的方案是一样的。

2、原子性(atomicity)

数据库中的原子性和多线程领域内的原子性不是一回事。我们知道在Java中有AtomicInteger这样的类能够提供线程安全的整数操作服务,这里的atomicity关心的是在多个线程并发的情况下如何保证正确性的问题。而在数据库领域,原子性关心的是如何应对错误或异常情况,特别是对于事务的处理。如果服务发生故障,之前提交的事务要保证已经持久化,而当前运行的事务要终止(abort),它执行的所有操作都要回滚,最终的状态就好像该事务从未运行过那样。举个实际的例子,比如下面这张图:

在异质分布式系统中一个比较经典的问题就是如何确保不同系统之间的数据同步。比如这个图中如何确保数据库、缓存和搜索索引之间的数据一致性就是一个关于原子性的问题:app写入数据库的写更新如何同步到cache和Index中,更关键的是如何确保这些写更新与之前写数据库是原子性的,要么它们全部写入成功,要么全部写入失败。我之前在知乎上也回答过一个类似的帖子,是关于“如何保持mysql和redis中数据一致性”的。令人意外地收获了近100个赞,感觉比我回答10个Kafka问题得到的赞还要多,这也足见这种一致性问题是多么地受欢迎。

显然,要实现这种分布式场景下的数据一致性并不容易。一个典型的异常场景就是当发生cache写入成功,而Index写入失败时,应用程序应该如何处理?如下图所示:

让app重试似乎是一个可行的选择,但重试的频率该怎么设定呢?更要命的是,如果因为网络的问题使得Index其实写入成功,但response返回失败,此时app重试有可能发生重复生产数据的问题,这还需要Index端有数据去重的能力。如果是撤销数据库和cache之前的写入呢? 如下图所示:

似乎这个方法也是可行的,但这就有了linearizability的问题了:即用户在某个时刻T看到了这个写入带来的新值,但在之后的某个时刻T1该值又变回了之前的老值,这必然造成用户的困扰,因此也不是一个好办法。

实际上,解决这个问题的常见做法是采用两阶段提交(2PC)这样分布式事务。不过2PC是出了名的慢,而且存在单点故障的隐患(coordinator),更重要的是它要求所有系统都要支持XA,但像Redis和ElasticSearch这样的系统本质上是不支持XA的,因此也就不能使用2PC来保证原子性。

第三个方法是采用基于日志结构的消息队列来实现,比如使用Kafka来做,如下图所示:

在这个架构中app仅仅是向Kafka写入消息,而下面的数据库、cache和index作为独立的consumer消费这个日志——Kafka分区的顺序性保证了app端更新操作的顺序性。如果某个consumer消费速度慢于其他consumer也没关系,毕竟消息依然在Kafka中保存着。总而言之,有了Kafka所有的异质系统都能以相同的顺序应用app端的更新操作,从而实现了数据的最终一致性。这种方法有个专属的名字,叫capture data change,也称CDC。

3、隔离性(isolation)

在传统的关系型数据库中最强的隔离级别通常是指serializability,国内一般翻译成可串行化或串行化。表达的思想就是连接数据库的每个客户端在执行各自的事务时数据库会给它们一个假象:仿佛每个客户端的事务都顺序执行的,即执行完一个事务之后再开始执行下一个事务。其实数据库端同时会处理多个事务,但serializability保证了它们就像单独执行一样。举个例子,在一个论坛系统中,每个新用户都需要注册一个唯一的用户名。一个简单的app实现逻辑大概是这样的:

1) 首先,发起SQL查询:select count(*) from user_accounts where username = 'jane',查看是否存在名为jane的用户;

2. 如果返回0, 则执行 insert into user_accounts(username, ...) values("janes", ...) 注册用户

显然存在某个特殊的时刻,使得两个新用户同时发现某个用户名可用,从而最终注册了相同的用户名,如下图所示:

这种就不是serializability级别的隔离,如果要实现这种唯一性,你就需要提高数据库的隔离级别到serializability。针对这个需求,我们可以使用Kafka来帮助实现吗?当然是可以的!如下图所示:

如果把用户名作为key,那么显然请求同一个用户名的用户必然访问Kafka主题的同一个分区上,此时根据Kafka分区消息写入前后顺序来确定谁先谁后就是一个自然的选择。数据库读取Kafka分区中的注册消息,发现红色标识的用户最先写入了key=jane的消息,那么当它再次读到key=jane的消息时就能明确拒绝绿色用户发起的请求,因为jane用户名已经被注册了。当然要实现这一整套的流程,你需要的不仅是Kafka,更要是一套相应的流处理管道,比如使用Kafka Streams。但无论如何,Kafka可以被用来实现这种事务的隔离性。依托Kafka的好处在于它不仅实现了serializability,而且依靠Kafka的分区机制,它能处理多个不同的用户名注册,因而也实现了scalability。

4、一致性(consistency)

最后说说一致性。按照Kelppmann大神的原话,这是一个很奇怪的属性:在所有ACID特性中,其他三项特性的确属于数据库层面需要实现或保证的,但只有一致性是由用户来保证的。严格来说,它不属于数据库的特性,而应该属于使用数据库的一种方式。坦率说第一次听到这句话时我本人还是有点震惊的,因为从没有往这个方面考虑过,但仔细想想还真是这么回事。比如刚才的注册用户名的例子中我们要求每个用户名是唯一的。这种一致性约束是由我们用户做出的,而不是数据库本身。数据库本身并不关心或并不知道用户名是否应该是唯一的。针对Kafka而言,这种一致性又意味着什么呢?Kelppmann没有具体展开,但我个人认为他应该指的是linearizability、消息顺序之间的一致性以及分布式事务。幸运的是,Kafka的备份机制实现了linearizability和total order broadcast,而且在Kafka 0.11开始也支持分布式事务了。

至此,我们说完了经典数据库中的ACID特性以及在Kafka中是如何支持它们的。现在你觉得Kafka是数据库了吗:) 这是个开放的问题,我们可以一起讨论下~~

转载于:https://www.cnblogs.com/huxi2b/p/10883121.html

Apache Kafka是数据库吗?相关推荐

  1. Spring Boot 和Apache Kafka的集成

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 1. 引言 Apache Kafka 是一个分布式的.容错 ...

  2. Apache Kafka:大数据的实时处理时代

    在过去几年,对于 Apache Kafka 的使用范畴已经远不仅是分布式的消息系统:我们可以将每一次用户点击,每一个数据库更改,每一条日志的生成,都转化成实时的结构化数据流,更早的存储和分析它们,并从 ...

  3. 重磅开源 KSQL:用于 Apache Kafka 的流数据 SQL 引擎 2017.8.29

    Kafka 的作者 Neha Narkhede 在 Confluent 上发表了一篇博文,介绍了Kafka 新引入的KSQL 引擎--一个基于流的SQL.推出KSQL 是为了降低流式处理的门槛,为处理 ...

  4. 基于事件驱动架构构建微服务第13部分:使用来自Apache KAFKA的事件并将投影流传输到ElasticSearch...

    原文链接:https://logcorner.com/building-microservices-through-event-driven-architecture-part13-read-mode ...

  5. 基于事件驱动架构构建微服务第12部分:向Apache KAFKA生成事件

    原文链接:https://logcorner.com/building-microservices-through-event-driven-architecture-part12-produce-e ...

  6. kafka处理流式数据_通过Apache Kafka集成流式传输大数据

    kafka处理流式数据 从实时过滤和处理大量数据,到将日志数据和度量数据记录到不同来源的集中处理程序中,Apache Kafka越来越多地集成到各种系统和解决方案中. 使用CData Sync ,可以 ...

  7. 通过Apache Kafka集成流式传输大数据

    从实时实时过滤和处理大量数据,到将日志数据和度量数据记录到不同来源的集中处理程序中,Apache Kafka日益集成到各种系统和解决方案中. 使用CData Sync ,可以轻松地将此类解决方案应用于 ...

  8. Apache Kafka / Spark流系统的性能调优

    电信行业的实际案例研究 调试实际的分布式应用程序可能是一项艰巨的任务. 至少在一开始,最常见的Google搜索并没有什么用. 在这篇博客文章中,我将详细介绍如何将Apache Kafka / Spar ...

  9. 饶军:Apache Kafka的过去,现在,和未来

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文首发在云+社区,未经许可,不得转载. 大家好,我大概简单的介绍一下,我叫饶军,我是硅谷的初创公司Confluent的联合创始人之一,我们公 ...

最新文章

  1. 一笔画 (25 分)
  2. pandas object转float_数据分析篇 | Pandas基础用法6【完结篇】
  3. iOS 获取app进程被杀死事件applicationWillTerminate
  4. WebConfig的经典使用,大家一起交流一下吧!!!
  5. 模式识别Pattern Recognition和机器学习Machine Learning资源
  6. 2020.NET开发者大会大会线上同步直播,以及参会秘籍
  7. And Then There Was One POJ - 3517(变形约瑟夫环+规律)
  8. java 正则表达式使用_如何用正则表达式杀死Java
  9. 程序员面试题 php_程序员面试必备PHP基础面试题 – 第十五天
  10. .与localhost与 .\sqlexpress的区别
  11. java mvc demo_SpringMvcDemo 一个简单的 mvc 的 实现例子 Java Develop 259万源代码下载- www.pudn.com...
  12. ubuntu添加桌面快捷方式图标
  13. Learn Python The Hard Way (python 2.7) ex45.py 你来制作一个游戏
  14. Try tracing
  15. 《剑魂之刃》游戏破解
  16. 2022-2028全球抗氧剂1425行业调研及趋势分析报告
  17. 计算机刻录机无法显示,电脑不识别刻录机是为什么
  18. 机器学习中如何处理非数值型的特征
  19. 两个日期月数差值计算
  20. 工具包-POST请求

热门文章

  1. APP开放源码第一弹《纳豆》
  2. [万字长文]使用 React 重写学成在线前端项目 I 代码完整可运行,步骤有详解
  3. 状态标志与状态标志寄存器
  4. cf1326 E. Bombs
  5. Integer、new Integer()和int的区分与比较
  6. Loadrunner安装破解
  7. 深圳市文化创意产业百强(2011-2012)公示
  8. Android 集成环信IM,实现头像和昵称的显示
  9. 改进的LCS算法的应用
  10. Android实现简单的计算器功能