В предыдущей статье "Дерево Киви для поиска шаблона по тексту" я рассказывал, как можно эффективно находить по входящему сообщению все удовлетворяющие "поисковые запросы", избегая их перебора "в лоб" и прямого сопоставления. Это можно применить реализации полноценной Pub/Sub-системы, дополняющей уже существующие, такие как Nats, Apache Kafka или AWS SNS новой возможностью поддерживать действительно масштабируемое число wildcard-подписок. В этой статье я расскажу о такой системе.
Авакари на текущий момент - backend сервис, который использует gRPC API по ряду причин:
Эффективное использование ресурсов (HTTP/2, бинарная сериализация Protobuf)
Streaming - необходимо для реализации push уведомлений от сервиса клиенту. Здесь отдельное спасибо Кириллу Гусакову за подсказку.
Получение и отправка сообщений
Потоковая передача сообщений используется как для отправки сообщений в систему (Publish), так и для получения сообщений на выходе.
При выборе формата сообщений я решил остановиться на нейтральном стандарте CloudEvents. Исходные требования к формату сообщений были следующие:
Поддержка произвольных key-value метаданных, по которым будет происходить сопоставление с подписками
Независимость от протокола
Удобство (де)сериализации с помощью Protobuf
Пример payload при получении/отправке сообщений выглядит следующим образом:
{ "msgs": [ { "id": "3426d090-1b8a-4a09-ac9c-41f2de24d5ac", "type": "example.type", "source": "example/uri", "spec_version": "1.0", "attributes": { "author": { "ce_string": "Obi-Wan Kenobi" }, "time": { "ce_timestamp": "1985-04-12T23:20:50.52Z" } }, "text_data": "I felt a great disturbance in the force" } ] }
Подписки
Для работы с пользовательскими подписками достаточно простого набора CRUDL операций (также gRPC). Чтобы пользователь мог определять, как выбирать сообщения, подписки должны содержать условия выбора.
Kiwi-условия
Так как входящие сообщения имеют метаданные в виде набора "key: input value", то условия выбора сообщения можно выразить как: "key: wildcard", где key - это искомый ключ метаданных, а wildcard - шаблон. Kiwi-условие, если короче.
Дополнительно kiwi-условия имеют следующие свойства:
Not - условие является отрицанием, то есть совпадение исключает сообщение
Partial - искать совпадения также среди лексем из input, который разбивается
Пример:
"cond": { "not": false, "ktc": { "key": "title", "pattern": "?usk", // musk, Musk, dusk, ... "partial": true } }
Такому условию должны удовлетворять сообщения, которые в метаданных по ключу "title" содержат отдельные слова как, например, "musk" или полные строки вроде "Elon Musk" или "Dusk and her embrace".
Группы условий
Для полноценного описания ��ого, какие сообщения требуется получать, kiwi-условий недостаточно. Необходимо иметь возможность описывать сразу множество условий в одной и той же подписке (например по разным ключам метаданных) и применять логические операции:
And
Or
Xor
Для этой цели служат группы условий. Так как группа тоже является условием, можно использовать вложенность.
Полный пример описания подписки с групповым условием:
{ "md": { "description": "my subscription 1", "enabled": true }, "cond": { "not": false, // "gc" means "group condition" "gc": { "logic": 0, // 0 - And, 1 - Or, 2 - Xor "group": [ { "not": false, // "ktc" means "kiwi-tree condition" "ktc": { "key": "key0", "pattern": "pattern?", "partial": false } }, { "not": true, "ktc": { "key": "key1", "pattern": "pattern1", "partial": true } } ] } } }
Как это попробовать
На текущий момент есть два варианта:
Самостоятельно раздеплоить Core систему, например, на minikube у себя дома.
В облачном варианте уже используется producer-rss компонент, который регулярно поглощает RSS из разных источников, конвертирует данные в сообщения и отправляет в систему. То есть можно подписаться на новости по какому-либо критерию и получать их.
Планы на будущее

В первую очередь, конечно же нужно добиться выполнения критериев production-ready и запустить боевой экземпляр сервиса. Тут ещё довольно много рутинной работы, такой как автоматизация выдачи сертификатов.
В перспективе Авакари можно будет использовать в довольно широком наборе сфер, таких как инвестиции, СМИ, реклама.
Можно представить интеграцию с чем-то вроде Авито, где новое объявление о продаже уведомляет всех, кто подписан на специфический товар, например iphone 42.
Вместо изобретения собственного UI есть идея реализации чат-бота, который будет позволять управлять подписками, отправлять и получать сообщения в/из Авакари.
