一天,阿强接到一个需求,将公网的服务的执行结果通知到内网的服务上。阿强一想,很简单阿,只要在公网搭一个简单的消息服务,给公网系统提供一个存储消息接口;给内网系统提供一个查询消息接口,消息存在 mysql。内网服务跑个定时器,轮询查询接口。他麻溜的搭好服务,实现业务并通过自测。嗯,奈斯。
这个项目的负责人阿明同学,看了阿强的实现,认为添加新服务增加维护部署成本,轮询每次都要查询数据库降低性能,推荐使用 RabbitMQ,并说服了阿强。 阿强用 docker 启动一个单节点的 RabbitMQ,在管理台进行配置。之前他没用过 RabbitMQ,对配置中 Virtual host,exchange,routing key,queue,channel,connection 的概念很模糊,不知道怎么配置使用。既然阿明提议用 RabbitMQ,他一定比较了解,还是问他吧。 阿强:exchange,queue,routing key 是什么呢,怎么理解,配置? 阿明:MQ 的生产者将消息发到 queue 中,消费者监听 queue,获得消息。exchange 用来管理多个 queue,举个例子,一个消息要发给两个 queue,我们可以建一个 exchange,绑定这两个 queue,给 exchange 发消息,exchange 会给这两个 queue 发消息,不用给一个个 queue 发消息。routing key 的意义是给 exchange 绑定的 queue 分类。举个例子, exchange 绑定了多个 queue ,要给其中两个 queue 发消息,给这两个 queue 设置一个的 routing key,生产者向该 routing key 发消息。不设置 routing key 时,routing key 就是 queue 的名称。我们项目需求很简单,建一个 queue,公网系统发送结果给这个 queue ,消费监听这个 queue,可以不用配置 exchange 和 routing key。 阿强:用法上和你说的有些不一致额,我没有创建 exchange 和 routing key,只创建 queue。但是生产者发送消息调用的 API 需要指定 exchange 和 routing key,没有 queue 的参数,这里应该怎么传参?
代码语言:javascript复制# 生产者
import pika
credentials = pika.PlainCredentials('test', 'test123')
connection = pika.BlockingConnection(pika.ConnectionParameters('xx', '5672', '/', credentials))
channel = connection.channel()
channel.queue_declare(queue='testQ')
channel.basic_publish(exchange='', routing_key='', body='Hello World!')
connection.close()
代码语言:javascript复制// 消费者
@Component
@Slf4j
public class MQReceiver {
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "testQ", durable = "true"),
exchange = @Exchange(value = "", type = ExchangeTypes.DIRECT),
key = "")
)
public void onCi(@Payload String request) {
log.info("MQ receiver msg : {}", request);
}
}
阿明:在 RabbitMQ 创建的 queue,会默认绑定一个空名的 exchange。所以你配置 exchange 名为 空,routing_key 为 queue 的名字就好了。
阿强:Soga,大佬厉害。用户和资源授权怎么理解和配置?
阿明:RabbitMQ 可以添加用户,用户可以配置它三种权限,Configure,Write,Read,Configure 是配置权限,创建 queue 就是配置权限,Write/Read 就是读写权限。在管理页面上,配置 Configure regexp 上配置 'abc.’,这个 user 就只能创建,删除 abc 开头的 queue 或 exchange,读写配置也是这样。
阿强:真是粗暴简单。我配置 Configure regexp 和 Write 为 ab.,创建一个 ab123 的 queue 并发送消息,但是 queue 创建成功,消息没有发送。
阿明:你需要加上默认 exchange,要这样写 (ab.*|amq.default)
。
阿强:Virtual host 该怎么理解?
阿明:Virtual host 是用于数据隔离,赋予用户一个 Virtual host 的权限,那它只能访问其下的 queue 和 exchange,不能访问其他 Virtual host 下的。
阿强:那 connection 和 channel 呢?
阿明:这个是消费者连接 MQ 的连接,不用配置,只要连接上就会多一个。
阿强:原来这么回事,功能通过测试了,谢谢大佬。
说服阿强的小剧场 阿明:每次轮询都会在数据库查询没有执行结果的 requestID,影响性能;增加一个通知服务和一个公网数据库,存在两个服务需要部署维护,部署的客户越多维护成本大。建议换成一个开源消息队列 RabbitMQ。 阿强不太想修改,一则不熟悉 RabbitMQ,二则不想花功夫返工,于是想到一个理由。 阿强:使用 mq,确实会提升性能,减少维护成本。不过我担心后期多租户业务,需要对通知服务增加一些业务鉴权,使用自己的服务能记录下每次通知结果,方便追溯,后期存在多租户相关业务,也好扩展。目前一期给内部人员使用,不用担心性能损耗。我认为通知服务还是要,可以后期通知服务再对接一个 MQ,优化性能。 阿明:个人经验多租户等扩展功能并不知道什么时候才能上,暂时不用考虑。通知服务业务如果遇到问题还要问你,以后不能每次上线前都喊你解决问题吧。 阿强听出这个版本要用很久,考虑到长时间都有找自己麻烦的可能性,加之能借机了解一下 RabbitMQ, 同意切换。 阿强:你说的对,我把它切成 RabbitMQ。 大家皆大欢喜。