【发布时间】:2015-07-08 23:20:20
【问题描述】:
我们目前正在为一个开源学术项目Logbus-ng 执行一些基准测试。它基本上通过 UDP (RFC 5426) 和 TLS (RFC 5425) 实现 Syslog 协议。 我们知道 TLS 的优点是可靠性(即我们不会丢失消息),但缺点是性能。
我们有一个基准测试客户端和一个特殊的伪造 Apache 安装,可以高速发送消息。 我们的目标是将UDP数据包的丢失减少到最低限度。 Apache 1.3.41 已被检测为通过 UDP 发送特殊日志消息(不是 Syslog 格式,而是我们在服务器端解析的特殊短语法),并且这种检测使它在 httpd 启动时发送超过 2000 条消息,并且我们希望它发生 :)
此外,我可以告诉您,在 Apache 的启动阶段,少量消息(与我们提交给日志服务器的其他工作负载相比)以极快的速度发送高速率,可能淹没 UDP。
现在,日志服务器与 HTTP 服务器位于不同的机器上,并且两者都几乎没有像样的硬件(甚至没有双核 CPU,而是带有超线程的 Pentium 4)。日志服务器代码在 C# 中。以下方法由 4 个线程以 AboveNormal 优先级运行
UdpClient _client;
IQueue<T>[] _byteQueues; //not really IQueue, but a special FIFO queue class that reduces overhead to the minimum
private void ListenerLoop()
{
IPEndPoint remoteEndpoint = new IPEndPoint(IPAddress.Any, 0);
while (_listen)
{
try
{
byte[] payload = _client.Receive(ref remoteEndpoint);
_byteQueues[
(((Interlocked.Increment(ref _currentQueue))%WORKER_THREADS) + WORKER_THREADS)%WORKER_THREADS].
Enqueue(payload);
}
catch (SocketException)
{
}
catch (Exception)
{
} //Really do nothing? Shouldn't we stop the service?
}
}
为了减少线程在 Receive 方法之外花费的时间,我们不会在收到消息后解析消息,而是将其存储在 4 个特殊队列之一中,其他工作线程将读取这些队列。据我所知,.NET 调度器是贪婪的,所以无论线程等待多长时间,更高优先级的线程都会更早调度并可能导致饥饿,所以这就是为什么我们目前不关心线程数量增加的原因应用程序(全球大约有 20 个)。
我们不仅增加了线程优先级,而且尝试将 UDP 缓冲区大小增加到 1MB。这是初始化代码的片段
try
{
Socket clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
{
#if !MONO
//Related to Mono bug 643475
ExclusiveAddressUse = true,
#endif
};
if (ReceiveBufferSize >= 0) clientSock.ReceiveBufferSize = ReceiveBufferSize;
clientSock.Bind(localEp);
_client = new UdpClient {Client = clientSock};
}
catch (SocketException ex)
{
throw new LogbusException("Cannot start UDP listener", ex);
}
ReceiveBufferSize 在运行时配置...
Apache 发送的每条日志消息都很短,我认为不超过 50 个字节。我们在实验室中运行千兆以太网。
在上一次使用这种配置的实验期间,日志服务器只收到了生成的 2900 多条中的 700 条以上。 Wireshark 在 UDP 套接字上报告了超过 2900 条消息,但 Logbus 的日志跟踪(将所有接收到的消息存储到文件中)仅报告这 700/800 条。执行 cat /proc/net/udp 并欺骗 lsof 以找到正确的行报告 大量丢弃 数据包。日志肯定是以非常高的速度发送的。如果我们在每次日志调用后将 Apache 内核修改为休眠一小段时间(不到一毫秒),我们会将损失降低到零,但性能也会降低到几乎为零。我们会做这样的测试,但我们必须在现实生活场景中证明 Logbus-ng 的有效性:(
我的直接问题是
- UdpClient.ReceiveBufferSize 是否有助于防止数据包丢失?在 C# 中我还能做什么?
- 显然应该也可以在 Mono 中工作,但是您知道该属性可能存在的错误吗?我的意思是,有人报告过错误吗? (单声道 2.8)
- 你知道先发送数据包到本地主机是否可以减少数据包丢失吗? (我会在 Web 服务器机器上运行一个特殊的日志服务器实例,然后通过不会丢失的 TLS 将日志转发到真正的日志服务器)
- 您建议我如何降低丢失率
我们目前必须使用 Apache 执行特殊测试,并且我们可以仅使用 UDP 来传递消息。我们不能选择 TLS,因为我们只有 C# APIs。
提前感谢您的帮助。我希望已经清楚了。如果有帮助,可以在SVN找到UDP接收器的源代码
【问题讨论】:
-
> 请澄清哪些机器(你可以称之为 A、B、C 等)正在运行:1. Apache 2. Wireshark 3. Logbus(我假设这是你的 C# 代码正在执行的地方。)
-
机器 A 运行 Apache,机器 B 运行 Logbus 和 Wireshark :)