![](https://habrastorage.org/storage2/113/540/089/113540089a6ff7822587234714dc967f.png)
Пользователи LinguaLeo начинают изучать английский язык в Джунглях — хранилище тысяч материалов разного уровня сложности, формата и тематик; шаг за шагом учатся слышать и понимать речь носителей языка и расширять словарный запас. Кому нужна грамматика — идут в Курсы. Словарный запас пополняется не только из Джунглей, при добавлении незнакомых слов в Личный словарь, но и с помощью подготовленных Наборов слов, доступных для индивидуального изучения. В разделе Общение можно вести Диалоги на английском, чтобы практиковать язык с другими пользователями LinguaLeo в режиме real-time, выбирая темы для общения. Общение только на английском!
Для создания Диалогов на английском мы использовали Node.js, DynamoDB (все на AWS). Сейчас поделимся нашим опытом.
█ Почему Node.js?
![](https://habrastorage.org/storage2/f2e/32d/3fe/f2e32d3fe7465c41a0239358d0f78e08.png)
«… Чтобы обеспечить нашим пользователям все возможности для общения, мы выбрали технологию Node.js. Почему? Node.js адекватен для работы со stream'ами, где существует огромное количество модулей. Кроме того, грамотный JavaScript-программист, работая на Node, сможет реализовать весь объём задачи, а не только её серверную часть (в отличие, например, от специалиста по Erlang).
В качестве «транспортного узла» между сервером и клиентом мы использовали WebSockets как наиболее быстрый способ доставки информации.
Для решения проблемы кросс-платформенности нами была выбрана библиотека Sock.JS. Во-первых, из-за соответствия стандартам W3C для WS, а во-вторых, Sock.JS отлично подходит для наших потребностей.
![](https://habrastorage.org/storage2/c5c/af4/8da/c5caf48da7a8f592c4f184c2cff8b8fd.jpg)
Итак, поехали. Демон Node.js мы запустили на «облачных» мощностях Amazon EC2. Деплоится приложение через git. За логирование и перезапуск отвечает модуль forever. К слову, у Amazon'а есть очень полезный сервис — Amazon Cloudwatch. Его функционал позволяет мониторить основные параметры системы, а главное его достоинство — настраиваемые нотификации, которые позволяют следить только за тем, что действительно важно. Для получения детальной информации о состоянии приложения мы используем nodetime.
![](https://habrastorage.org/storage2/da9/f99/565/da9f995653043b3ce6815fccd28b29f1.jpg)
В качестве драйвера для работы с DynamoDB используется модуль dynode. Он хорошо себя зарекомендовал, однако несовершенная техническая документация добавила дёгтя в бочку мёда. Официальный Node.js SDK от Amazon'а вышел позднее и всё ещё находится в стадии Developer Preview. Таким вот
![](https://habrastorage.org/storage2/ace/a39/cea/acea39cea53d2d5cd8cdb285aa3541fc.jpg)
█ Тонкости работы 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 — хранение метаданных диалога, кэширование последнего сообщения.
![](https://habrastorage.org/storage2/c45/912/34d/c4591234d0c9e49885e56c947eb72aa6.jpg)
UserDialogs — список диалогов пользователя, кэширование + счетчик непрочитанных сообщений.
![](https://habrastorage.org/storage2/2e1/c56/b3d/2e1c56b3d6797c1254cd8c4b38546e1b.jpg)
Messages — все сообщения пользователей.
![](https://habrastorage.org/storage2/2fc/af8/85f/2fcaf885fd29d20a292f47f16c24e1ea.jpg)
User2User — участники диалога.
![](https://habrastorage.org/storage2/9e0/19c/5f3/9e019c5f37bf6dbfe6ce2394e947f48c.jpg)
Пример 1
Процесс получения всех диалогов пользователя для страницы «Мои диалоги на английском» реализован нестандартно. На странице пользователь видит все свои диалоги, в том числе общее количество непрочитанных сообщений, а также последнее сообщение каждого диалога.
Данные выбираются за два запроса. Первый – это выборка всех dialogld из таблицы UserDialogs с помощью Query. Второй – это получение диалогов посредством BatchGetItem. Тут есть небольшой нюанс — BatchGetItem за один раз выбирает максимум 100 сообщений. Поэтому, если их у пользователя 242 штуки, нам потребуется сделать 3 запроса, что занимает около 70-100 миллисекунд. Помня об этом и стремясь к большей оптимизации производительности, мы кэшируем данные диалогов в ElasticCache, обновляя его при каждом новом сообщении.
![](https://habrastorage.org/storage2/a6b/8c8/16b/a6b8c816b48e8c0ef8d6a586d6ec34c8.png)
Пример 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, делитесь впечатлениями и получайте удовольствие. Свобода общения — это здорово!
![](http://habr.habrastorage.org/post_images/f7b/bb8/f60/f7bbb8f6061695fe55a540824f4428f3.png)