消息系统基本原理
消息系统的分类
基于Peer-to-Peer的消息系统
- 一般基于pull或polling接受消息;
- 发送到队列中的消息被一个而且仅仅一个接收者所接收,即使有多个接收者在同一个队列中侦听同一消息;
- 即支持异步"即发即弃"的消息传送方式,也支持同步请求/应答传送方式;
如下图所示,生产者Producer1生产的消息发送到队列后只能被其中某一个consumer所消费:
基于发布/订阅的消息系统
- 发布到一个主题的消息,可被多个订阅者所接收,主题可认为是消息的类型;
- 发布/订阅可基于push消费数据,也可基于pull或polling消费数据;
- 解耦能力比跑p2p模型更强;
如下图所示,消息发布者Pushlisher1生产消息并发送到topic,只要订阅了该主题的Subscriber都可接收到该消息:
消息系统的适用场景
- 解耦: 各系统之间通过消息系统这个统一的接口交换数据,无需了解彼此的存在;
- 冗余:部分消息系统具有消息持久化能力,可规避消息处理前丢失的风险;
- 扩展:消息系统是统一的数据接口,各系统可独立扩展;
- 峰值处理能力:消息系统可顶住峰值流量,业务系统可根据处理能力从消息系统中获取并处理对应量的请求;
- 可恢复性:系统中部分组件失效并不会影响整个系统,它恢复后仍可从消息系统中获取并处理数据;
- 异步通信:在不需要立即处理请求的场景下,可将请求放入消息系统,合适的时候再处理;
Kafka设计目标
- 高吞吐率:在廉价的商用机器上单机可支持每秒100万条消息的读写;
- 消息持久化:所有消息均被持久化到磁盘,无消息丢失,支持消息重放;
- 完全分布式:Producer、Broker、Consumer均支持水平扩展;
- 同时适应在线流处理和离线批处理
Kafka初体验
Kafka使用Scala语言开发,运行于JVM之上,因此我们首先安装Jdk,具体安装方法就不说了,从官网下载Kafka解压:
$ tar -zxvf kafka_2.11-1.1.0
进入到Kafka解压目录,首先启动Zookeeper服务,因为Kafka依赖于Zookeeper,如果需要后台启动Zookeeper则加上-daemon
参数:
$ cd kafka_2.11-1.1.0/
$ bin/zookeeper-server-start.sh config/zookeeper.properties
出现如下信息表明Zookeeper启动成功:
[2018-07-06 08:55:57,637] INFO binding to port 0.0.0.0/0.0.0.0:2181 (org.apache.zookeeper.server.NIOServerCnxnFactory)
启动Broker服务,同样后台启动只需加上-daemon
参数:
$ bin/kafka-server-start.sh config/server.properties
验证Zookeeper是否已经监听2181端口,可以看到Zookeeper不仅监听2181端口,还和Broker服务建立了链接:
peter@ubuntu:~/Study/Kafka/kafka_2.11-1.1.0$ lsof -i:2181
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 2862 peter 92u IPv6 53459 0t0 TCP *:2181 (LISTEN)
java 2862 peter 93u IPv6 53761 0t0 TCP localhost:2181->localhost:52102 (ESTABLISHED)
java 3150 peter 110u IPv6 53760 0t0 TCP localhost:52102->localhost:2181 (ESTABLISHED)
验证Broker服务是否监听9092端口:
peter@ubuntu:~/Study/Kafka/kafka_2.11-1.1.0$ lsof -i:9092
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 3150 peter 97u IPv6 52842 0t0 TCP *:9092 (LISTEN)
java 3150 peter 113u IPv6 53762 0t0 TCP localhost:34792->ubuntu:9092 (ESTABLISHED)
java 3150 peter 114u IPv6 53763 0t0 TCP ubuntu:9092->localhost:34792 (ESTABLISHED)
创建Topic,需要制定Zookeeper列表、Topic名称、Partitions数量等:
$ bin/kafka-topics.sh --zookeeper localhost:2181 --create --topic test1 --partitions 3 --replication-factor 1
验证Topic是否创建成功:
$ bin/kafka-topics.sh --zookeeper localhost:2181 --describe --topic test1
显示如下结果:
Topic:test1 PartitionCount:3 ReplicationFactor:1 Configs:
Topic: test1 Partition: 0 Leader: 0 Replicas: 0 Isr: 0
Topic: test1 Partition: 1 Leader: 0 Replicas: 0 Isr: 0
Topic: test1 Partition: 2 Leader: 0 Replicas: 0 Isr: 0
启动Kafka提供的Consumer命令行工具:
$ bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test1
启动Kafka提供的Producer命令行工具:
$ bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test1
Kafka架构
Kafka的整体架构图如下图所示:
Producer刷新Broker集群元数据信息有两种方式:一、当Producer向某一台Broker机器发送消息失败的时候,则该机器上运行的Broker服务可能宕掉了,这是会触发Producer刷新本地缓存的Broker元数据信息;二、Producer定期的刷新本地缓存的Broker集群元数据信息,其中刷新周期可以通过Producer的配置参数做配置。
其中Broker和Zookeeper作为服务运行,而Producer和Consumer是Kafka提供的SDK,我们可以通过Producer的SDK向Broker发送消息,通过Consumer的SDK从Kafka获取消息。
Topic & Partition
Topic:
- 顾名思义,消息的主题,可认为Kafka使用Topic对消息进行分类;
- Topic是逻辑上的概念,隶属同一个Topic的消息可分布在一个或多个Broker节点上;
- 一个Topic包含一个或多个Partition;
- 每条消息属于仅且属于一个Topic;
- 当Producer发布消息时,必须指定将该消息发布到哪一个Topic;
- 当Consumer订阅消息时,也必须指定订阅哪个Topic的消息;
如下图所示:
Partition
- Partition是一个物理的概念,不考虑备份的情况下同一个Topic下的一个Partition只分布于一台Broker机器上;
- 一个Partition物理上对应一个文件夹,等下我们实验的时候可以验证这一点;
- 一个Partiton包含多个Segment(Segment对用户透明);
- 一个Segment对应一个文件,Kafka会将记录写入到这些文件当中;
- Segment由一个个不可变的记录组成;
- 记录只会append到Segment上,不会被单独删除或修改;
- 清除记录时,直接删除一个或多个Segment,即直接删除Segment对应的文件,这样类似于关系型数据库中直接drop table数据来更加高效的清除过期记录;