Новички, у которых возникают проблемы с обработкой видеопотока UDP с помощью Netty 3.2.4. На разных машинах мы видим отброшенные байты и т. д., используя Netty. У нас есть небольшой счетчик после того, как Netty получает байты, чтобы увидеть, сколько байтов получено. Дисперсия больше, чем то, что можно было бы объяснить ненадежностью UDP. В нашем случае мы также сохраняем байты в файл для воспроизведения видео. Воспроизведение видео в VLC действительно иллюстрирует пропущенные байты. (Размер отправляемых пакетов составлял около 1000 байт).
Вопросы
- Верны ли наши предположения о Netty API с точки зрения невозможности использования AdaptiveReceiveBufferSizePredictor для прослушивателя потока UDP?
- Есть ли лучшее объяснение поведения, которое мы наблюдаем?
- Есть ли лучшее решение? Есть ли способ использовать адаптивный предиктор с UDP?
Что мы пробовали
...
DatagramChannelFactory datagramChannelFactory = new OioDatagramChannelFactory(
Executors.newCachedThreadPool());
connectionlessBootstrap = new ConnectionlessBootstrap(datagramChannelFactory);
...
datagramChannel = (DatagramChannel) connectionlessBootstrap.bind(new
InetSocketAddress(multicastPort));
datagramChannel.getConfig().setReceiveBufferSizePredictor(new
FixedReceiveBufferSizePredictor(2*1024*1024));
...
Судя по документации и поиску в Google, я думаю, что правильный способ сделать это — использовать OioDatagramChannelFactory вместо NioDatagramChannelFactory.
Кроме того, хотя я не нашел явного указания, вы можете использовать FixedReceiveBufferSizePredictor только с OioDatagramChannelFactory (по сравнению с AdaptiveReceiveBufferSizePredictor). Мы обнаружили это, просмотрев исходный код и поняв, что метод previousReceiveBufferSize() AdaptiveReceiveBufferSizePredictor не вызывался из класса OioDatagramWorker (в то время как он вызывался из класса NioDatagramWorker).
Итак, мы изначально установили FixedReceivedBufferSizePredictor в (2*1024*1024)
Наблюдаемое поведение
Работая на разных машинах (разная вычислительная мощность), мы видим, что Netty принимает разное количество байтов. В нашем случае мы передаем потоковое видео через UDP и можем использовать воспроизведение переданных байтов для диагностики качества прочитанных байтов (размеры отправляемых пакетов составляли около 1000 байт).
Затем мы поэкспериментировали с разными размерами буфера и обнаружили, что 1024*1024 вроде бы улучшают работу... но на самом деле понятия не имеем, почему.
Изучив, как работает FixedReceivedBufferSizePredictor, мы поняли, что он просто создает новый буфер каждый раз, когда приходит пакет. В нашем случае он будет создавать новый буфер размером 2*1024*1024 байта независимо от того, был ли пакет 1000 байт или 3 МБ. Наши пакеты были всего 1000 байт, поэтому мы не думали, что это наша проблема. Может ли какая-либо из этой логики вызывать проблемы с производительностью? Например, создание буфера каждый раз, когда приходит пакет?
Наш обходной путь
Затем мы подумали о том, как сделать размер буфера динамическим, но поняли, что не можем использовать AdaptiveReceiveBufferSizePredictor, как указано выше. Мы экспериментировали и создали свой собственный MyAdaptiveReceiveBufferSizePredictor вместе с сопутствующими классами MyOioDatagramChannelFactory, *Channel, *ChannelFactory, *PipelineSink, *Worker (которые в конечном итоге вызывают MyAdaptiveReceiveBufferSizePredictor). Предсказатель просто изменяет размер буфера, чтобы удвоить размер буфера на основе размера последнего пакета или уменьшить его. Это, казалось, улучшило ситуацию.