Не відкладайте на поштову скриньку: b2c-месенджер 2ГІС



У вересні на 2gis.ru з'явилася нова фіча — b2c-мессенджер для спілкування з організаціями. Чат дуже зручний при пошуку товару або послуги: можна написати відразу в кілька компаній, не потрібно слухати голоси роботів-автовідповідачів або чекати на лінії, поки оператор уточнить ціну або залишок потрібного товару. Виберіть компанію, натисніть на іконку повідомлення на картці компанії, і відкриється чат.

Щоб зробити месенджер, нам довелося трохи порозбиратися з тим, як взагалі працюють чати і що під капотом у «великих братів» типу WhatsApp або Telegram. Виявилося, все не так страшно.

Навіщо 2ГІС месенджер
Почати, мабуть, варто не з месенджера, а з того, як ми прийшли до цієї ідеї. Раніше ми показували в довіднику email компанії. Потім додали форму зв'язку з компанією безпосередньо з довідника. Пишуть менше, ніж дзвонять, але довжина ланцюжка листів — в середньому від 2 до 10 повідомлень. Тобто месенджер — логічний розвиток вже існуючої можливості відправляти листи в компанії.

Як це працює зараз

А ще краще — просто спробуйте задати нам питання. Ми в Новосибірську, і коли в Москві 18:00, у нас вже 22:00.

Побіжний огляд: вибираємо велосипед
Спершу ми подивилися на BaaS (Backend as a Service), типу quickblox.com, backendless.com, sendbird.com і т. д. Всі вони надають інструменти для додавання стандартної чатовой функціональності в мобільні або веб-додатки.

Реалізація основного (відправлення email-повідомлень в компанії) і більш просунутих сценаріїв на основі існуючого BaaS-рішення вимагатиме від нас розробки власних бекендов для інтеграції через вебхуки, так і надзусиль інтеграції API вендора. Тому BaaS нам не підійшов. Крім того, ми хотіли мати повний контроль над фичей, тобто не залежати від сторонніх рішень. Зрештою, ми ж інженери і зважилися на експеримент, щоб отримати новий досвід для нас.

А як повідомлення-то доставляти?
Щоб зробити свій бекенд для месенджера, спочатку треба розібратися з купою питань: як взагалі передавати повідомлення з клієнта на сервер і назад, де їх зберігати, як впоратися з купою одночасних з'єднань, як масштабувати сервіс. Подумали, погуглили, зібрали способи доставки повідомлень в табличку для порівняння.
ТаблицяВибачте, але ми не змогли оформити в таблиці Хабраредакторе красиво.
Спосіб Опис Транспорт Протокол Підтримка в браузерах
WebSockets Клієнт відкриває постійне з'єднання з сервером, використовуючи API WebSockets. API Websockets TCP (необхідний HTTPhandshake для відкриття з'єднання) caniuse.com/#feat=websockets
Streaming Клієнт відкриває постійне з'єднання з сервером. XMLHttpRequest (multipart onload), XMLHttpRequest (onprogress), Iframe tag HTTP caniuse.com/#feat=streaming
Server-Sent Events Клієнт відкриває постійне з'єднання з сервером, використовуючи API Server-Sent Events. API Server-Sent Events HTTP Немає підтримки в IE, caniuse.com/#feat=eventsource
Polling Клієнт періодично опитує сервер на предмет наявності нових повідомлень. Будь-який доступний HTTP
Long Polling Клієнт відкриває довгоживучі з'єднання з сервером, яке не закривається до появи нового повідомлення або закінчення тайм-ауту. Відразу ж після закриття з'єднання клієнт відкриває нове. XMLHttpRequest
Script tag
HTTP
Browser Plugins (Java / Flash) Клієнт відкриває постійне з'єднання з сервером, використовуючи API браузерного плагіна (Java або Flash). API плагіна TCP/UDP

