记一次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); } }
注意:并且服务器有可能会不断的写入空值流,如果不判断的话有可能造成死循环不断读取流

浙公网安备 33010602011771号