干货 | QMQ在携程的落地实践

本文介绍了QMQ在携程的落地过程中遇到的网络和磁盘IO问题,包括OOM、文件句柄耗尽、Broker未被摘除、SocketTimeoutException、大流量挑战以及堆积消息拉取和大消息处理。通过案例分析,提出了解决方案,强调了系统回压机制和磁盘IO优化的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者简介

 

Magiccao,携程软件开发工程师,热衷网络、操作系统相关技术。

QMQ(Qunar Message Queue)诞生于去哪儿网,初版基于MySQL存储。随着集团业务系统越发倚重消息解耦上下游,业务量的上涨随之带来消息量的增长,MySQL作为存储的瓶颈也越发明显。

比较自然的解决方案有两个:1)分库分表;2)换存储。与业界众多出名的消息队列(Kafka、RocketMQ、Pulsar等)一样,QMQ也走上了基于文件存储的分布式消息系统自研之路(详细设计请关注QMQ开源:https://github.com/qunarcorp/qmq)。后文的介绍, QMQ均指基于文件存储的版本。

       

在携程落地的过程中,我们主要和两类问题打交道:网络和磁盘IO。


一、网络

       

网络问题多种多样,因而也诱发了一系列问题,和大家分享5种比较典型的场景。


1.1 OOM

       

场景来自某台Broker slave机器OOM告警,问题出在堆外内存分配上,图1是堆外内存泄露现场。QMQ网络通信基于netty开发,接收消息时使用堆外内存;拉取消息时,使用FileRegion和少量堆内内存;slave从master同步消息文件,使用FileRegion。FileRegion直接将消息文件写入到发送缓冲区,不会分配堆外内存,排除。接收消息放入Receiver队列,如果消息落磁盘操作阻塞,消息积压在队列(没有回压机制,而channel是auto read的,只要有消息进来,就会不停的放入队列),势必引发堆外内存上涨,但只有master提供消息服务,排除。

图1 OOM时堆外内存泄露现场

       

引起关注的是稳定的增长速率:300MB/分钟,即50MB/10秒。50MB是个特殊的数字,我们有一个消息索引备份服务,会实时从slave上拉取消息索引,我们设置了每次拉取的上限。10秒则是索引备份服务请求的超时时间。如果,备份服务的请求抵达slave,slave实时计算了索引、分配了内存,但数据未被备份服务接收,10秒后超时,重试。似乎一切都能解释了,查看了当时的备份服务的日志(图2所示),吻合。

图2 备份异常日志

       

备份服务和slave是tcp单连接通信,备份服务和slave是一对一关系,当slave上tcp连接的发送缓冲区满了后,索引数据的网络写入会感知到失败,我们的服务应该是能感知到才对。原来,FileRegion的操作,不会影响netty的水位线,因而代码中没有做channel.isWritable的判断就直接channel.writeAndFlush了。后面因为需求,增加了slave实时计算索引的功能,复用了以前的代码,导致数据积压在netty的OutboundBuffer中,从而引发了堆外内存泄露。至于备份请求能到slave,响应未能从slave送出去,是网络故障导致。

       

结论:netty write操作前,须判断isWritable。


1.2 文件句柄耗尽

       

场景来自客户端与MetaServer 新建tcp连接失败的告警。图3是某一台MetaServer的网络连接现场。tcp连接是需要分配文件句柄的,机器上设置的最大可用文件句柄为65536,显然tcp建连失败,是因为此机器上的文件句柄耗尽导致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值