Більшість сучасних чат-додатків використовують один із двох способів: long polling або websockets. Websockets володіє рядом переваг перед long polling (повнодуплексне з'єднання, відсутність зайвого трафіку при переконнектах), широко підтриманий в браузерах і opensource-бібліотеках, тому представляється оптимальним вибором для нашої задачі. Є й недоліки: відмінності імплементації в різних браузерах, більш складна логіка на сервері.

Найбільш поширений відкритий general-purpose протокол для передачі даних — XMPP.
Позитивні сторони Негативні сторони
— це Відкритий стандарт IETF Надмірність інформації
Велика кількість opensource-реалізацій XML
Широкі можливості для кастомізації Вимагатиме доопрацювання під специфіку нашої задачі
Огляд великих месенджерів
Месенджер Спосіб доставки Протокол Система зберігання
WhatsApp Websockets Починали з XMPP, але потім перейшли на in-house протокол Вся серверна інфраструктура побудована на Erlang + FreeBS, це дозволяє тримати до 2kk TCP-з'єднань на одному сервері. Починали на ejabberd, але дуже сильно його доопрацьовували під себе згодом. Yaws, lighttpd Не зберігають історію повідомлень на сервері, повідомлення видаляються з сервера після отримання клієнтом, mnesia
Line Немає веб-версії, тільки Chrome app Thrift для мобільних клієнтів Java, С++, Nginx Почали з кластера з трьох инстансов Redis, після вибухового зростання користувацької бази смигрировали в Hbase «холодні» дані: історію повідомлень і історію змін користувачів / груп / контактів, MySQL для бекапів і аналітики
Viber Немає веб-версії In-house С++, хостятся в AWS Почали з самопісного in-memory сховища написаного на C++, потім перешили на Mongo і Redis в якості кеша. Mongo не влаштувала по продуктивності, в результаті мігрували на Couchbase
Facebook Messenger Long polling In-house json-based для вебу, Thrift для мобільних додатків Erlang — черги повідомлень. C++ — сервіс інформації про присутність, сховище історії повідомлень. PHP — фронтенд, обробляє всі запити, окрім long polling. Сервіси між собою спілкуються через Thrift
Чергу на MySQL, HBase
Slack Websockets In-house json-based Java messaging server, LAMP for core app/APIs, хостятся в AWS Redis, MySql, Apache Solr

Однак, вивчивши рішення різних «великих» месенджерів, ми не виявили жодної значимої історії успіху використання XMPP без його подальшої доробки і кастомізації. Поміркувавши, вирішили розробити простий json-based протокол, спочатку враховує специфіку нашої задачі.

Технологічний стек
Так історично склалося, що наш основний бекенд-сервіс — АПІ 2ГІС — був написаний на PHP5. Два роки тому ми прийняли рішення піти від PHP, мігрувати на Scala і Go. Go дозволяє дуже легко будувати досить складні concurrent-програми. Це стало вирішальним фактором при виборі його як основної технології реалізації месенджера. Так і певний досвід розробки на Go у нас вже був.

Отже, бекенд пишемо Go, а фронтенд — на React + Redux. В якості системи обміну повідомленнями ми вибрали RabbitMQ; для зберігання даних використовуємо Redis і PostgeSQL. Додаток пакуємо в Docker-контейнер і деплоим через Gitlab-CI в платформу Deis.

Як я сказав вище, ми хотіли використати вебсокеты, але коли справа дійшла до реалізації, трохи переосмислили рішення. Справа в тому, що ми хотіли випустити фічу як можна швидше, щоб перевірити гіпотезу (горезвісний MVP). Щоб прискоритися, вирішили розділити логіку на використання вебсокетов для відправки даних з клієнта на сервер і найпростішого REST API в іншу сторону.

Що з повідомленнями?
Раптово найскладнішим у реалізації виявилися нотифікації. Здавалося б, все просто: відправляй пуши в телефон, листи на пошту, отображай нотификашки у браузері. Але нашим завданням було зробити так, щоб всі повідомлення прочитувалися максимально швидко і при цьому не перетворювалися в потік спаму.

Є рішення, яке називають каскадної системою нотифікацій. Наприклад, у нас є три основних канали: повідомлення на 2gis.ru, листи і пуши на телефон.

В цьому випадку система нотифікацій приймає вигляд:
— перевіряємо, чи немає користувача онлайн → якщо так, то шолом йому повідомлення в браузері;
— якщо користувача немає онлайн, перевіряємо, прив'язаний телефон → якщо так, намагаємося відправити пуш на мобільний телефон, показуємо повідомлення в діалогах в браузері, лист не відсилаємо;
— якщо не спрацював і це, тоді шолом лист;
— якщо повідомлення стосується компанії — ще деякий час спостерігаємо за реакцією, а якщо відповіді після повідомлення в браузері і пуша немає, то все одно шолом лист.

Насправді, пуш-нотифікації з цього сценарію прямо зараз ми не відправляємо, але дуже скоро навчимося це робити.

Плани
У найближчих планах — додати функціонал месенджера в мобільні додатки 2ГІС, добити основний функціонал (можливість докласти аттачей до повідомлення, браузерні пуши), реалізувати просунуті сценарії спілкування (наприклад, запит на кілька компаній відразу).

Поки компанії не звикли до месенджера, і не все швидко відповідають на повідомлення. Але ми віримо, що у взаємодії людей і компаній через текст велике майбутнє.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.