Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

в 10:11, , рубрики: dynamodb, english, LinguaLeo, technology, webdev, английский язык, Блог компании LinguaLeo, Веб-разработка, изучение, образование, технологии, метки: , , , , , , , , ,

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

Пользователи LinguaLeo начинают изучать английский язык в Джунглях — хранилище тысяч материалов разного уровня сложности, формата и тематик; шаг за шагом учатся слышать и понимать речь носителей языка и расширять словарный запас. Кому нужна грамматика — идут в Курсы. Словарный запас пополняется не только из Джунглей, при добавлении незнакомых слов в Личный словарь, но и с помощью подготовленных Наборов слов, доступных для индивидуального изучения. В разделе Общение можно вести Диалоги на английском, чтобы практиковать язык с другими пользователями LinguaLeo в режиме real-time, выбирая темы для общения. Общение только на английском!

Для создания Диалогов на английском мы использовали Node.js, DynamoDB (все на AWS). Сейчас поделимся нашим опытом.

Почему Node.js?

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

«… Чтобы обеспечить нашим пользователям все возможности для общения, мы выбрали технологию Node.js. Почему? Node.js адекватен для работы со stream'ами, где существует огромное количество модулей. Кроме того, грамотный JavaScript-программист, работая на Node, сможет реализовать весь объём задачи, а не только её серверную часть (в отличие, например, от специалиста по Erlang).

В качестве «транспортного узла» между сервером и клиентом мы использовали WebSockets как наиболее быстрый способ доставки информации.

Для решения проблемы кросс-платформенности нами была выбрана библиотека Sock.JS. Во-первых, из-за соответствия стандартам W3C для WS, а во-вторых, Sock.JS отлично подходит для наших потребностей.

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

Итак, поехали. Демон Node.js мы запустили на «облачных» мощностях Amazon EC2. Деплоится приложение через git. За логирование и перезапуск отвечает модуль forever. К слову, у Amazon'а есть очень полезный сервис — Amazon Cloudwatch. Его функционал позволяет мониторить основные параметры системы, а главное его достоинство — настраиваемые нотификации, которые позволяют следить только за тем, что действительно важно. Для получения детальной информации о состоянии приложения мы используем nodetime.

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

В качестве драйвера для работы с DynamoDB используется модуль dynode. Он хорошо себя зарекомендовал, однако несовершенная техническая документация добавила дёгтя в бочку мёда. Официальный Node.js SDK от Amazon'а вышел позднее и всё ещё находится в стадии Developer Preview. Таким вот естественным путём образом было принято решение использовать продукты от Amazon'а, ибо они отвечают всем техническим требованиям.

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

Тонкости работы Node.js

Особое внимание мы уделили проблеме авторизации пользователя на сервере диалогов. У нас за авторизацию на сервере отвечают cookie. Это весьма «дорогое» решение с точки зрения скорости работы, но оно подкупает стабильностью и безопасностью, плюс независимой сервис-ориентированной архитектурой.

Как это работает? Cookie пользователя поступают через WebSockets на сервер диалогов → сервер диалогов проверяет валидность cookie, отправляя запрос с полученной кукой к нашему API, а оно уже отдаёт данные пользователя обратно. Если данные получены без ошибок, сервер «Диалогов» делает своё дело (авторизует) и отсылает данные на пользователя.

Мы знаем, что многие занимаются на LinguaLeo не только дома, но и на работе. Часто случается, что корпоративные фаерволы настроены чрезмерно строго, из-за чего все порты, кроме стандартных, бывают недоступны. Мы помним об этом, и для WebSocket-соединения используем порт 443 (без привязки к https). Это решение позволяет избегать возможных сетевых проблем.

Особенности DynamoDB

Чуть больше года назад Amazon выпустил распределённую NoSQL базу данных — Amazon DynamoDB. На этапе проектирования системной архитектуры перед нами стоял выбор между двумя продуктами: MongoDB и DynamoDB. От первого варианта мы отказались из-за сложностей с администрированием, и выбор пал на Amazon, так как поддержки в случае с его продуктом не требовалось. Ну и, конечно, самим было интересно «обкатать» технологию для дальнейшего использования.

