C# 在.NET/Mono中减少UDP消息丢失

C# 在.NET/Mono中减少UDP消息丢失,c#,mono,udp,C#,Mono,Udp,我们目前正在为一个开源学术项目执行一些基准测试。它基本上通过UDP(RFC 5426)和TLS(RFC 5425)实现Syslog协议。 我们知道TLS的优点是可靠性(即我们不会丢失消息),但也有性能方面的缺点 我们有一个基准测试客户端,还有一个特殊的伪造Apache安装,可以高速发送消息。 我们的目标是将UDP数据包的丢失降至最低。Apache 1.3.41已被检测,以便通过UDP发送特殊日志消息(不是Syslog格式,而是我们在服务器端解析的特殊简短语法),这种检测使它在httpd启动时发送

我们目前正在为一个开源学术项目执行一些基准测试。它基本上通过UDP(RFC 5426)和TLS(RFC 5425)实现Syslog协议。 我们知道TLS的优点是可靠性(即我们不会丢失消息),但也有性能方面的缺点

我们有一个基准测试客户端,还有一个特殊的伪造Apache安装,可以高速发送消息。 我们的目标是将UDP数据包的丢失降至最低。Apache 1.3.41已被检测,以便通过UDP发送特殊日志消息(不是Syslog格式,而是我们在服务器端解析的特殊简短语法),这种检测使它在httpd启动时发送2000多条消息,我们希望它发生。:)

此外,我可以告诉您,在Apache的提升阶段,少量消息(与我们提交给日志服务器的其他工作负载相比)以极高的速率发送,可能会淹没UDP

现在,日志服务器与HTTP服务器位于不同的机器上,并且两者都几乎没有像样的硬件(甚至没有双核CPU,而是带有HyperRead的奔腾4)。日志服务器代码是C#。以下方法由4个线程以高于正常优先级运行

    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?
        }
    }
ReceiveBufferSize是在运行时配置的

Apache发送的每个日志消息都非常短,我认为不超过50字节。我们在实验室里运行千兆以太网

在上一次使用这种配置的实验中,日志服务器只接收到生成的2900多个日志中的700多个。Wireshark报告了UDP套接字上超过2900条消息,但Logbus的日志跟踪(将所有接收到的消息存储到一个文件中)只报告了这700/800条消息。执行cat
/proc/net/udp
并使用
lsof
进行欺骗,以找到正确的行报告大量丢弃的数据包。日志肯定是以非常高的速率发送的。如果我们在每次日志调用后将apachecore修改为睡眠一段短时间(略小于一毫秒),我们会将损失减少到零,但性能也会降低到几乎零。我们将进行此类测试,但我们必须证明Logbus ng在现实场景中的有效性:(

我直截了当的问题是
  • UdpClient.ReceiveBufferSize有助于防止数据包丢失吗?在C#中我还能做什么
  • 它显然也应该在Mono中工作,但是你知道该属性可能存在的bug吗?我的意思是,有人报告过bug吗?(Mono 2.8)
  • 您知道首先向localhost发送数据包是否可以减少数据包丢失吗?(我会在web服务器机器上运行日志服务器的一个特殊实例,然后通过不会丢失的TLS将日志转发到真正的日志服务器)
  • 你建议我怎样降低损失率
  • 我们目前必须使用Apache执行一项特殊测试,并且我们只能使用UDP来传递消息。我们不能选择TLS,因为我们只有C#API


    提前感谢您的帮助。我希望已经说清楚了。如果有帮助,您可以在上找到UDP接收器的源代码。ReceiveBufferSize肯定会影响UDP套接字(即UdpClient),如果数据包丢失是由于缓冲区溢出,那么增加ReceiveBufferSize将有帮助

    请记住,如果数据速率太高,以至于无法从缓冲区快速读取足够长的时间,那么即使是最大的缓冲区,也不可避免地会溢出

    我已经在Ubuntu上运行的Mono 2.6.7上有效地使用了UdpClient.Client.ReceiveBufferSize,所以我相信Mono的实现很好,当然我还没有在Mono 2.8上使用它

    根据我的经验,以极高的速率向本地主机发送UDP数据包时,可能会出现一些数据包丢失,尽管我在现实世界的应用程序中从未遇到过这种数据包丢失的情况。因此,使用这种方法可能会取得一些成功

    您还需要查看是否发生了数据包丢失,数据包丢失可能是由于网络基础设施、数据包冲突、交换机可能由于交换机上的某些限制而丢弃数据包造成的


    简单地说,在使用UDP时,您需要准备好处理和预期数据包丢失。

    ReceiveBufferSize会影响UDP套接字(即UdpClient),如果数据包丢失是由于缓冲区溢出造成的,则增加ReceiveBufferSize将有所帮助

    请记住,如果数据速率太高,以至于无法从缓冲区快速读取足够长的时间,那么即使是最大的缓冲区,也不可避免地会溢出

    我已经在Ubuntu上运行的Mono 2.6.7上有效地使用了UdpClient.Client.ReceiveBufferSize,所以我相信Mono的实现很好,当然我还没有在Mono 2.8上使用它

    根据我的经验,以极高的速率向本地主机发送UDP数据包时,可能会出现一些数据包丢失,尽管我在现实世界的应用程序中从未遇到过这种数据包丢失的情况。因此,使用这种方法可能会取得一些成功

    您还需要查看是否发生了数据包丢失,数据包丢失可能是由于网络基础设施、数据包冲突、交换机可能由于交换机上的某些限制而丢弃数据包造成的


    简单地说,在使用UDP时,您需要准备好处理和预期数据包丢失。

    如果您使用UDP,您必须预期数据包丢失。数据包丢失的原因有很多。对您来说,最有可能是因为通道上任何位置的数据包溢出。可能是您的交换机,也可能是您的接收器。溢出的原因是因为UDP没有任何类型的拥塞控制。Tcp有拥塞控制(慢启动),这就是为什么对于Tcp,它永远不会(理论上在完美的环境下)溢出

    手动采用tcp慢启动拥塞控制策略是防止udp传输溢出的有效方法

    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);
    }