消息中心消息性能(削峰),查问题,业务封装难易度

xzdxmynet 发布于 2024-04-26 阅读(25)

前言

消息队列有上千种,比如kafka等,网上有很多文章分析这些mq的源码。 然而实际上,对于普通开发者来说,他们更关心的并不是这些mq的内部实现,而是如何封装它们,如何调用它们的api。 对于简单的发送和接收消息来说,mq的直接区别其实并没有想象中的那么大。 那么今天我们就来看看性能(削峰)以及检查问题、分布式事务、业务封装的易用性、链路跟踪、监控等。我们先来看看两种主流的mq封装以及各自实现的逻辑有何不同功能。

本地直连mq

第一种形式是直接将mq客户端jar包引入到典型业务代码中。

远程代理连接mq

有极少数单位不把发送和接收消息的代码和业务放在一起,而是单独作为一个独立的消息中心。 然后业务调用这个服务,这个服务再调用mq。 同时这个服务自己订阅mq,然后拿到服务后,调用消费者业务。 在这种形式下,消息中心的消息一般会被放入数据库中。

了解了两种不同的设计形式之后,我们再来看看这两种设计。 各方面有何差异? 这里一定要注意,任何设计都有优点和缺点,一定要合理对待~

消息发送和接收性能

事实上,从上图可以看出,本地直连mq的性能要优于代理连接mq。 使用代理连接 mq 会导致额外的网络开销,并且必须访问数据库。 这里的表现非常弱。 ,使用代理发送消息的代码,我之前测过,tps只能是4G左右的双核服务器,原生mycat,在线的还有几个。 也许普通公司用异步逻辑还是可以的,但是需要在千万级并发面前肯定是势不可挡的。 同时,消费者消费的时候,因为还需要调用业务,记录消费结果,所以这里的性能也被消耗了。 因此,对于消息量较大的场景,还是推荐本地直连mq~

mq集群部署和消息可靠性

我看过很多关于mq集群的文章,里面都提到了mq消息的主从同步。 其实这种情况是针对客户端直连的情况。 如果我们不在本地存储消息,那么消息的可靠性谁来保证? 来保证? 如果消息丢失了怎么办? 是的,只能通过mq自己的集群来保证。 这里涉及到很多知识,比如kafka的备份分片机制,slave节点机制的备份机制等。 这里还有一个配置叫是否绝对可靠。 简单来说,消息必须发送到所有备份分片/备用节点后才能成功发送。 当然,今天的文章不是来聊这个的。

远程代理的形式并没有那么复杂,因为消息是在代理中落入数据库的,所以mq只是一个通知功能。 mq 不需要集群。 如果消息在 mq 中丢失,我将启动一个计时器,将未见过的消息保存在数据库中。 只需检索已消费的消息并重试即可。 当然,这种对数据库的性能消耗也是非常严重的。 。 。 。 。

综上所述,mq本地直连对mq集群的可用性要求较高。 代理形式对数据库性能的可用性要求很高,而且代理对数据库分库、表也有要求,所以不好说哪一种特别好。 我只能说,技能不同。 不同的地方有不同的困难。

解决日常问题

在我遇到的所有mq问题中,问得最多的问题就是为什么消息没有被消费?这里有很多种情况,比如

显然消费还没有发出去

消息被消费了,但是业务消费失败,而其他人却认为消费成功。

消息确实丢失了。 。 。 。 (我以前从未遇到过这种情况)

。 。 。 。 。 。

如果是本地直连mq的设计,排除机制完全取决于mq本身的消息查询机制。 也就是说,你使用的 mq 控制台必须有一个根据消息 id 或消息 key 查询消息的接口。 采用这种设计的MQ在存储消息时必须在消息索引文件中存储一个消息ID或者消息key,因为如果只是为了发送和消费,实际上索引中只放置消息和消息文件的行位置文件。 就是这样,我知道目前最多的消息索引内容就是它可以原生支持各种消息查询。

服务器连接mq时,由于消息是放在磁盘上的,并且消息被消费后修改了消息状态,所以问题非常容易排查,大大节省了开发和排查的成本。这也是最大的代理连接到 mq 的优点。 很容易检查问题。

分布式交易

消息队列除了最大的作用就是消峰之外,第二个用途就是解决分布式事务问题。 目前国际上消息队列的分布式事务主要分为Kafka中多条消息的一致性,以及消息和本地事务一致性两种。

对于本地直接连接mq的系统来说,能否支持上述两个消息中间件的分布式事务完全取决于mq本身。 多条消息的一致性要求mq本身有假发送和最终确认接口。 消息和本地事务的一致性要求mq有预发送、确认发送、取消发送接口,以及最重要的回调接口。 不管是哪一个,mq本身都需要携带这些。 如果你使用的mq不支持分布式事务或者是本地直连的,那么你只能更改mq。

