为啥要使用消息队列,主要是两个目的:
(场景:生产者消费者模型)
- 生产者与消费者速度不匹配;(生产者太快了)
- 解耦生产者与消费者。(可以异构,不同语言,不同节点)
JMS(Java MessageService)
Sun公司早期提出的消息标准。
api规范(旧).支持点对点和发布订阅.
概念 | 解释 |
---|---|
producer/publisher | 生产者 |
consumer/subscriber | 消费者 |
message | 消息 |
queue | 存放消息的地方 |
topic | 提供多个订阅者消费消息的机制 |
JMS中的消息模式有两种:
- P2P: 点对点
- publish-subscribe: 发布订阅
AMQP (advanced message queuing protocol)
高级MQ协议. 不但约束了api,还使不同实现之间可以合作.
加入了Exchange,Binding,解耦了队列,
可以灵活实现除了点对点\发布订阅以外的模型.
消息模型:
AMPQ其中一个实现: rabbitmq
简单理解概念:
1 | Channel : 信道.一个连接多个Channel. 节省开销.(复用tcp连接,每次发送消息算一个信道) |
Exchange
:
根据配置好的路由规则,转发收到的消息到符合的queue.
不同类型的exchange:
1 | direct 直连 |
kafka
基本概念
1 | Broker: kafka server的一个单位(brokerid); |
内部组件
1 | SocketServer: 接受消息,返回消息(客户端、内部通信), |
KafkaController
Broker通过ZK抢注Controller。
Controller负责管理broker。它会注册很多Listener,监听zk上节点变化,来维护状态自动机变化。
- Slave(Follower,对于某一个topic的partition是follower):同步数据。
- Slave(Leader,对于某一个topic的partition是leader): 接受kafkaApi(consumer和producer)的请求。
读写partition:
随机找一个机器->metadata(zk)->发送请求给这个partition的具体leader。
SocketServer
状态机
KafkaHA
ISR
: in-sync Replicaleader
: 最新offset;follower
: 最新offset就是ISR;(轮询offset)zk
: 都有谁是ISR,同步了。
leader挂了,选一个ISR;
如果没有ISR,则随机选一个最先起来的。(不一定选offset最高的,不确定后头还会不会起来follower)。
ACK
(均到内存,均不保证落盘)
1: leader收到就收到;
2: 有一个follower收到就收到;
3: 所有follower收到才收到。
错误恢复
leader选举
直接从ISR中选第一个(近似于随机)。Controller选举:(某台机器)
所有Broker抢注ZK。
Controller挂的时候: 所有replica和partition的状态不能改变。也不能reBanlance了。
如果Controller挂的时候,leader也挂,所在partition就不能读不能写了。
- 倾斜(热点):
一台最稳定的机器上,可能集中了所有leader.
(可以手动reAssign)
实际案例
其他类kafka的消息队列改进:
- Consumer之间消费的分区互不重叠(防止kafka的重复消费);(tube)
- 严格有序:数据落地到单队列上,每次ACK。(hippo)
- controller改成双master热备,降低对zk依赖,引入nameserver.(rocketmq)