воскресенье, 2 ноября 2014 г.

12. ZeroMQ: высокая вода. High-Water Marks. Настройки пропускной способности сокетов.

(Начало - здесь.)




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

Проблема заключается в следующем: вообразите, что есть процесс A, с высокой частотой отправляющий сообщения процессу B, который их обрабатывает. Иногда процесс B оказывается недоступен (сборка мусора, перегрузка CPU, что угодно), и не может обработать сообщения за короткий период. Если такие задержки составляют несколько секунд или даже больше - это может стать серьезной проблемой. Что произойдет с сообщениями, которые процесс A все еще старается отправлять? Некоторые из них попадут в сетевые буферы процесса B. Некоторые будут все еще в процессе передачи по Ethernet. Некоторые будут в буферах сети процесса A. А остальные будут накапливаться в памяти процесса A с той скоростью, с которой процесс A их отправляет. Если не принять мер предосторожности, можно легко получить out of memory и крах.

Это - классическая проблема систем обмена сообщениями. Причем, чаще всего, процесс В - это приложение, написанное пользователем, и процесс А его никак не контролирует.

Что делать? Один из вариантов решения - управлять входным потоком. Процесс A получает сообщение откуда-то еще. Говорим ему "Stop!". И так далее - тормозим всех, кто меня торопит. Это называется управление потоком (flow control - обмен сигналами, при котором каждое устройство оповещает о готовности послать или принять данные). Такое решение выглядит правдоподобно, но что если вам пришло сообщение из Твиттера? Вы скажете всему миру подождать, пока вы в процессе B делается что-то важное?

Flow control работает в некоторых случаях, но не работает в других. Транспортный уровень не может сообщить уровню приложения "stop". Это как если метрополитен скажет большему бизнесу: "пожалуйста, держите работников еще полчаса, я слишком занят". Решением для системы обмена сообщениями является назначение пределов размеров буферов, а по достижению этих границ - выполнение некоторых разумных действий. В некоторых случаях (ОК, не для метрополитена), будет отказ в обслуживании (сообщения отбрасываются), в других лучшей стратегией будет ожидание.

ZeroMQ использует концепцию HWM (high-water mark) для определения емкости своих внутренних трубопроводов. Каждое соединение от сокета к сокету имеет собственный трубопровод, и значение HWM для отправки и/или для приема , в зависимости от типа сокета. Некоторые сокеты (PUB, PUSH) имеют только буферы для отправления сообщений. Некоторые (SUB, PULL, REQ, REP) - только для приема. Некоторые (DEALER, ROUTER, PAIR) имеют оба типа буферов.

В ZeroMQ v2.x значение HWM было бесконечным по умолчанию. Это было легко для использования, но и, как правило, оказывалось смертельным для сокетов - издателей с большим объемом сообщений. В ZeroMQ v3.x и в v4.x оно установлено в 1000 по умолчанию, которое является более разумным. Если вы все еще используете ZeroMQ v2.x, вы всегда должны установить HWM на ваших сокетах, например - 1000, чтобы соответствовать ZeroMQ v3.x/4.x или другое значение, которое посчитаете правильным.

Когда сокет достигает своего HWM, он либо блокирует данные, либо отбрасывает сообщения, в зависимости от типа скета. Сокеты типа PUB и ROUTER будут отбрасывать данные, в то время как другие будут блокировать. Для транспорта inproc передающий и принимающий сокеты используют общие буферы, поэтому реальное значение HWM будет суммой HWM, установленных для обоих сторон.

Наконец, последнее. Значения HWMs не являются точными величинами. Если вы установите 1,000 сообщений (по умолчанию), то реальная величина буфера будет меньше, чем половина, так как libzmq реализует еще и собственные очереди.

Дальше будет описан универсальный решатель проблем. Не всех, конечно, а связанных с потерями сообщения. (Продолжение).

Комментариев нет :

Отправить комментарий