.NET Core中的RabbitMQ消费者CPU高,竟然是这个原因

开发 架构
通过一段时间的努力,产品终于支持多租户模式了,测试在做测试的时候发现了一个问题,随着租户数添加的越来越多,RabbitMQ 消费者的 CPU 占用也越来越高。

在 RabbitMQ 中有一个 vhsot 机制,可以用来做租户隔离,当产品从单租户演化为多租户时,正好可以用到这个特性,不同 vhost 中的交换机、队列互不影响。

起初在产品中引入 RabbitMQ 的时候,版本如下:

  • RabbitMQ:3.7.2 (后来升级为 3.8.2)。
  • RabbitMQ Client:5.1.2。
  • .NET Core:3.1。

通过一段时间的努力,产品终于支持多租户模式了,测试在做测试的时候发现了一个问题,随着租户数添加的越来越多,RabbitMQ 消费者的 CPU 占用也越来越高。

100 左右的租户数,每个租户队列大概 10 几个,这时 CPU 占用稳定在 50% 左右,即使系统没有任何人访问。

分析下可能的原因:

  • 因产品比较复杂,可能是其代码影响到。
  • 可能是 RabbitMQ 的参数问题。
  • 可能是 .NET Core 中的驱动的问题,可以尝试下 Java 。

正式进入问题的排查。

简单示例

1、在 .NET Core 3.1 中编写一个简单的 RabbitMQ 示例:

public void Start()
{
Console.WriteLine("App Start...");
_defMqConfig = new MQConfig()
{
MQAutomaticRecoveryEnabled = true,
MQHeartBeat = 5,
MQNetworkRecoveryInterval = 5,
MQVHost = "/",
MQHostName = _mqHostName,
MQUserName = _mqUserName,
MQPassword = _mqPassword,
MQPort = _mqPort,
MQServerPort = string.IsNullOrEmpty(_mqServerPort) ? $"1{_mqPort}" : _mqServerPort
};
Console.WriteLine(" MQ vhost init Start...");
string prefix = "testhost";
for (int i = 0; i < 200; i++)
{
string vhost = $"{prefix}{i}";
InitAllVhost(vhost);
Console.WriteLine($" 初始化vhost:{vhost}...");
}
Console.WriteLine(" MQ vhost init Done...");
Console.WriteLine("App Start Done...");
}
private void InitAllVhost(string vhost)
{
string url = $"http://{_mqHostName}:{_mqServerPort}";
_mqManager.AddVirtualHost(url, vhost, _mqUserName, _mqPassword);

_defMqConfig.MQVHost = vhost;
_mqManager.Subscribe(_defMqConfig);
}

2、监听的代码如下:

public void Subscribe(MQConfig engineConfig)
{
var factory = new ConnectionFactory();
factory.HostName = engineConfig.MQHostName;
factory.UserName = engineConfig.MQUserName;
factory.Password = engineConfig.MQPassword;
factory.VirtualHost = engineConfig.MQVHost;
factory.RequestedHeartbeat = (ushort) engineConfig.MQHeartBeat;
factory.AutomaticRecoveryEnabled = true;
factory.NetworkRecoveryInterval = new TimeSpan(engineConfig.MQNetworkRecoveryInterval);
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.QueueDeclare("TestQueue", false, false, false, null);
channel.ExchangeDeclare("TestQueueExchange", ExchangeType.Direct, false, false, null);
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume("TestQueue", false, consumer);
channel.QueueBind("TestQueue", "TestQueueExchange", "TestQueueExchange");
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("已接收: {0}", message);
};
}

3、上面代码创建了 200 个 vhost ,每个 vhost 中 1 个队列,程序运行后观察 cpu 如下图:

图片

4、在 Subscribe 方法中有创建 Connection 和 CreateModel 方法,如果使用 using 或在方法最后对其进行释放,CPU 会是一个正常的状态,但消息也就接收不到了。

调整参数

1、在 RabbitMQ 中有两个参数 MQHeartBeat、MQNetworkRecoveryInterval :

  • MQHeartBeat:心跳检测
  • MQNetworkRecoveryInterval:掉线重连

2、不断调整这两个参数的值,进行尝试,发现 CPU 并没有明显改善。

尝试 Java

当没有什么头绪的时候,就会采用各种方式进行尝试,来排除问题,所以决定用 Java 试试。

在 Java 程序中,使用的 RabbitMQ 客户端为 rabbitmq-java-client ,版本为 5.14.2 ,因为之前在 .NET 程序验证时已经创建了 vhost ,所以在 Java 程序中只写了消费者进行监听。

当 Java 程序跑起来的时候,发现 CPU 占用是正常的,在遍历 vhost 监听的过程中 CPU 有所波动,遍历完后 ,CPU 占用比较稳定。

真正的原因

这时基本可以确定,是 .NET Core 的 RabbitMQ 客户端的问题,到这时才想起有可能是 .NET Core  RabbitMQ 客户端的版本问题,检查发现目前使用的版本是 5.1.2,而最新的版本为 6.3.0 。

升级 .NET Core RabbitMQ 到最新版本,升级后有两个地方不兼容:

  • RequestedHeartbeat 类型变成了 TimeSpan。
  • 接收的消息由 byte[] 变成了 ReadOnlyMemory类型。

图片

修改这两处后,赶紧运行进行测试,CPU 终于正常了。

查看了下 RabbitMQ 客户端在 GitHub 上的更新记录,发现在版本 6.2.4 中有修复一个关于连接的 Bug:

图片

又继续将版本回退到 6.2.3 进行测试,问题又能重现了,就更加确定了这个问题是在 6.2.4 中解决了。

最后

现在无论是做项目还是做产品,都会使用很多中间件,这些中间件和相关的库也是在不断地更新迭代的,当我们进行功能迭代的同时,也需要关注这些中间件的发展,在新的版本中提供了什么新特性,修复了什么问题,这给我们是否升级提供依据。

责任编辑:姜华 来源: 今日头条
相关推荐

2024-09-27 11:38:49

2021-10-18 13:42:52

加密货币金融工具

2022-07-07 19:44:22

Python 3.1

2016-10-25 21:00:27

云计算

2017-11-03 09:10:48

2024-09-30 09:48:41

RabbitMQ消息中间件

2019-02-12 14:53:44

物联网设备物联网IOT

2009-07-15 19:51:01

AMD六核CPU服务器

2020-08-19 09:23:10

传输网络WDM网络技术

2020-09-29 06:45:49

JDK

2020-11-03 09:14:30

编程语言Go技术

2015-06-18 11:04:58

2020-12-15 08:05:40

路由器服务器网络层

2021-07-28 06:51:08

Nacos代理模式

2018-06-23 13:49:56

苹果谷歌手机

2024-08-05 01:28:26

2022-11-15 07:35:50

Spring事件观察者模式

2023-02-12 21:47:47

NacosRabbitMQ消费者

2023-06-01 08:08:38

kafka消费者分区策略

2023-03-13 08:09:03

Protobuffeature分割
点赞
收藏

51CTO技术栈公众号