RabbitMQ C# 驱动程序导致 System.AccessViolationException
Posted
技术标签:
【中文标题】RabbitMQ C# 驱动程序导致 System.AccessViolationException【英文标题】:RabbiMQ C# driver Causes System.AccessViolationException 【发布时间】:2017-05-31 11:34:15 【问题描述】:我们有一个 ASP.Net WebAPI 2.0 应用程序,可以将消息发布到我们的 RabbitMQ 服务器。在 99% 的情况下,一切都很好……但随机地,应用程序以 System.AccessViolationException 无故终止。
如何防止这种失败?会不会与我们最近升级到 3.6.6 C# 驱动有关(升级前它运行良好)?
我已经消除的东西:
-
每次发布都使用一个新的
IModel
(我知道IModel
不是线程
安全)
每次通话都会拨打CreateConnection
(我
知道我可以重用连接,但我们目前没有)。连接是AutoClose = true;
Channel 用在 using 块中...所以每次都被释放
这里是它爆炸位置的示例堆栈跟踪:
异常详情
System.AccessViolationException
试图读或写保护 记忆。这通常表明其他内存已损坏。
在 System.Net.UnsafeNclNativeMethods.SafeNetHandlesXPOrLater.GetAddrInfoW(String nodename, String servicename, AddressInfo& 提示, SafeFreeAddrInfo& 处理) 在 System.Net.Dns.TryGetAddrInfo(字符串名称、AddressInfoHints 标志、IPHostEntry& 主机信息) 在 System.Net.Dns.InternalGetHostByName(字符串主机名,布尔值 includeIPv6) 在 System.Net.Dns.GetHostAddresses(字符串主机名或地址) 在 RabbitMQ.Client.TcpClientAdapter.BeginConnect(字符串主机,Int32 端口,AsyncCallback requestCallback,对象状态) 在 RabbitMQ.Client.Impl.SocketFrameHandler.Connect(ITcpClient 套接字,AmqpTcpEndpoint 端点,Int32 超时) 在 RabbitMQ.Client.Impl.SocketFrameHandler..ctor(AmqpTcpEndpoint 端点,Func`2 socketFactory,Int32 connectionTimeout,Int32 读超时,Int32 写超时) 在 RabbitMQ.Client.Framing.Impl.ProtocolBase.CreateFrameHandler(AmqpTcpEndpoint 端点,Func'2 socketFactory,Int32 connectionTimeout,Int32 读超时,Int32 写超时) 在 RabbitMQ.Client.ConnectionFactory.CreateConnection(IList'1 端点,字符串 clientProvidedName)
还有一个
System.Net.UnsafeNclNativeMethods+SafeNetHandlesXPOrLater.GetAddrInfoW(System.String, System.String,System.Net.AddressInfo ByRef, System.Net.SafeFreeAddrInfo ByRef) System.Net.Dns.TryGetAddrInfo(System.String, System.Net.AddressInfoHints, System.Net.IPHostEntry ByRef) System.Net.Dns.InternalGetHostByName(System.String, Boolean) System.Net.Dns.GetHostAddresses(System.String) RabbitMQ.Client.TcpClientAdapter.BeginConnect(System.String,Int32,System.AsyncCallback,System.Object) RabbitMQ.Client.Impl.SocketFrameHandler.Connect(RabbitMQ.Client.ITcpClient, RabbitMQ.Client.AmqpTcpEndpoint, Int32) RabbitMQ.Client.Impl.SocketFrameHandler..ctor(RabbitMQ.Client.AmqpTcpEndpoint, System.Func'2, Int32, Int32, Int32) RabbitMQ.Client.Framing.Impl.ProtocolBase.CreateFrameHandler(RabbitMQ.Client.AmqpTcpEndpoint, System.Func'2, Int32, Int32, Int32) RabbitMQ.Client.ConnectionFactory.CreateConnection(System.Collections.Generic.IList'1, System.String)
【问题讨论】:
【参考方案1】:我不确定您的错误发生的确切原因我需要查看您的一些代码,但我使用 RabbitMQ 并发布我使用这样的类:
(更改了一些与您的情况无关的部分,例如加密,压缩等。但这将是它的基本格式)
using System;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Framing;
namespace Messaging
public class MessageSender : IDisposable
private const string EXCHANGE_NAME = "MY_EXCHANGE";
private readonly ConnectionFactory factory;
private readonly IConnection connection;
private readonly IModel channel;
public MessageSender(string address, string username, string password)
factory = new ConnectionFactory UserName = username, Password = password, HostName = address;
connection = factory.CreateConnection();
channel = connection.CreateModel();
channel.ExchangeDeclare(EXCHANGE_NAME, "topic");
public void Send(string payload, string topic)
var prop = new BasicProperties();
var data = Encoding.ASCII.GetBytes(payload);
channel.BasicPublish(EXCHANGE_NAME, topic.ToUpper(), prop, data);
public void Dispose()
try
channel.Dispose();
connection.Dispose();
catch (Exception e)
Console.WriteLine(e);
这个想法是让您发出多个调用或单个调用,并在您愿意时处理类。用 using 语句和你的集合包装它。
在使用它大约 3-4 年的时间里,从未遇到过任何问题,因此您可以将其与您的代码进行对比以找出差异。
【讨论】:
感谢您的意见。 我们的实现不会每次都创建一个新的“Sender”类,但我们确实将 Channel 包装在 using 中。 作为记录,我的实现也已经运行了 3 年,没有任何问题...最近才开始失败。可能是我刚升级到(3.6.6)的驱动版本有bug 你运行的是什么版本的 RabbitMQ。我们发现了 3.6.4 的几个问题。主要问题是心跳导致客户端出现故障并会中断连接。 (根据补丁说明,我相信在 3.3.6 中已修复)根据您的错误处理,这可能是它。仅通过 Windows 事件日志注意到它,该日志将错误列为源自 .NET rabbitmq 客户端,问题是“心跳”。【参考方案2】:设法从 RabbitMQ 用户组获得(部分)解决方案。
详情请看:Rabbit MQ Users Group
基本思想是应该共享 IConnection 对象,因为打开和关闭它很重。只有 IModel 应该为每个线程重新打开
【讨论】:
以上是关于RabbitMQ C# 驱动程序导致 System.AccessViolationException的主要内容,如果未能解决你的问题,请参考以下文章
无法连接到在 C# 程序中使用 Docker 启动的 RabbitMQ(使用 RabbitMQ.Client)
将带有参数的 c# 回调方法传递给 c++ dll 会导致 System.ExecutionEngineException
搭建高可用的Rabbitmq集群 + Mirror Queue + 使用C#驱动连接