记一次rabbitmq队列阻塞

一,问题

通过rabbitmq可视化界面看到其中有一个队列未消费数量有5万多,而且在持续增加中

二,分析

1,上网了解了rabbitmq原理后,从未消费的队列中看到unacked一直没有变化,而consumers中有存在消费者,所以应该是程序有收到消息,却一直卡主,没有返回ack给rabbitmq。

2,通过不断测试后发现,程序中确实有一个会发生堵塞地方,就是tcp链接中readline方法。每当有远程主机断开强制断开连接时,有几率发生readline一直堵塞,具体原因未知

三,解决问题

知道了原因,就好解决了,

解决方法1:目前未找到微软有提供的流读取操作有超时设置的地方,因此暂时自己先弄一个线程来对操作进行超时限制,实现如下

        /// <summary>
        /// 超时处理
        /// </summary>
        /// <param name="time">超时时间,单位毫秒</param>
        /// <param name="func">发生堵塞的方法</param>
        /// <returns></returns>
        public static Tuple<bool, string> TimeOutCommand(int time, Func<string> func)
        {
            var cts = new CancellationTokenSource();
            var token = cts.Token;
            var task = Task.Factory.StartNew(() =>
            {
                try
                {
                    using (token.Register(Thread.CurrentThread.Interrupt))
                    {
                        return func();
                    }
                }
                catch (Exception)
                {

                }
                return string.Empty;
            });

            var result = string.Empty;//结果
            var loop = 100;//等待时间,单位毫秒
            var waitTime = 0;//已经等待时间
            bool flag = task.Wait(1);//是否执行成功

            while (!flag)
            {
                waitTime += loop;
                flag = task.Wait(loop);

                if (!flag)
                {
                    if (waitTime > time)
                    {
                        try
                        {
                            cts.Cancel();
                        }
                        catch (Exception)
                        {

                        }
                        break;
                    }
                }
            }

            if (flag)
            {
                result = task.Result;
            }

            return new Tuple<bool, string>(flag, result);
        }

  

解决方法2:使用TcpClient,设置ReceiveTimeout和SendTimeout超时时间就行

/// <summary>
        /// 连接远程服务器
        /// </summary>
        public void ReConnect()
        {
            if (this.LocalEndPoint != null && this._tcpClient != null)
            {
                this.Dispose();
            }
            try
            {
                this._tcpClient = new TcpClient(this._host, this._hostPort);
                this._tcpClient.ReceiveTimeout = 10000;
                this._tcpClient.SendTimeout = 10000;
                this._ntkStream = this._tcpClient.GetStream();
                this._sReader = new StreamReader(this._ntkStream, Encoding.Default);
                this.LocalEndPoint = this._tcpClient.Client.LocalEndPoint;
                this.SetConnectionState(true);
            }
            catch (Exception lastError)
            {
                this.LastError = lastError;
                this.SetConnectionState(false);
            }
        }

 

注意:并且服务器有可能会不断的写入空值流,如果不判断的话有可能造成死循环不断读取流

posted @ 2023-09-14 12:07  元点  阅读(150)  评论(0编辑  收藏  举报