Confluent联合创始人兼CEO Jay Kreps发表了一篇博文,给出了Kafka的真正定位——它不只是个消息系统,它还是个存储系统,而它的终极目标是要让流式处理成为现代企业的主流开发范式。以下内容翻译自作者的博文,查看原文It’s Okay To Store Data In Apache Kafka。
人们总是问是否可以把Kafka作为长期的数据存储来使用,很显然,如果把数据保留策略设置为“永久”或者启用主题的日志压缩功能,那么数据就可以被永久保存下来。但我觉得人们其实真正想知道的是,这样做是不是很疯狂。
简而言之,这样做不算疯狂。实际上,人们一直都在这么做,而且Kafka的设计意图之一就是要将它作为数据存储系统。不过问题是,为什么我们要把Kafka作为数据存储呢?
你可能在构建一个基于事件溯源的应用程序,需要一个数据存储来保存变更日志。理论上,你可以使用任何一种存储系统。Kafka已经解决了不可变(immutable)日志和基于这些日志生成“物化视图”的问题,既然这样,为什么不直接使用Kafka呢?纽约时报已经在他们的CMS系统里使用Kafka来保存他们的文章。
你可能在应用程序里使用了缓存,并从Kafka上获取数据来更新缓存。你可以将Kafka的主题设置为压缩型日志,应用程序每次在重启时就可以从零偏移量位置重新刷新缓存。
你的流式作业数据流来自Kafka,在流式作业的逻辑发生变更后,需要重新计算结果。最简单的办法就是将偏移量重置为零,让新代码重新计算结果。
Kafka经常被用于捕获和分发数据库的变更事件(通常被称为CDC,Change Data Capture)。应用程序可能只需要最新的数据库变更,但却要处理完整的数据快照,而这是相当耗时的操作。如果启用主题的日志压缩功能,就可以让应用程序直接从零偏移量位置重新加载数据。
像这样在Kafka里存储数据并不是什么疯狂事,Kafka本来就是设计用来存储数据的。数据经过校验后被持久化在磁盘上,并通过复制副本提升容错能力。再多的数据都不会拖慢Kafka,在生产环境中,有些Kafka集群甚至已经保存超过1 TB的数据。
那么人们为什么会对使用Kafka来存储数据心存疑问呢?
我想,人们更多的是把Kafka当成了消息队列系统。消息队列有一些不成文的规则,比如“不要在消息队列里保存消息”。传统的消息系统之所以不能用来保存消息,是因为:
消息被读取后就会被删除
伸缩性差
缺乏健壮的复制机制(如果broker崩溃,数据也就丢失了)
传统的消息系统在设计上存在很多不足。从根本上讲,任何一个异步消息系统都会保存消息,只是时间很短,有时候只有几秒钟,直到消息被消费为止。假设有一个服务向消息队列发送消息,并希望有一种机制可以保证其他服务能够收到这个消息,那么消息就需要被保存在某个地方,直到其他服务读取它。如果消息系统不擅长存储消息,也就谈不上给消息“排队”了。你可能觉得无所谓,因为你并不打算长时间地保留消息。但不管怎样,如果消息系统持续地处理负载,总会有一些未被消费的消息需要保存下来。一旦消息系统发生崩溃,如果没有有效的容错存储机制,数据就会丢失。消息存储是消息系统的基础,但人们总是忽略这一点。
实际上,Kafka并非传统意义上的消息队列,它与RabbitMQ等消息系统并不一样。它更像是一个分布式的文件系统或数据库。Kafka与传统消息系统之间有三个关键区别。
Kafka持久化日志,这些日志可以被重复读取和无限期保留
Kafka是一个分布式系统:它以集群的方式运行,可以灵活伸缩,在内部通过复制数据提升容错能力和高可用性
Kafka支持实时的流式处理
以上三点足以将Kafka与传统的消息队列区别开,我们甚至可以把它看成是流式处理平台。
我们可以这样来看待消息系统、存储系统和Kafka之间的关系。消息系统传播的是“未来”的消息:你连接到broker上,并等待新消息的到来。存储系统保存的是过去写入的数据:你查询或读取的结果是基于过去所做的更新。而流式处理可以把这二者结合起来,既可以处理过去的数据,也可以处理未来的消息。这也就是为什么Kafka的核心就是一个持续的、基于时间排序的日志。它是一种结构化的“文件”,而且从逻辑上看,它没有终点,会一直持续下去。应用程序不需要区分已有的旧数据和即将生成的新数据,它们都存在于一条持续的流中。Kafka提供了统一的协议和API来保存过去的数据和传播未来的消息,Kafka因此成为一种非常好的流式处理平台。