Skip to content

RabbitMQ

  1. 坏盘怎么办,怎么伸缩

Erlang语言最初在于交换机领域的架构模式,这样使得RabbitMQ在Broker之间进行数据交互的性能是非常优秀的

Erlang的优点: Erlang有着和原生Socket一样的延迟

集群

主备模式

warren (兔子窝),一个主/备方案(主节点如果挂了,从节点提供服务,和ActiveMQ利用Zookeeper做主/备一样)

远程模式

远距离通信和复制,可以实现双活的一种模式,简称Shovel模式

所谓Shovel就是我们可以把消息进行不同数据中心的复制工作,可以跨地域的让两个mq集群互联

镜像模式

集群模式非常经典的就是Mirror镜像模式,保证100%数据不丢失

多活模式

热伸缩

这种模式也是实现异地数据复制的主流模式,因为Shovel模式配置比较复杂,所以一-般来说实现异地集群都是使用这种双活或者多活模型来实现的

这种模型需要依赖RabbitMQ的federation插件,可以实现持续的可靠的AMQP数据通信,多活模式实际配置与应用非常简单

  • Federation插件是一个不需要构建Cluster,而在Brokers之间传输消息的高性能插件,Federation 插件可以在Brokers或者Cluster之间传输消息,连接的双方可以使用不同的users和virtual hosts,双方也可以使用版本不同的RabbitMQ和Erlang。Federation 插件使用AMQP协议通讯,可以接受不连续的传输
  • Federation Exchanges,可以看成Downstream从Upstream主动拉取消息,但并不是拉取所有消息,必须是在Downstream上已经明确定义Bindings关系的Exchange,也就是有实际的物理Queue来接收消息,才会从Upstream拉取消息到Downstream。使用AMQP协议实施代理间通信,Downstream 会将绑定关系组合在一起,绑定/解除绑定命令将发送到Upstream交换机。因此,FederationExchange只接收具有订阅的消息,本处贴出官方图来说明;

可靠性

保障消息的成功发出

保障MQ节点的成功接收

发送端收到MQ节点(Broker) 确认应答

完善的消息进行补偿机制

可靠性投递

消息落库,对消息状态打标

消息延迟投递,做二次确认,回调确认

  • 通过二次延迟队列进行检查,如果没有结果,则重新告诉生产者发送新的任务

幂等性

极端情况下AB两个线程同时对一个商品进行操作,此时版本号为1,当其中一个线程获取到商品操作后,将版本号+1,这样B线程就会失败,保证单次消费

消费端实现幂等性,就意味着,我们的消息永远不会消费多次,即时我们收到了多条一-样的消息

主流实现

唯一ID +指纹码机制,利用数据库主键去重

  • SELECT COUNT(1) FROM T ORDER WHERE ID =唯- -ID +指纹码
  • 好处:实现简单
  • 坏处:高并发下有数据库写入的性能瓶颈
  • 解决方案:跟进ID进行分库分表进行算法路由

利用Redis的原子性去实现

DeadLetter

QOS流控

TTL

常见场景

分布式

  • 普通集群:不同步数据,每个节点存储自己的消息队列,如果发生宕机,则不可用

消息发送

Topic模式

采用Topic Exchange交换数据,其Exchange下绑定多个消息队列,通过routingKey转发到指定队列

消费者

并发

RabbitListener注解的concurrency可以设置并发度

模式

push/pull

消息丢失

生产者和消费者都可以开启确认机制

  • 生产者

  • 消费者
    • 开启手动ack,但是无法自动重试

重试

  • 方案一:使用自动ACK + RabbitMQ重试机制
    • 使用自动ACK存在消息丢失风险
    • 重试一定次数以后会丢到DeadLetter中,可以指定其它队列
    • 需要显示的抛出异常
    • 重试机制依赖于spring-retry
    • 重试过程会阻塞
  • 方案二:使用手动ACK + 手动重试机制
    • 第一种:通过代码方式记录重试次数,超过重试次数以后将其丢入DeadLetter
    • 第二种:确认消费消息,但是把消息重试次数+1,再次放入队列(因为ack机制无法修改数据),超过重试次数以后将其丢入DeadLetter
    • nack会把数据丢到队头

对象传输

java
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

异步调用

  • 异步调用常见实现就是事件驱动模式

  • 异步通信的优点
    • 耦合度低
    • 吞吐量提升
    • 故障隔离
    • 流量削峰
  • 异步通信的缺点
    • 依赖于roker的可靠性、安全性、吞吐能力
    • 架构复杂了,业务没有明显的流程线,不好追踪管理

对比

RabbitMQActiveMQRocketMQKafka
公司/社区RabbitApache阿里Apache
开发语言ErlangJavaJavaScala&java
协议支持AMQP,XMPP,SMTP,STOMPOpenWire,STOMP
REST,XMPP,AMQP
自定义协议自定义协议
可用性一般
单机吞吐量一般非常高
消息延迟微秒级毫秒级毫秒级毫秒以内
消息可靠性一般