对于代理连接mq的情况,可以忽略mq的这些方面,因为对于业务系统来说,使用代理形式意味着调用代理的步骤被视为发送消息,而代理可以封装这些功能通过它自己。 您不需要依赖 mq。 这就是代理机构灵活的地方。 但越是灵活,就越容易出错。 您可以自己封装回调和一致性接口。 如果写错了怎么办? 哈哈,这也是有代价的。

消息迁移

上面说了,改变mq,那么问题又出现了,消息如何迁移? 其实我不妨告诉大家,我工作过的公司都遇到过消息迁移的问题。 例如,当mq迁移到云端时,我们需要将我们原来的在线mq切换到在线云mq。 比如我们原来用mq,后来改用kafka。

对于本地直连mq的设计来说,这其实是一个关键点。 双启用mq消费者端的监控。 因为我从mq A切换到mq B,可能会出现mq A还有未消费消息的问题。 当系统很大,topic很多的时候,有可能只迁移一部分topic,所以这里的方法是在consumer端同时开启两个不同的mq监控。 一般来说,客户端直连的方法就是切换mq。 对于一个非常大的项目,生产者业务和消费者业务必须沟通良好。 这与技术无关,而与商业有关。 如果生产者向新的mqB发送消息,但消费者端没有双开,那么也需要更改配置。 。 。 并依靠监控。 。 。 。 。

对于代理连接mq的设计,因为mq只和代理相关,所以这里很无脑,直接砍掉即可。 。 。 。 。 是的,你没有看错。 你可以不假思索地直接切换到新的mq,但是你必须有两个定时器。 一种是针对尚未消费、将重新发出的消息的计时器。 另一个是定时器,用于未达到最大权重的消费重试。 尝试次数继续重试计时器。 这两个定时器在切换之前必须存在。 同时,如果消息量很大,系统中有很多消息没有被消费,数据库里有几百万、几千万条消息。 这还会涉及到分库性能、调度设计、MQ的抗压能力等。

综上所述,前者需要大量的业务沟通成本,而后者则是对系统性能的考验。 也有优点和缺点。

监控 mq

总的来说,mq的监控无非就是这么几个点。 某个topic消费者没有监听者,某个topic有大量消息堆积,mq挂起,消息消费重试次数过多失败(特别是mq自带的重试机制)

对于本地直连 mq 的系统,这些逻辑需要调用 mq admin 接口获取主题列表,然后调用 mq 接口查看这个主题的累积情况。 无论mq是否挂掉,你都可以查看端口或者自发关闭。 心跳消息等,这是一个主要依赖mq的接口。 这种接口一般mq都有,否则本地直连mq就成了伪命题。

以代理连接mq为例,监控mq时可以使用定时器进行扫表。 为什么? 一是数据表中的信息会非常完整,向业务报错会更加友好,二是如果做了mq迁移。 。 。 。 。 这些监视定时器不需要更改。 。 。 。 。 。 当然,代理类更重要的是它需要做一个额外的监控,即代理本身需要备货。 如果所有的代理都宕机了,对于业务来说,所有的mq都宕机了,所以这里需要添加一个代理服务监控。

链接追踪

链接跟踪和两者没有区别。 两者都需要在框架层为消息主体提供一个字段。 无论你重新打包一个消息体对象还是其他东西,客户端直连都是在jar包中做这个逻辑的。 代理连接还在代码的客户端执行此操作。 没有不同。

消息发送失败

在本地直连mq的设计中,一般来说,都是将消息存储在本地文件中,然后代码开启一个线程重试。 如果是代理,则将发送失败状态的消息状态更新到数据库,然后定时器进行补偿。

事实上,仅从发送失败的情况来看,两种形式并没有太大的区别。 这就是本地和数据库的区别。 一般情况下,发送失败的时候,要么是mq挂了,要么是连接建立速度慢。 如果 mq 挂了,就会切换到另一个。 在当前主题路由的机器上,一般不太可能出现几千万条消息同时发送失败而落入数据库或者本地的情况。

发送失败的容器化处理

容器化现在很流行,但是容器化的一个特点是,每次启动进程时,IP都会发生变化。 很有可能你进入容器后,这次落盘的数据下次启动后就找不到了。 请注意,对于本地直连,最好有一个独立的进程,可以持续处理本地文件中的消息。 当然,agent端的消息是放在数据库中的,所以不需要考虑容器的影响。 这里请求头数据的读取主要分为以下几个步骤:

三、总结

讲解了读取和解析请求头的过程,重点讲解了读取数据的主要流程代码以及读取的详细步骤。

标签:  mq 数据库 科技新闻 

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。