Тайм-ауты и медленные запросы к Redis при использовании библиотеки StackExchange.Redis

Мы начали использовать Redis в нашем приложении, чтобы сохранять там ответы API. Я выбрал для работы с ним StackExchange.Redis и после реализации всей логики сохранения ответов результаты нагрузочного тестирования стали весьма неутешительными. Общая пропускная способность приложения упала в 3-4 раза! Было около 550-600 об/с, а сейчас около 180 об/с (может быть и медленнее).

Иногда во время стресс-тестирования исключений вообще нет, но время от времени возникают исключения Timeout, подобные этим:

Timeout awaiting response (5094ms elapsed, timeout is 5000ms), inst: 0, qs: 10, in: 65536, mgr: 10 of 10 available, IOCP: (Busy=26,Free=974,Min=8,Max=1000), WORKER: (Busy=3,Free=32764,Min=8,Max=32767), v: 2.0.513.63329 
Timeout awaiting response (5063ms elapsed, timeout is 5000ms), inst: 0, qs: 4, in: 47355, mgr: 10 of 10 available, IOCP: (Busy=40,Free=960,Min=8,Max=1000), WORKER: (Busy=34,Free=32733,Min=8,Max=32767), v: 2.0.513.63329 
The timeout was reached before the message could be written to the output buffer, and it was not sent (5000ms, inst=3, qs=3, in=10, active=HMSET), inst: 3, qs: 3, in: 10, mgr: 10 of 10 available, IOCP: (Busy=36,Free=964,Min=8,Max=1000), WORKER: (Busy=34,Free=32733,Min=8,Max=32767), v: 2.0.513.63329 

А вот общая картина всех исключений тайм-аутов, произошедших во время последнего стресс-теста: Статистика

Я пытался реализовать пул соединений (на основе свойства TotalOutstanding), пытался уменьшить количество запросов к Redis и так далее, но это не помогло.

Я выполнил команды SHOW LOG и LATENCY DOCTOR, но, похоже, с нашим экземпляром Redis все в порядке (хотя мы отключили THP, как это было рекомендовано доктором).

Я предполагаю, что некоторые очень большие ответы API препятствуют выполнению других запросов. Я так думаю из-за высоких значений входящего трафика. Это правильно? Что можно с этим сделать? Нужно ли как-то разделять запросы?


person Dobby007    schedule 03.12.2018    source источник
comment
Мы увеличили количество буферов IOCP с 8 до 300.ThreadPool.SetMinThreads(minimumThreadCount, MinimumThreadCount); У нас также есть пул ConnectionMultiplexors и циклических вызовов между 100 из них.   -  person No Refunds No Returns    schedule 05.12.2018


Ответы (1)


Я вижу здесь интересный намек:

The timeout was reached before the message could be written to the output buffer

Я думаю, что, по сути, Redis говорит вам очистить входящее сообщение, потому что он пожарный шланг на вас. Скорее всего, вы создали подписку с довольно широким охватом.

Я прошел через тот же опыт и в итоге просто запихнул данные в кеш памяти (он же ConcurrentQueue<T>) в лямбда-выражении подписки и обработал результаты сообщения в отдельном дросселированном потоке, который проверял очередь и обрабатывал содержимое, типичный подход производитель-потребитель-очередь. В этот момент ошибки тайм-аута исчезли.

person Ojingo    schedule 03.12.2018
comment
Я использовал IMemoryCache до перехода на Redis. У нас есть кластер серверов, и когда один сервер снимается с балансировки нагрузки, приложение все равно должно иметь возможность получить ответ API. Я не использую механизм подписки, предложенный Redis. Только вызовы с асинхронным ожиданием для получения и размещения данных. - person Dobby007; 03.12.2018
comment
Также я не вижу другого способа очистить входящие сообщения, кроме как получать их из сокета. - person Dobby007; 03.12.2018