当前位置: 首页 > 科技观察

.NETCore中RabbitMQ消费者的CPU很高,这就是为什么

时间:2023-03-12 13:11:03 科技观察

RabbitMQ中有一个vhsot机制,可以用于租户隔离。当产品从单租户演进到多租户时,可以使用这个特性,不同vhost中的交换机和队列互不影响。RabbitMQ最初引入产品时,版本如下:RabbitMQ:3.7.2(后来升级到3.8.2)。RabbitMQ客户端:5.1.2。.NET核心:3.1。经过一段时间的努力,产品终于支持了多租户模式。在测试过程中,发现了一个问题。随着租户数量的增加,RabbitMQ消费者的CPU使用率越来越高。租户数量约100个,每个租户约有10个队列。此时CPU使用率稳定在50%左右,即使没有人访问系统。分析可能的原因:因为产品比较复杂,可能是受其代码的影响。可能是RabbitMQ的参数问题。可能是.NETCore的驱动问题,你可以试试Java。正式进入问题排查。简单示例1.在.NETCore3.1中编写一个简单的RabbitMQ示例:publicvoidStart(){Console.WriteLine("AppStart...");_defMqConfig=newMQConfig(){MQAutomaticRecoveryEnabled=true,MQHeartBeat=5,MQNetworkRecoveryInterval=5,MQVHost=“/”,MQHostName=_mqHostName,MQUserName=_mqUserName,MQPassword=_mqPassword,MQPort=_mqPort,MQServerPort=string.ServerIsNullOrEmpty$“1{_mqPort}”:_mqServerPort。}r("MQvhostinit开始...");字符串前缀=“测试主机”;for(inti=0;i<200;i++){stringvhost=$"{prefix}{i}";InitAllVhost(vhost);Console.WriteLine($"初始化vhost:{vhost}...");}Console.WriteLine("MQvhost初始化完成...");Console.WriteLine("AppStartDone...");}privatevoidInitAllVhost(stringvhost){stringurl=$"http://{_mqHostName}:{_mqServerPort}";_mqManager.AddVirtualHost(网址,虚拟主机,_mq用户名、_mq密码);_defMqConfig.MQVHost=虚拟主机;_mqManager.Subscribe(_defMqConfig);}2、监听的代码如下:publicvoidSubscribe(MQConfigengineConfig){varfactory=newConnectionFactory();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=newTimeSpan(engineConfig.MQNetworkRecoveryInterval);varconnection=factory.CreateConnection();varchannel=connection.CreateModel();channel.QueueDeclare("TestQueue",false,false,false,null);channel.ExchangeDeclare("TestQueueExchange",ExchangeType.Direct,false,false,null);varconsumer=newEventingBasicConsumer(channel);channel.BasicConsume("TestQueue",false,consumer);通道.队列Bind("TestQueue","TestQueueExchange","TestQueueExchange");consumer.Received+=(model,ea)=>{varbody=ea.Body;varmessage=Encoding.UTF8.GetString(body);Console.WriteLine("收到:{0}",消息);};}3.上面的代码创建了200个虚拟主机,每个虚拟主机有1个队列。程序运行后,观察cpu如下图:4.在Subscribe方法中创建Connection和CreateModel方法,如果在方法最后使用using或release,CPU会处于正常状态,但不会收到消息。调整参数1、RabbitMQ中有两个参数MQHeartBeat和MQNetworkRecoveryInterval:MQHeartBeat:心跳检测MQNetworkRecoveryInterval:断开重连2、不断调整这两个参数的值,尝试发现CPU并没有明显提升。试试Java当你毫无头绪时,你会尝试各种方法来解决问题,所以你决定用Java试试。Java程序中,使用的RabbitMQ客户端为rabbitmq-java-client,版本为5.14.2。因为.NET程序校验时已经创建了vhost,所以在Java程序中只写了consumer来监控。Java程序运行时,发现CPU占用正常。在遍历vhostmonitor的过程中,CPU有波动。遍历之后,CPU占用比较稳定。真正的原因这个时候就可以基本确定了。这是.NETCore的RabbitMQ客户端的问题。这才意识到可能是.NETCoreRabbitMQ客户端的版本问题。查看后发现目前使用的版本是5.1.2,最新的版本是6.3.0。将.NETCoreRabbitMQ升级到最新版本。升级后有两个不兼容的地方:RequestedHeartbeat类型变成了TimeSpan。接收到的消息由byte[]类型更改为ReadOnlyMemory类型。修改这两个地方后,快速运行测试,CPU终于正常了。查看了GitHub上RabbitMQ客户端的更新记录,发现6.2.4版本修复了一个关于connection的bug:并继续回滚版本到6.2.3进行测试,问题可以再次重现,更加确认这个问题在6.2.4中得到解决。最后,不管我们做项目还是做产品,都会用到很多中间件。这些中间件和相关库是不断更新迭代的。我们在进行功能迭代的时候,也需要关注这些中间件的开发。在新版本中提供了哪些新功能,修复了哪些问题,为我们升级提供了依据。