2019独角兽企业重金招聘Python工程师标准>>>
1. Rabbitmq 是什么?
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件). AMQP(Advanced Message Queuing Protocol) , 一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计, RocketMQ,ActiveMQ, ZeroMQ, Kafaka, 等消息队列都是AMQP协议的实现。
2. 为什么用MQ?
在项目中,将一些无需即时返回且耗时的操作提取出来,进行了异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。 例如:点赞/评论/阅读数等,要求实时性不高的,只要求最终一致性的业务。
3. rabbitMQ 名词解析
3.1 virtual host
类似DB中的schema, JAVA中的namespace
3.2 exchange
交换机,消费者发送消息到exchange
3.3 routeint key (binding key - 生产者端) 路由
生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。
在Exchange Type与binding key固定的情况下(在正常使用时一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时, 通过指定routing key来决定消息流向哪里。RabbitMQ为routing key设定的长度限制为255 bytes。
3.4 queue
队列用于储存消息
4. Exchange Types
Exchange Types有 fanout、direct、topic、headers这四种类型
4.1 fanout message
广播模式,fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中,所以不管你的生产者端的bingding key 和 消费者端的routing key.
参考下面的图片:
生产者发送一个消息会被消费者C1 & C2接收到。
4.2 direct message
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中, routing(binding) key 最大长度 255 bytes。
根据生产者中binding key 来和消费者端 routing key 做精确匹配(equal)。
4.3 topic message
direct message 是 binding key == routing key, topic message是like, 其中routing key中可以带 * 和 # 来做模糊匹配, “*”用于匹配一个单词,“#”用于0~N个单词.
4.4 headers message
headers类型的Exchange不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
headers 图片引用自
headers x-match 决定是否进入到相应队列, x-match = any, key*/value* 只要有一个符合就行, x-match =all key*/value* 要求 >= 条件
5. RPC
MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败,但实际的应用场景中, 业务上很可能需要一些同步处理,需要同步等待服务端将消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。 在RabbitMQ中也支持RPC。
根据消息属性上的 replyTo & correctionId 标识,返回给生产者(P)端,让生产者端继续执行之后的业务逻辑(可以同步/异步).
6. Dead letter message
用来做延时任务
channel.exchangeDeclare("some.exchange.name", "direct");
Map args = new HashMap();
# expire time (ms)
args.put("x-message-ttl", 60000);
args.put("x-dead-letter-exchange", "some.exchange.name");
# without consumer listener queue: myqueue, will redirect to dead leter routing key
args.put("x-dead-letter-routing-key", "some-routing-key");
channel.queueDeclare("myqueue", false, false, false, args);
7. CAP
7.1 一致性
consumer 接口应该考虑幂等性和最终一致性。 例如:consumer 操作 DB 应该提前定义主键, insert or update
7.2 高可用
为了达到高可用,合理的设置每个consumer 的线程池大小和prefetch count.
# set consumer thread pool
ExecutorService es = Executors.newFixedThreadPool(20);
Connection conn = factory.newConnection(es);
# consumer 同时允许处理多少条未消费的消息
channel.basicQos(10); // Per consumer limit
7.3 分区容错性
启动多个consumer listener, 一个consumer down了,还能正常的使用。