Оказалось, работа с DynamoDB сильно отличается от всего того, что мы привыкли видеть. Являясь SaaS-продуктом, эта штука научила нас принимать в расчёт время на http-запрос. В пределах датацентра Amazon'а среднее время запроса составляет около 20 миллисекунд, из-за которых мы пришли к выводу: крайне желательно все выборки делать только через индексы (это быстрее и дешевле), а scan-запросы использовать исключительно для аналитики или миграций.

Структура данных

Dialogs — хранение метаданных диалога, кэширование последнего сообщения.

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

UserDialogs — список диалогов пользователя, кэширование + счетчик непрочитанных сообщений.

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

Messages — все сообщения пользователей.

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

User2User — участники диалога.

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

Пример 1

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

Данные выбираются за два запроса. Первый – это выборка всех dialogld из таблицы UserDialogs с помощью Query. Второй – это получение диалогов посредством BatchGetItem. Тут есть небольшой нюанс — BatchGetItem за один раз выбирает максимум 100 сообщений. Поэтому, если их у пользователя 242 штуки, нам потребуется сделать 3 запроса, что занимает около 70-100 миллисекунд. Помня об этом и стремясь к большей оптимизации производительности, мы кэшируем данные диалогов в ElasticCache, обновляя его при каждом новом сообщении.

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB

Пример 2

Добавление нового сообщения в диалог тоже происходит нетривиально. Скорость базы данных нам не очень важна, поскольку мы не дожидаемся записи в DynamoDB. Нам ведь нужно провести большое количество записей, а это играет значительную роль для быстроты последующей выборки. Сначала мы записываем новое сообщение в таблицу Messages PutItem, а после кэшируем в таблице Dialogs UpdateItem. Дальше нам нужно заинкрементить messageCounter в таблице UserDialogs для каждого пользователя (UpdateItem). Всякое ведь бывает, вдруг один из пользователей решил удалить диалог и сбросил нам счетчик сообщений. В сумме = 4 запроса, по времени собираются около 70-100 миллисекунд. К сожалению, такие транзакции не поддерживаются в DynamoDB, что накладывает ощутимые ограничения для процессов, где сохранность данных критично важна.

А вообще, изменение требований к продукту — явление довольно частое. Иногда это влечёт за собой трансформацию структуры данных. В реляционных базах данных это решается с помощью ALTER TABLE, а вот в DynamoDB этой штуки просто нет. Изменение схемы тут обходится очень дорого. Нам приходится пересоздавать таблицы или использовать Elastic MapReduce. За оба варианта приходится платить. Много данных = много денег. Чтобы с этим как-то справиться, пришлось выбирать все данные Scan'ом по 1 мегабайту, а после записывать в новую таблицу. Отнимает очень много времени, но это плата за отсутствие DBA.

Впечатления от DynamoDB

Наш эксперимент по использованию DynamoDB удался. Это потрясающая база данных, которая отличается простотой масштабирования. Работаете с ней и забываете про администрирование. Но помните: взамен она требует аккуратного обращения на этапе проработки архитектуры. Иначе возможны всякие там неожиданные повороты и неприятные грабли. Мы рекомендуем использовать DynamoDB, если некритичных данных много, а работать с ними надо часто. Мы пользуемся — нам нравится» :)

***
Общайтесь легко и непринуждённо в Диалогах на английском — практикуйте английский язык в приятной компании и присоединяйтесь к нашей команде!

Следите за новостями на Facebook, Вконтакте и в Twitter, делитесь впечатлениями и получайте удовольствие. Свобода общения — это здорово!

Хроники LinguaLeo: как мы сделали «Диалоги на английском» с Node.js и DynamoDB Команда LinguaLeo

Автор: LinguaLeo

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js