Подтвердить что ты не робот

Redis Pubsub и Message Queuing

Мой общий вопрос: использование Redis для PubSub, что происходит с сообщениями, когда издатели нажимают сообщения на канал быстрее, чем подписчики могут их прочитать?

Например, скажем, у меня есть:

  • Простые публикации издателей со скоростью 2 мс/сек.
  • Простые сообщения для чтения подписчиков со скоростью 1 msg/sec.

Мое наивное предположение заключалось в том, что абонент увидит только 50% сообщений, опубликованных в Redis. Чтобы проверить эту теорию, я написал два сценария:

pub.py

queue = redis.StrictRedis(host='localhost', port=6379, db=0)
channel = queue.pubsub()

for i in range(10): 
    queue.publish("test", i)
    time.sleep(0.5)

sub.py

r = redis.StrictRedis(host='localhost', port=6379, db=0)
p = r.pubsub()
p.subscribe('test')

while True:
    message = p.get_message()
    if message:
        print "Subscriber: %s" % message['data']
    time.sleep(1)

Результаты

  • Когда я сначала запустил sub.py, а затем pub.py, я обнаружил, что sub.py фактически отображал все сообщения (1-10) один за другим с задержкой в ​​1 секунду. Мое первоначальное предположение было неправильным, Redis представляет очереди сообщений. Требуется больше тестов.
  • Когда я сначала побежал pub.py, а затем ждал 5 секунд перед запуском sub.py, я обнаружил, что sub.py отображает только вторую половину сообщений (5-10). Я бы предположил это первоначально, но, учитывая мои предыдущие результаты, я думал, что сообщения были поставлены в очередь, что привело меня к следующему выводу...

Выводы

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

Остальные вопросы

  • Являются ли эти выводы действительными?
  • Если да, то как долго сообщения клиента/канала остаются в очереди?
  • Если да, существует ли команда redis-cli info для просмотра количества сообщений в очереди (для каждого клиента/канала)?
4b9b3361

Ответ 1

Тесты действительны, но выводы частично ошибочны.

Redis ничего не останавливает в пабах/подканалах. Напротив, он имеет тенденцию читать элемент из сокета издателя и записывать элемент во всех сокетах-абонентах, в идеале в той же самой итерации цикла событий. В структурах данных Redis ничего не содержится.

Теперь, как вы показали, все еще есть какая-то буферизация. Это связано с использованием сокетов TCP/IP и буферов обмена Redis.

У Sockets есть буферы, и, конечно же, TCP поставляется с некоторыми механизмами управления потоком. Это позволяет избежать потери данных при заполнении буферов. Если абонент не достаточно быстрый, данные будут накапливаться в буфере сокета. Когда он будет заполнен, TCP заблокирует связь и не позволит Redis нажимать больше информации в сокете.

Redis также управляет выходными буферами связи (поверх них сокетов) для генерации данных, отформатированных в протоколе Redis. Поэтому, когда выходной буфер сокета заполнен, цикл события будет отмечать сокет как незаписываемый, а данные будут оставаться в выходных буферах Redis.

Если TCP-соединение все еще действует, данные могут оставаться в буферах в течение очень долгого времени. Теперь оба выходных буфера сокета и Redis связаны. Если абоненты действительно слишком медленны, и накопилось много данных, Redis в конечном итоге закроет соединение с подписчиками (как механизм безопасности).

По умолчанию для pub/sub Redis имеет мягкий предел в 8 МБ и жесткий предел в 32 МБ на каждый буфер подключения. Если выходной буфер достигает жесткого предела или если он остается между мягким и жестким пределом более 60 секунд, соединение с медленным абонентом будет закрыто.

Знать количество ожидающих сообщений непросто. Его можно оценить, посмотрев размер ожидающей информации в буферах сокетов и буферов вывода Redis.

Для выходных буферов Redis вы можете использовать команду CLIENT LIST (из redis-cli). Размер выходного буфера возвращается в полях obl и oll (в байтах).

Для буферов сокетов нет команды Redis. Однако в Linux можно построить script для интерпретации содержимого файла /proc/net/tcp. См. Пример здесь. Этот script, вероятно, необходимо адаптировать к вашей системе.