为什么用rabbitmq?
使用mq主要为了实现解耦、提高系统的健壮性和响应速度,将一些与主链路不需要同步执行的逻辑,直接抛给队列异步处理(注意:开发中采用异步线程发送队列消息,同步的话当队列发生阻塞时,会影响业务主链路)
概念
基本概念
- broker——消息队列服务器
- producer——生产者,生产消息的客户端
- customer——消费者,消费消息的客户端
- vhost——虚拟主机,一个broker可以设置多个vhost,用作权限分离,公用同一个消息队列服务器,但看上去是在使用不同的broker
- connection——连接,客户端与服务器的一次TCP长连接
- channel——消息通道,建立在connection基础上,AMQP协议规定只能在通道上进行通信执行命令。一个连接可以创建多个通道,起到了复用tcp连接的效果,之所以使用channel,是因为tcp连接的创建和释放的开销很大
- exchange——交换机,生产者将消息发送到交换机,然后根据exchange type和binding将消息路由对应的queue队列中
- queue——队列,消息保存在队列中,可以设置durability属性实现队列和消息的持久化
- binding——绑定,将exchange和queue关联在一起
- routing key——路由键,生产者发送消息时,指定路由规则,exchange将消息路由到对应的queue
exchange类型
- fanout——不处理路由键,一条消息发送到交换机,交换机复制多份路由到有绑定关系的队列中
- direct——直接路由,根据routing key与binding路由到指定的queue
- topic——根据#、*进行模糊匹配,任何发送到topic exchange的的消息都会路由到关注routing key的指定话题上。#匹配一个或多个词、*只匹配一个词
- headers——根据发送消息中的属性(键值对)完全匹配exchange与routing key绑定时设定的键值对
扩展
- 备份交换机,对于生产者发送到交换机的消息,有可能存在无法正确路由的队列,如果想要保证消息不丢失,可以使用备份交换机,使用参数alternate-exchange来实现
- 死信队列,如果一个消息变成死信之后,将会重新发送到一个新的交换机中,与交换机绑定的队列就是死信队列。一条新消息变成死信的理由有两种,一是消息被拒收;二是消息已过期。死信队列可用于配合TTL实现延迟队列
- 持久化,交换机和队列默认非持久化,设置属性durable为true实现持久化,消息持久化需要设置参数deliveryMode=2,1为不设置初始化
- 流控,流控是用来避免消息的发送速率过快,积压消息过多,导致服务器难以支撑的场景。当某个进程因为某些原因导致来不及处理发送过来的消息时,这个进程的消息将会出现积压,当积压到一定量时,将会出现线程阻塞并且不接受来自上游线程发送过来的消息;这样上游的进程也将出现消息积压最后阻塞并拒绝接受上游的消息。当阻塞一直传递到最上游时,将会出现暂停接受生产者消息的情况
- 信用流算法,用来限制发送速率来控制消息处理进程的处理能力
以上图为例,每个进程都会有一个默认的credit的值,进程B有两个参数,{credit_from, C}表示可以发送到进程C的消息数量,每发送一条消息该值就减1,当为0时,进程B将不接受上游发送的消息也不会给下游发送消息;{credit_to, A}表示接受多少条消息后,就通知上游A进程增加credit,进程A随后增加{credit_from, B}这样A就可以继续发送消息到B。
当上游发送消息速率过快,credit会快速消耗完,这时线程也就会阻塞,一直传播到最上游。当上游收到下游增加credit值的通知时,将解锁阻塞状态,恢复正常。
高可用架构
镜像队列
对于单节点的broker,即使将队列和消息设置为持久化,在消息发出到存入磁盘期间也可能存在消息丢失的情况,而且单节点风险很高,宕机后系统将不可用。
镜像队列可以将队列镜像到集群的其他broker上,如果集群的一个节点失效了,可以切换到镜像中其他节点保证服务的可用性。
镜像队列包含一个主节点和N个从节点,发送消息时,是会向所有的master以及slave节点发送,除此之外,所有的命令都是发送到master,然后再广播给其他的slave节点;如果客户端连接的是slave节点,会转发到master,然后再将结果发送到slave,然后再到客户端;当master节点宕机后,加入集群时间最久的slave升级为master,因为该slave存在与master最多的信息。
镜像队列的三种模式:(设置ha-mode参数)
- all:集群中所有节点进行镜像
- exactly:表示指定个数的节点进行镜像
- nodes:表示指定节点进行镜像