【问题标题】:RabbiMQ C# driver Causes System.AccessViolationExceptionRabbitMQ C# 驱动程序导致 System.AccessViolationException
【发布时间】:2017-05-31 11:34:15
【问题描述】:

我们有一个 ASP.Net WebAPI 2.0 应用程序,可以将消息发布到我们的 RabbitMQ 服务器。在 99% 的情况下,一切都很好……但随机地,应用程序以 System.AccessViolationException 无故终止。

如何防止这种失败?会不会与我们最近升级到 3.6.6 C# 驱动有关(升级前它运行良好)?

我已经消除的东西:

  1. 每次发布​​都使用一个新的IModel(我知道IModel不是线程 安全)
  2. 每次通话都会拨打CreateConnection(我 知道我可以重用连接,但我们目前没有)。连接是AutoClose = true;
  3. 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)

【问题讨论】:

    标签: c# asp.net-web-api rabbitmq


    【解决方案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 应该为每个线程重新打开

    【讨论】:

      猜你喜欢
      • 2015-11-19
      • 1970-01-01
      • 1970-01-01
      • 2019-09-08
      • 1970-01-01
      • 2011-09-05
      相关资源
      最近更新 更多