1.4 消息系统
数据通常从一个应用流向另一个。一个应用产生数据,而后被一个或多个其他应用使用。一般来讲,生成或发送数据的应用叫作生产者,接收数据的则叫作消费者。
有时候,产生数据的应用数量和使用数据的应用数量会出现不对称。比如,一个应用可以产生数据,而后被多个消费者使用。同样地,一个应用也可以使用来自多个生产者的数据。
有时候应用产生数据的速率和另一个应用使用数据的速率也会出现不对称。一个应用可能产生数据的速率快于消费者使用数据的速率。
从一个应用向另一个应用发送数据的简单方法就是把它们直接互连。然而,当生产者和消费者数量或数据生成速率和使用速率之间存在不对称时,这个方法就行不通了。另一个挑战是生产者和消费者之间的强耦合要求它们同时运行,或实现一个复杂的缓冲机制。因此,生产者和消费者之间直连无法扩展。
一个灵活且可扩展的解决方法是用一个消息代理或消息系统。应用无须直接互联,而是连接到消息代理或消息系统。这样的架构使在数据管道上添加生产者或消费者变得容易,也允许应用以不同速率来生成和使用数据。
本节讨论几个大数据应用广泛使用的消息系统。
1.4.1 Kafka
Kafka是一个分布式的消息系统或消息代理。准确来讲,它是一个分布式的、分块的、重复的提交日志服务,可以用来作为发布-订阅式消息系统。
Kafka的关键特性包括:高吞吐量、可扩展性和持久性。单个代理可以处理来自数以千计应用的每秒几百兆字节的读和写。可以通过向集群中增加更多节点来轻松扩容。关于持久性,它在硬盘上保存消息。
基于Kafka的架构中的关键实体包括:代理、生产者、消费者、主题和消息(见图1-6)。Kafka作为节点的集群来运行,每个节点叫作代理。通过Kafka发送的消息属于主题。把消息发布到Kafka主题的应用叫作生产者。消费者指的是订阅Kafka主题并处理消息的应用。
Kafka把一个主题分割为多个分块。每个分块是消息的一个有序而不可变的序列。新消息被追加到一个分块。给一个分块中的每一条消息指定一个唯一的连续标识符(叫作偏移量)。各个分块分布在Kafka集群的各个节点。另外,也复制它们以提供容错功能。主题的分割有助于扩展性和并行性。一个主题不需要限制于单台机器,它可以增长到任意大小。主题大小的增长可以通过向Kafka集群中添加更多节点来解决。
发布到Kafka集群的消息中,一个重要的属性是:它在一个可配置的周期内保留所有消息。即使消费者使用了一条消息,在所配置的间隔内消息依然可以获取它。更重要的是,Kafka的性能对于数据大小实际上保持恒定。
Kafka使用一个叫作消费者组的机制来同时支持队列和发布-订阅消息模型。把发布到一个主题的每条消息发送到每一个订阅的消费者组内的一个消费者。因此,如果订阅一个主题的所有消费者属于同一个消费者组,则Kafka作为一个队列消息系统而工作,每条消息只发送到一个消费者。另一方面,如果订阅一个主题的每一个消费者属于不同的消费者组,则Kafka作为一个发布-订阅消息系统而工作,把每条消息都广播到所有订阅某主题的消费者。
1.4.2 ZeroMQ
ZeroMQ是一个轻量级的高性能消息库。它用来实现消息队列和构建可扩展的并发和分布式消息驱动的应用。它没有利用以代理为中心的架构,尽管根据需要也可以用它来构建一个消息代理。它支持大多数现代语言和操作系统。
ZeroMQ的API仿效了标准的UNIX Socket API。应用之间通过套接字互相通信。不像标准的套接字,它支持N对N连接。一个ZeroMQ套接字代表一个异步的消息队列。它用一个简单的框架在线缆上传输离散消息。消息长度可以是0字节到数吉字节。
ZeroMQ不会对消息强加任何格式,而将消息当作二进制大对象blob。可以通过序列化协议来结合它,比如用Google的Protocol Buffers来发送和接收复杂的对象。
ZeroMQ在后台线程中异步实现I/O。它会自动处理物理连接设置、重连、消息传送重试和连接清除。另外,如果接收者不可达,它会将消息排队。当队列满额时,可以将其配置为阻止发送者或丢弃消息。因此,ZeroMQ提供了一个比标准套接字更高级的抽象来发送和接收消息,使创建消息分发应用更加简单,也使得应用间发送和接收消息的松耦合成为可能。
ZeroMQ库支持多个传输协议来进行线程间、进程间和跨网络的消息传递。对于相同进程内线程间的消息传递,它支持一种不涉及任何I/O的基于内存的消息传递机制。对于运行在相同机器上的进程之间的消息传统,它使用UNIX域或IPC套接字。这种情况下,所有通信都在操作系统内核中发生,而不会使用任何网络协议。ZeroMQ支持TCP协议来实现应用间通过网络进行通信。最后,它还支持PGM来多播消息。
ZeroMQ可用来实现不同的消息传递模式,包括:请求-应答、Router-Dealer、客户端-服务器、发布-订阅和管道。比如,可以用ZeroMQ创建一个发布-订阅模式的消息传递系统来从多个发布者发送数据到多个订阅者(见图1-7)。要实现这个模式,发布者应用会创建一个ZMQ_PUB类型的套接字。在这样的套接字上发送的消息以扇出(fan-out)的方式分布到所有已连接的订阅者。订阅者应用创建一个ZMQ_SUB类型的套接字来订阅来自发布者的数据,可以指定一个过滤器来获取想要的消息。同样地,也可以用ZeroMQ创建一个管道模式来分发数据到管道上排列的各个节点。应用创建ZMQ_PUSH类型的套接字来发送消息到下游应用,下游应用则需创建ZMQ_PULL类型的套接字。