Как продавать шкуры и ловить троллей в Telegram с помощью Kafka, Kubernetes, PostgreSQL и Redis

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

С чего все началось

Работаю в IT больше 15 лет. Чем только не занимался, но всегда следовал правилу - каждые майские праздники я пытаюсь применить на практике что-то новое.

В этом году я прочитал книгу Event Driven Microservices и загорелся потрогать Kafka как настоящий брокер событий, а не сообщений.

Идей было много, но мне хочется проверить все это под реальной нагрузкой, что сразу привело в телеграм боты, где получить +- 1000 пользователей труда не составляет.

Я все детство провозился с ASCII играми в DOS и идея пришла сама собой. В телеграме я нашел кучу текстовых квестов, но с графикой не было ни одного. Я провел небольшое исследование, как телеграм реагирует на большое количество emoji и выявил пару проблем:

  • Есть ограничение на 13 символов в строке, до момента, как телега не будет все ломать

  • На андроид, начиная с 50 символа телеграм меняет стилистику emoji

Первое решается легко, а второе потребовало добавить шапку из элементов:

Я решил использовать синие ромбы, похоже на небо
Я решил использовать синие ромбы, похоже на небо

Когда с идеей определился, настал момент выбирать технологии к реализации:

  • У меня есть кластер Kubernetes и несколько серверов

  • Для хранения данных я установил PostgreSQL, так как хорошо его знаю

  • Написал несколько скриптов на "Bashsible" для потребностей DevOps

  • Установил Kafka. Версия с Zookeeper и без репликации

  • В дальнейшем добавил Redis, но об этом позже

  • Сервисы решил писать на Java со Spring Boot

  • Для хранения и аналитики логов поставил ELK

Первая проблема с которой я столкнулся - это настройка Webhook в телеграме. Он категорически отказывался принимать мой сертификат с ingress контроллера. Хотя, любой frontend сервис, размещенный на кластер, отлично работал в браузере через https.

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

Вторая - это ограничения Telegram. В первой версии я реализовал MMO. Персонажи обновлялись сразу во всех чатах, где их можно увидеть.

Но лимиты телеграма быстро вернули меня в реальность и я решил оставить эту затею. Затем пришла пора входного потока событий. Если изменять сообщение чаще чем раз в секунду, то сразу попадаешь под ошибку подобную этой:

Too Many Requests: "{"ok":false,"error_code":429,"description":"Too Many Requests: retry after 33","parameters":{"retry_after":33}}"

К этому моменту я разбил всю систему на 3 группы микросервисов:

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

  2. Обработчики событий. В нее входят:

    1. Consumer сообщений из входного потока сообщений, и producer в выходной поток сообщений

    2. Сервисы карты мира

    3. Объекты для взаимодействия (мобы, NPC, здания, лут и т.д.)

    4. Пользователи и их характеристики

    5. Квестовый движок (Состояния, диалоги, скрипты)

  3. Отправка событий в Telegram. Сервис получает сообщения из выходного потока и отправляет их в телеграм. Попутно проверяя их на лимиты.

Для чего пригодился Redis

Я искал способ на проверку частоты отправки и наткнулся на такую возможность Redis как PX, т.е. время жизни объекта. При получения события я проверяю на наличие объекта по ключу(id чата пользователя), а затем записываю его опять с параметром px = 1000ms.

Если при получении события объект в Redis существует, то я игнорирую данное событие.

Ключевые фишки PostgreSQL

PostgreSQL очень помог на этапе создания квестового движка. Я активно использую индексы с условием и функциональные констрейнты.

Также, очень помогла и сократила размер кода такая конструкция в запросах как INSERT ... on conflict do

Результат

Я получил горизонтально-масштабируемую систему, позволяющую довольно легко внедрять новый функционал. При повышении нагрузки - я добавляю партиции в топики Kafka и увеличиваю кол-во pod'ов, содержащие consumer’ы.

Я накидал небольшой сюжет и опубликовал все это на нескольких ресурсах. Полет нормальный, народ требует продолжения, MMO и PvP

Если тоже хотите присоединиться к волшебному миру, то добро пожаловать в EmojiHeroesBot

Источник: https://habr.com/ru/post/675792/


Интересные статьи

Интересные статьи

Доклад Алексея Лесовского про то, что нового есть в PostgreSQL в плане мониторинга. Охватывать Алексей будет 13 и 14 версии. Далее от его лица.
Вместо return в корутине используется co_return, возвращающий результат. В этой заметке я хочу реализовать простую корутину с использованием co_return.
Внезапно прогремевший около 13.8 миллиардов лет назад Большой Взрыв положил начало истории. Через несколько миллиардов лет после этого из облаков слегка остывшего газа сф...
После написания предыдущей статьи по языку PERM и библиотеке Casbin, возникли вопросы. Причем не у одного человека, и я хотел ответить сначала в комментарии, но понял, что объем материала...
После удаления приложения Telegram с Вашего macOS-устройства стандартным путем (переносом из папки Applications в корзину) — в нем остаются файлы. Скриншот файлов Это какая-то часть переп...