消息队列(一)介绍与常见实现
概念
消息队列这东西不是必须的,根据场景来选择。这么流行的东西,J2EE当然有对应的规范,JMS,几个概念掌握很很简单理解。 选择使用上,一般用用AMQ就能解决大部分问题。kafka也非常火,连spring都有spring kafka项目。在大的项目中还是很有用的,虽然kafka也是消息队列,但是持久化非常快,可以扩展很多新的应用。
特性
- 消息队列是“暂存”,一般都有个broker
- 消息队列一般有个中间的queue(broker),消息队列=消息+队列
- 简单来看,消息队列=两次RPC+转储,RCP=序列化反序列化+网络传输
使用场景
- 延迟不很敏感,相对笨重的分布式事务可以采用支持最终一致性的消息队列
- 上游下游系统存在差异
- 有多个系统等待通知
- log,在down机时可恢复(spark的rdd,数据库同步)
与RPC不同
- RPC的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。
- 一般RPC强事务保证
- RPC同步接口多,使用相对简单
- 可以保证调用返回即处理完成
设计问题
消息堆积
处理消息对接一般是采用持久化的方式,存储系统可以分为以下几类
- 文件系统(Kafka)
- 分布式KV(Mongodb\HBase\Redis)
- 分布式文件系统
- 数据库
上面的持久化方式选择上,速度与可靠性反比。非持久化投递性能高,但处理慢的话会堆积在内存,有内存限制。
消费关系
有以下三种:
- JMS 规范Topic/Queue
- Kafka Topic/Partition/ConsumerGroup
- RabbitMQ里面的Exchange
可靠性
设计上需要考虑超时、down机、消息没有送达、送达后数据没落地、数据落地了回复没收到等异常。
顺序消息
一般来说要求消息顺序发送,就会允许消息丢失,否则重发消息的话消息顺序性就不能保证了。
重复消息
如何鉴别重复消息有以下几种方式
- 版本号方式,发送方自带版本(消息队列能实现),接收方保存版本,如果中断丢消息,需要特殊处理
- 状态机方式,例如如果在告警状态,不在接收告警消息。可以使用在特殊的场景下。
慢消费
这是消息队列中非常常见的问题,处理方式有多种,需要根据实际场景选择。后面介绍AMQ的文章中有提及处理方式。
常见实现与特点
Kafka/Jafka
- 持久化快
- 吞吐量大适合大数据采集
- 分布式,自动负载均衡
- Apache家族支持hadoop
- 依赖Zookeeper
- 分区+备份
- pull模式+分布式,大吞吐量
- broker越多,吞吐量越大
ZeroMQ
- 传输最快
- 延时极低,应用于金融等领域
- 支持复杂功能,使用也复杂,学习成本高
- 没有broker,从名字可见,zero mq
- 可以看成网络库与tcpmodule类似
- 非持久化(默认不支持)
- Storm从0.9版本开始同时支持ZeroMQ和Netty作为传输模块
RabbitMQ
- 功能多
- 支持协议多
- 重量级(企业级),遵从AMPQ
- 开发语言Erlang(分布式并发而设计,并发运行性能比Java好)
- RMQ比AMQ快
- 电信行业多用
ActiveMQ
- 轻量级,中庸,ZeroMQ 与RabbitMQ 结合
- 功能多,使用简单,学习成本低,在极端情况下不如RabbitMQ稳定
- 支持JMS1.0,6.x可能支持JMS2.0
Redis
- 非专业,NoSql分布式数据库
- 不适合放大消息,不要放图片,反序列化消耗性能,尤其是对象
- 适合小的消息处理
- 高版本自带内存分配器jemalloc