用RabbitMQ了好几年以后,我总结出来5点RabbitMQ的使用心得

大概从 2013 年开始,我就开始了本身和 RabbitMQ 的接触,到如今已经有七年多了。java

在这七年中,既有一些对 RabbitMQ 的深度体验,更有无数的血泪史。程序员

而根据我这么多年的使用经验,我将 RabbitMQ 的心得造成一些提醒或者规范分享给你们,这样,你们之后使用 RabbitMQ 的时候,就不会再走我走过的弯路了。数据库

我想把我这些关于 RabbitMQ 的经验和心得,分红三篇来写:服务器

  • 开发前的规范;
  • 开发中的注意事项;
  • 以及 MQ 自己的优化。

此次我们先从开发前的规范开始谈起。网络

我曾经一直都很奇怪,为什么你们使用开发语言有开发规范,使用数据库有数据库规范,可是使用 MQ 却不多见一些规范。框架

使用 MQ 缺乏规范,这是广泛的问题?还只是我身边的个例?优化

无论答案是哪一个,在 RabbitMQ 使用时,为了不在开发中少出现问题,为了事半功倍,都须要提早规范好一些配置和事项。设计

1. 一个 RabbitMQ 应用里创建多个 vhost,去对应不一样的开发项目

咱们在使用数据库的时候,会在一个数据库应用里创建多个不一样的数据库去给不一样的项目使用,而不用在不一样的服务器专门每一个项目都安装个数据库应用。队列

在 RabbitMQ 的 vhost,也是相似的理念。进程

vhost 本质上是一个 mini 版的 RabbitMQ 服务器,拥有本身的队列、绑定、交换器和权限控制,当在 RabbitMQ 中建立一个用户时,用户一般会被指派给至少一个 vhost,而且只能访问被指派 vhost 内的队列、交换器和绑定,vhost 之间是绝对隔离的。

因此,不一样的 vhost 对应不一样的项目,互不影响,而这些 vhost 其实都是在一台主机一个 RabbitMQ 应用上。

可是,如今的情况是大部分使用 RabbitMQ 的技术团队每每就使用默认的 vhost:“/”,若是多出一个项目了,就再去建立一个 RabbitMQ 的进程。这样作,很是浪费开发资源。

推荐一个项目对应一个 vhost。

2. 不直接使用 RabbitMQ 本身的客户端

不少公司使用 RabbitMQ 都是直接使用 RabbitMQ 本身的 java 版本客户端,可是因为 RabbitMQ 自己内在的复杂性和多样性,有不少技术细节须要独自处理。

好比网络链接的处理,好比异常的处理,好比消息失败的处理等等等。这些,若是手头没有一套成熟的框架,那么极可能因为一些细节处理不到位,致使很是多的问题,这都是没必要要的成本。

因此,要么使用一套已有的 RabbitMQ 客户端框架(好比 Spring 的 RabbitMQ 框架),要么本身封装出一套底层 RabbitMQ 客户端框架,而不是单独使用 RabbitMQ 的客户端

3. 不管如何消费者必须给回 ACK 响应

ACK 机制就是消费者从 RabbitMQ 收到消息并处理完成后,反馈给 RabbitMQ,而后 RabbitMQ 收到反馈后才将此消息从队列中删除。

因为 ACK 机制自己必须回复给 RabbitMQ,消息才会丢弃这个特色。对于什么时候给 ACK,咱们作开发的时候必定要在开发项目前提早规划好、设计好。

咱们使用 RabbitMQ 一般不想在收到消息就当即给回 ACK 的,也不会设置 autoACK 机制即消费端收到自动返回一个 ACK 响应。通常来说,咱们都会根据业务逻辑的不一样,会在不一样的位置手动返回 ACK。

这时候,就可能出现问题:当收到消息,有时候处理业务逻辑报错了,每每在处理完业务逻辑就会忽略 ACK,这会致使消息始终卡死在 queue 里……若是数量愈来愈多,后续处理很是麻烦。

4. 考虑设置 dead letter exchanges

为何那么多人不设置 dead letter exchanges?这是我很是疑惑的点。

出去和各种使用 RabbitMQ 的项目团队交流,发现不多人设置了 dead letter exchanges。这个是有问题的。

咱们得知道,有时候消息投递出错,并不老是在应用接收的时候出了问题,会有不少非应用的问题。好比:

  1. 消费端有问题,发出的消息被拒绝了。而且咱们也设置了 requeue=false;

  2. 消息可能由于没有收到 ACK 超时被删除,或者消费端消费速度跟不上致使消息超时被删除;

  3. 消息数量超过了队列最大长度限制被抛弃;

  4. 消息总大小超过了队列消息总大小限制被抛弃。

对于这些问题,设置 dead letter exchanges 算是一个解决办法。

当消息一旦出现我上面列举出来的状况,就会被发送到咱们设置的 dead letter exchanges。而后咱们就能够对这些特殊状况的消息进行单独处理,这样的作法可让咱们的项目更健壮,更容易追踪问题。

5. 尽可能使用 Direct Exchange

RabbitMQ 的Exchange 就是消息交换机,它指定消息按什么规则,路由到哪一个队列。

这家伙有四种类型:

  1. Direct:处理路由键,须要将一个队列绑定到交换机上,要求该消息与一个特定的路由键彻底匹配。这是一个完整的匹配。若是一个队列绑定到该交换机上要求路由键为“green”,则只有路由键为“green”的消息才被转发,不会转发路由键为"red",只会转发路由键为“green”。

  2. Topic:将路由键和某模式进行匹配。此时队列须要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”只能匹配一个词。

  3. Fanout:不处理路由键。你只须要简单的将队列绑定到交换机上。一个发送到该类型交换机的消息都会被广播到与该交换机绑定的全部队列上。

  4. Headers:不处理路由键,而是根据发送的消息内容中的 headers 属性进行匹配。在绑定 Queue 与 Exchange 时指定一组键值对;当消息发送到 RabbitMQ 时会取到该消息的 headers 与 Exchange 绑定时指定的键值对进行匹配;若是彻底匹配则消息会路由到该队列,不然不会路由到该队列。

在这四种类型里,Direct 类型的 Exchange 投递消息是最快的。其余的 Exchange,MQ还得花时间计算投递的位置。

因此,能使用 Direct 类型的建议使用 Direct。

以上就是在使用 RabbitMQ 前,须要考虑使用的规范,有了这些规范,不少程序员就能据此写出比较稳定健壮的程序,而不会致使各类莫名其妙的问题。

强烈建议你们在团队使用以前,先弄一份规范。不然,若是不少程序员使用 RabbitMQ 很是随意,容易致使出现各类幺蛾子问题。

在下一篇文章里,我将写一些开发中须要注意的事项。

虽然说是开发须要注意的事项,其实就是我在开发一套成熟的 RabbitMQ 客户端框架时,碰到的各类问题的总结。若是有些读者所在的开发团队刚好也有相似的经历,那么我说的全部问题,你会发现你可能都会遇到。

咱们下篇文章见!

相关文章
相关标签/搜索