消息中间件之RabbitMQ

组件

Producer: 生产者生产消息

Consumer:消费者消费消息

Exchange:交换器,RabbitMQ 中的消息不会直接投递到 Queue 中,中间需要经过 Exchange,由 Exchange 把消息分配到对应的 Queue 中。如果 Producer 生成的消息路由不到对应的队列,可能会返回给 Producer 或者直接丢弃掉。

RoutingKey:路由键,生产者将消息发送给交换器时,一般会指定 RoutingKey,用来指定路由规则。RoutingKey 要与 BindingKey 联合使用才会最终生效。

BindingKey:绑定键

RabbitMQ 需要通过 Binding(绑定),将 Exchange 和 Queue 关联起来,在绑定时一般会指定 BindingKey。在 Producer 发送消息时,BindingKey 就是RoutingKey。

一个 Exchange 和多个 Queue 绑定时,允许指定相同的 BindingKey。

BindingKey 在某些情况下是不生效的,例如 fanout 类型的交换器会无视 BindingKey,将消息路由到绑定到这个交换器上的所有队列中。

Queue:消息队列

消息队列用来保存消息,直到发送给消费者,它是消息的容器,也是消息的终点。一条消息可以投递到一个或者多个消息队列,等待消费者将其消费掉。

多个消费者订阅同一个队列时,队列中的消息会被均摊给多个消费者,而不是每个消费者都能收到消息,这样避免消息重复被消费。

Broker:消息中间件服务节点,即 RabbitMQ 服务节点。

Exchange Types(交换器类型)

RabbitMQ 的交换机类型。

fanout:广播模式,它会把所有发送到 Exchange 的消息路由到所有与该 Exchange 绑定的 Queue,fanout 是速度最快的交换机。fanout 通常用来广播消息。

direct:直接路由,它会将消息路由到那些 BindingKey 与 RoutingKey 完全匹配的队列中。

topic:主题路由,BindingKey 和 RoutingKey 约定它们都是有点号"."分割的字符串。例如“test.rabbitmq.client”,BindingKey 和 RoutingKey 中可以存在两种特殊字符""和"#",用于模糊匹配。其中""匹配一个单词,即相邻两个点之间的内容,"#"批次零个或多个单词,例如"test.#"可以匹配以"test."开始的任意路由。

headers:消息头路由,它不依赖路由键进行路由,而是根据发送消息内容中的 headers 属性进行匹配,通过对比消息的 headers 属性与 Exchange 绑定 Queue 时指定的属性是否一致来进行路由。

headers 类型的交换器性能会很差,而且也不实用。

RabbitMQ 的一些机制

TTL:time to live,生存时间,是 RabbitMQ 支持的消息过期时间。

  • 在发送消息时设置,通过配置消息体的 properties 指定消息的过期时间。

  • 在创建 Exchange 时设置,从消息进入队列开始计算,超过超时时间,消息会自动清楚。

DLX(死信队列):dead-letter-exchange,当一个消息成为死信后,会被重新 publish 到另一个 exchange上,这个 exchange 就是死信队列。

死信队列是一个正常的 exchange,它能在任何队列上被指定。当这个队列中有死信,RabbitMQ 会自动将消息重新发布到设置的 exchange 上去,进而被路由到另一个队列。

消息变成死信的几种情况:

  • 消息被拒绝(basic.reject/basic.nack)并且requeue=false

  • 消息TTL过期

  • 队列达到最大长度

死信队列使用:

  1. 在声明的 queue 中指定死信队列的 exchange

  2. 声明死信 exchange、queue 并绑定

消费端ACK、NACK、Reject:

ack 是手动确认消息被消费

nack 是拒绝确认消息被消费,一般可以通过 requeue 参数把消息重新返回到 Broker,一般来说,实际应用会设置为 false,不返回队列。

reject 是拒绝确认消息被消费,与 nack类似。

生产者Confirm机制:生产者投递消息后,如果 Broker 收到消息,会给生产者一个成功或者失败的应答,生产者根据应答来确认消息是否投递成功,以确定后续操作,重发或者记录日志。生产者Confirm机制,这是在投递方保证消息可靠性的核心。

return消息机制:当一些消息不可路由的时候,例如 exchange 不存在,或者路由键不存在,导致消息不可达,可以使用 return listener。通过chennel.addReturnListener(ReturnListener rl)传入已经重写过handleReturn方法的ReturnListener,处理不可达消息。

消费端消息的获取方式 pull/push:可以通过while循环 consumer.nextDelivery() 模拟进行pull消息,但是死循环会消耗CPU资源。也可以通过自定义 Consumer 等待 RabbitMQ 推送消息过来(现在默认使用 push 方式)。

持久化:queue、exchange、message 都支持持久化

持久化的 queue、exchange 在 RabbitMQ 的 Broker 重启后,queue 和 exchange 依然存在。

消息的持久化取决于消息本身的持久化模式,如果消息以持久化模式发布,会对性能造成一定的影响。

消费端限流:如果 RabbitMQ 瞬间将大量数据推给消费端,消费端无法处理,会导致消费端服务器被压垮。RabbitMQ 提供了 qos 功能,即在非自动确认消息的前提下,如果一定数量的消息没有被确认前,不进行消费新的消息。

顺序消息:顺序发送必须保证消息投递到相同的队列,且只能有一个消费者,每次只消费一条信息,手工ACK后,再处理下一条消息。

重复消费:保证消息不被重复消费的关键是保证消息的幂等性,

解决方案:

  • 把消息作为唯一主键,落库到数据库,如果重复会发生主键冲突。

  • 将消息set到redis中,set操作本身就是幂等。

  • 用第三方介质做消费记录,例如给消息分配全局id,将消息 id,message 以 K-V 形式存入,消费前,先查询有没有消费记录。

RibbitMQ集群

普通集群:多个节点之间只共享元数据,即队列结构,消息实体只存在其中一个节点中。例如 rabbit01、rabbit02,当消息进入 rabbit01 后,consumer 连接到 rabbit02 进行消费,会临时在两个节点之间进行消息传输,所以 consumer 尽量连接每一个节点,从中取消息。同一个逻辑队列,要在多个节点建立物理 queue,否则物理连接谁,出口总在 rabbit01,会产生瓶颈。

当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。如果做了消息持久化,那么得等rabbit01节点恢复,然后才可被消费。如果没有持久化的话,就会产生消息丢失的现象。

镜像集群:在普通集群的基础上,把需要的队列做成镜像队列,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取,也就是说多少节点消息就会备份多少份。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。

作者:南橘ryc 链接:https://juejin.cn/post/6844904121917505550 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

保证消息的投递成功

  1. 确认应答机制(生产者Confirm机制)、消费端ACK、NACK、Reject

  2. 消息自动补偿机制,(return消息机制、死信队列)

  3. 持久化机制,exchange、queue、message 都可以持久化到磁盘

  4. 消息落库机制,将消息写入数据库持久化,同时对消息进行确认,保证消息消费成功

  5. 延迟投递机制,借助死信队列和TTL实现延迟投递,在TTL后,数据被投递进死信队列,然后再处理

保证消息的消费成功

1.消息消费确认应答模式,当消息消费成功后手动或者自动ACK,或者NACK,保证消息被成功消费

参考文章1:Rabbitmq 原理解析与使用

参考文章2:【进阶之路】消息队列——RabbitMQ原理(二)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容