суббота, 9 апреля 2016 г.

[prog] Небольшой пример MxxRu::externals скрипта из реальной жизни

Под катом пример MxxRu::externals-скрипта, посредством которого подтягиваются почти все зависимости для одного из текущих проектов. Почти все потому, что Boost таким образом не подцепишь (пока по крайней мере не пробовали).

В дополнение к тем соображениям по поводу будущих доработок в MxxRu::externals, которые были изложены здесь, добавилась еще одна идея: нужно иметь разные списки externals-ов для разных кусков проекта. Например, делаю библиотеку libX. Для нее нужны spdlog и tinyformat. Посему желательно, чтобы эти зависимости подхватывались автоматически всеми, кто берет libX к себе. Для тестов библиотеки libX нужен Catch. Поэтому Catch должен относиться к зависимостями libX-tests. И нужен Catch будет только тем, кто хочет гонять тесты для libX. Для примеров библиотеки libX может быть нужен rapidjson. Посему rapidjson должен быть в externals-ах libX-samples, но его не должно быть в externals-ах самой библиотеки libX.

В общем, есть над чем покурить.

Ну а пока пример того, что сейчас используется в повседневной работе:

[prog.c++] Об особенностях стиля кодирования на примерах :)

Время от времени люди, заглядывающие в мой код, интересуются, почему стиль кодирования у меня такой... Ну странный такой :) Например, почему тип возвращаемого значения метода/функции пишется на отдельной строке. Или почему пробелы ставятся после открывающей скобки и перед закрывающей.

Это все потому, что время от времени приходится писать что-то вроде:

templatetypename POSTMAN >
std::vector< typename subscriptions_map_t< POSTMAN >::postman_shptr_t >
subscriptions_map_t< POSTMAN >::match( const std::string & topic_name ) const
{...}

templatetypename POSTMAN >
typename subscriptions_map_t< POSTMAN >::tree_item_t::remove_action_t
subscriptions_map_t< POSTMAN >::remove_subscription(
   tree_item_t * root,
   const fragments_extractor_t fragments,
   const postman_shptr_t & postman ) noexcept
{...}

И, если мне не изменяет склероз, это еще не самые тяжелые случаи :)

PS. И да, длина строки кода не должна превышать 80-ти символов. Даже если вы работаете на 27" мониторе :)

пятница, 8 апреля 2016 г.

[prog] Несколько ссылок на тему topic matching algorithm

Столкнулся тут с необходимостью рассовывать MQTT-шные сообщения по подписчикам. И, поскольку подписки могут создаваться с использованием wildcard-ов (в MQTT это "+" и "#"), то важно делать это эффективно, а не за счет полного перебора подписок.

В процессе поиска информации в Интернетах наткнулся вот на эти ссылки, которые рассказывают, как это можно делать:

Две записи в блоге разработчиков RabbitMQ о том, как они решали эту проблему в 2010-ом году: Very fast and scalable topic routing – part 1 и Very fast and scalable topic routing – part 2.

Статья "High-speed message matching" с сайта ZeroMQ. И еще один вариант этого же материала, но на сайте OpenAMQ.

Небольшая заметка Optimizing Subscriptions in nanomsg от автора ZeroMQ и nanomsg.

Любопытная и большая статья Breaking and Entering: Lose the Lock While Embracing Concurrency с упором на lock-free реализацию и ссылкой на github с исходниками на Go.

Статья Fast Topic Matching Algorithm Implementation for WOS2 Message Broker. Как я понял, описанный в этой статье подход требует перестройки внутренних структур данных как при появлении новых подписок, так и при появлении новых топиков. Есть подозрение, что пара индусов довольно коряво пересказали часть ранее упомянутой статьи High-speed message matching.

Если нарою еще что-нибудь интересное, добавлю сюда. Хотя, простые решения на основе деревьев, в принципе-то, очевидны. И, как показал опыт RabbitMQ, еще и весьма эффективны.

четверг, 7 апреля 2016 г.

[prog.mqtt] Интересная багофича MQTT, QoS=0 и pingreq/pingresp

Обнаружил интересную багофичу протокола MQTT. Если некоторый клиент подключается к брокеру и подписывается на некоторый топик с Quality-of-Service=0 (т.е. доставка сообщений не гарантируется), то в случае отсутствия сообщений в этом топике клиент и брокер будут обмениваться pingreq/pingresp-ами. И соединение будет продолжать жить, т.к. оно доказывает свою жизнеспособность этими самыми регулярными ping-ами.

Однако, если в топике появляется сообщение, оно доставляется до клиента посредством publish PDU. Но в ответ клиент ничего не отсылает, т.к. QoS=0 (при этом QoS подтверждения доставки не требуется). И здесь оказывается забавная ситуация: клиент видит у себя активность в канале и начинает отсчет времени для следующего pingreq заново. Т.е. клиент инициирует следующий pingreq через N секунд после получения publish, а не через N секунд после выдачи последнего pingreq. Т.е. если последний pingreq был в момент времени T(0), а publish пришел в момент времени T(1), то следующий pingreq от клиента уйдет в (T(1)+N).

А вот брокер ничего не видит от клиента. Брокер знает только про последний pingreq, полученный в момент времени T(0). И рассчитывает получить следующий в (T(0)+N). Но этого pingreq-а не будет, т.к. клиент отошлет его только в (T(1)+N). Поэтому в (T(0)+N) сервер решит, что клиент умер, а соединение "протухло". Что даст ему право соединение с клиентом разорвать.

Получается, что если некоторый клиент подключается к MQTT-брокеру только для того, чтобы слушать какие-то топики с QoS=0, но ничего не публиковать (например, клиент слушает $SYS-топики), то связь клиента с брокером может рваться на регулярной основе.

Причем, по стандарту, pingreq может отсылать только клиент. Брокер этого не делает. А если бы делал, то этой проблемы бы не было, просто брокер отослал бы pingreq сам, получил бы pingresp и понял бы, что клиент жив-здоров. Но нет, современный MQTT-протокол вот такой.

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

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

вторник, 5 апреля 2016 г.

[life.work] Двойственные чувства

Сегодня неожиданно довелось услышать теплые слова в адрес своей прошлой компании -- Интервэйл. Точнее в адрес ее гомельского филиала, Интервэйл-Гомель. Оказывается, уровень сотрудников оценивается как весьма высокий и многие хотят заполучить интервэйловцев себе.

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

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

Отрадно то, что не так давно власть таки была передана в нормальные руки и полномочия получили более чем вменяемые люди, отлично знающие, что такое разработка софта вообще и продуктовая разработка в частности. Так что буду рад узнать со временем, что нанесенные эффективным менеджментом повреждения устранены и у моих бывших коллег все нормально.