数据赋予了世界力量。我们每秒获取大量信息,我们对其进行清理,分析并创建更有价值的输出,无论是日志文件,用户活动,聊天消息还是其他内容。我们提供的速度越快,便会为客户带来更多的价值。我们正处于一个快节奏且瞬息万变的环境时代。
Apache Kafka是一个分布式流平台,可以实时发布,订阅,存储和处理消息。其拉取式的体系结构减轻了繁重负载对服务的压力,并使其易于扩展。它以低延迟将大量数据从源移动到目的地。
Kafka是基于JVM的平台,因此客户端的主流编程语言是Java。但是,随着社区的蓬勃发展,高质量的开源Python客户端也已面世,并已在生产中使用。
在本文中,我将介绍最著名的Python Kafka客户端:kafka-python
, pykafka
和confluent-kafka
。最后,我将对每个库的利弊发表自己的看法。
为什么需要Kafka?
为什么选择Kafka?Kafka旨在增强事件驱动的体系结构。它通过提供高吞吐量,低延迟,高耐用性和高可用性解决方案来增强体系结构。
除了其高性能之外,另一个吸引人的功能是“发布/订阅”模型,发件人不会直接将消息发送给收件人,而是根据主题将消息传递到接收者可以订阅的集中位置。
这样,我们可以轻松地将应用程序解耦并摆脱整体设计。让我们看一个例子,以了解为什么解耦更好。
您的网站需要将用户活动发送到某个地方,因此您可以编写从网站到实时监控仪表板的直接连接。这是一个简单的解决方案,效果很好。有一天,您决定将用户活动存储在数据库中,以供将来分析。因此,您将另一个直接数据库连接写入到您的网站。同时,您的网站越来越多的流量,并且您想通过添加警报服务,实时分析服务等来增强它的功能。
您的架构最终将像这样,并且面临诸多潜在问题,如安全性问题,可伸缩性问题和可维护性问题。
您需要一个中心来分隔具有不同角色的应用程序。对于创建事件的应用程序,我们称它们为生产者,他们将事件发布到一个中央位置,每个事件(即消息)都属于一个主题。与生产者相对应的是消费者,他们选择订阅需要的主题,而无需直接与生产者交互。
这样的架构可以轻松扩展和维护,程序员可以将更多精力放在业务上。
设置kafka
您可以从 官方网站下载Apache Kafka。快速入门可帮助您在10秒钟内启动服务器。
您也可以从Confluent平台下载Apache Kafka。它是迄今为止最大的面向Kafka的流数据平台,为个人和企业提供了一系列围绕Kafka的基础设施服务。
每台Kafka服务器都成为代理(broker),您可以单独运行它或创建集群。除了Kafka,我们还需要Zookeeper来存储Kafka的元数据。Zookeeper就像协调器一样,负责管理分布式系统中每个代理的状态。
假设我们已经设置好Kafka开发环境,是时候连接到它了!原始的Java客户端提供5个API:
- Producer API:将消息发布到Kafka。
- Consumer API:订阅Kafka主题的消息。
- Streams API:订阅主题消息,并进行清洗和转换。包括消息过滤,联接,映射,分组等。
- Connect API:直接将Kafka集群连接到数据源或接收器,包括云对象存储平台,关系型数据库,Elasticsearch等。
- Admin API:管理Kafka集群中的主题和代理。
Kafka的Python库
在Python世界中,已经实现了5个API中的3个,分别是Producer API,Consumer API和Admin API。Python还没有提供Kafka Stream API,但是一个很好的选择是Faust。
Kafka-python非常类似于官方的Java客户端,并带有大量的pythonic接口。最好与Kafka 0.9+版本一起使用。第一个版本于2014年3月发布,正在积极维护中。
安装
pip install kafka-python
Producer
每个消息都是通过send()
异步发送的。调用时,它将记录添加到缓冲区中并立即返回。这使生产者可以以批处理方式将记录发送到Kafka,以提高效率。异步可以极大地提高速度,但是我们还应该了解以下几点:
- 在异步模式下,不能保证排序,你无法控制Kafka何时确认每条消息。
- 对生产者进行成功回调和失败回调是一个好习惯。例如,您可以在成功回调中编写信息日志消息,而在失败回调中编写异常日志消息。
- 由于无法保证排序,因此在回调中收到异常之前,可能会发送额外的消息。
如果要避免这些问题,可以选择同步发送消息。 send()
的返回是FutureRecordMetadata
。通过执行future.get(timeout=60)
,生产者将被阻塞最多60秒,直到kafka成功确认消息为止。这样做的缺点是速度,与异步模式相比同步发送非常缓慢。
import time
from kafka import KafkaProducer
msg = ('kafkakafkakafka' * 20).encode()[:100]
size = 1000000
producer = KafkaProducer(bootstrap_servers='localhost:9092')
def kafka_python_producer_sync(producer, size):
for _ in range(size):
future = producer.send('topic', msg)
result = future.get(timeout=60)
producer.flush()
def success(metadata):
print(metadata.topic)
def error(exception):
print(exception)
def kafka_python_producer_async(producer, si