В настоящее время мы выполняем некоторые тесты для академического проекта с открытым исходным кодом, Logbus-ng . Он в основном реализует протокол Syslog по UDP (RFC 5426) и TLS (RFC 5425).
Мы знаем, что преимуществом TLS является надежность (т. Е. Мы не потеряем сообщения), но с недостатком производительности.
У нас есть клиент для тестирования, а также специальная поддельная установка Apache, которая отправляет сообщения с высокой скоростью.
Наша цель - снизить потери пакетов UDP до минимума. Apache 1.3.41 был инструментирован для отправки специальных сообщений журнала через UDP (не в формате Syslog, а в специальном коротком синтаксисе, который мы анализируем на стороне сервера), и такой инструментарий заставляет отправлять более 2000 сообщений при запуске httpd, и мы хотим, чтобы это произошло :)
Более того, я могу вам сказать, что на этапе развертывания Apache это небольшое количество сообщений (по сравнению с другими рабочими нагрузками, которые мы отправляли на сервер журналов) отправляется с чрезвычайно высокой скорость , возможно затопление UDP.
Теперь сервер журналов расположен на другом компьютере, нежели HTTP-сервер, и оба имеют едва приличное оборудование (даже не двухъядерный процессор, а Pentium 4 с HyperThread). Код сервера журнала находится в C #. Следующий метод запускается четырьмя потоками с приоритетом 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 до 1 МБ. Вот фрагмент кода инициализации
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 байтов. В нашей лаборатории мы используем гигабитный Ethernet.
Во время последнего эксперимента с такой конфигурацией сервер журналов получил только 700+ из более чем 2900 сгенерированных. Wireshark сообщил о более чем 2900 сообщений на сокете UDP, но трассировка журнала Logbus (которая хранит все полученные сообщения в файл) сообщает только об этих 700/800. Выполните команду cat /proc/net/udp
и обманите lsof
, чтобы найти правильные отчеты о строках много отброшенных пакетов. Журналы были определенно отправлены с очень высокой скоростью. Если мы изменим ядро Apache на короткое время (чуть меньше миллисекунды) после каждого вызова журнала, мы снизим потери до нуля, но производительность также снизится до почти-ноль . Мы проведем такой тест, но мы должны доказать эффективность Logbus-ng в реальных сценариях: (
Мои прямые вопросы
- Помогает ли UdpClient.ReceiveBufferSize предотвращать потерю пакетов? Что еще я могу сделать в C #?
- Очевидно, предполагается также работать в Mono, но знаете ли вы о возможных ошибках с этим свойством? Я имею в виду, кто-нибудь когда-нибудь сообщал об ошибке? (Моно 2,8)
- Знаете ли вы, может ли отправка пакетов на локальный хост сначала уменьшить потерю пакетов? (Я бы запустил специальный экземпляр сервера журналов на компьютере с веб-сервером, а затем перенаправил журналы через TLS, который не теряет, на настоящий сервер журналов)
- Что бы вы посоветовали мне уменьшить коэффициент потерь
В настоящее время мы должны выполнить специальный тест с Apache, и мы можем только использовать UDP для доставки сообщений. Мы не можем выбрать TLS, потому что для этого у нас есть только C # API.
Заранее спасибо за любую помощь. Я надеюсь, что было ясно. Вы можете найти исходный код приемника UDP на SVN , если это поможет