В этой статье я расскажу, как мы разрабатывали облачный сервис Scorocode, с какими проблемами столкнулись, и, что самое важное, поделюсь планами развития.

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

Предпосылки


Уже с 2011 года я активно использовал Parse для проведения быстрых экспериментов с разработкой мобильных и web-приложений. Полезность сервиса не вызывала сомнений, лишь некоторые огрехи периодически вызывали желание найти что-то более удобное.

Со временем, попробовав несколько похожих сервисов, я пришел к следующим выводам:

  1. Backend как сервис нужен многим разработчикам систем в архитектуре «клиент-сервер», так как ускоряет работу в разы, особенно на начальном этапе, когда структура данных и серверная логика уже нужны, а ресурс для её разработки ограничен.
  2. Основной функционал такого сервиса: структурированное хранение и доступ к данным с помощью SDK для разных платформ и возможность разработки серверной логики. Дополнительный функционал, как сообщения sms/push/email, готовые объекты типа пользователи/роли, с одной стороны, может реализовываться разработчиками самостоятельно, с другой стороны, еще больше ускоряет работу и позволяет сосредоточиться на frontend.
  3. Нет ни одного сервиса с полноценной документацией на русском языке. Да, есть переводы кусков и небольшое количество примеров, но они не дают полного понимания возможностей и подводных камней сервиса.

В связи с этим возникла идея разработки подобного сервиса для русскоязычной аудитории, в котором можно было бы реализовать собственные пожелания и пожелания пользователей.

Историю о том, как мы в 2015 году проходили организационный путь от идеи до инвестпроекта опущу, об этом лучше расскажут мои коллеги. А вот на технической части остановлюсь подробнее.

Средства разработки


После определения минимума функций, которые нужно было реализовать, стали определяться со средствами разработки.

Вариант использования платного проприетарного ПО сразу было отметен в связи с его несостоятельностью. Основной причиной явилось то, что в течение последних 5-6 лет отрасль разработки ПО претерпела сильные качественные изменения в положительную сторону. Те задачи, которые раньше могли решаться исключительно с помощью платформ и средств «монстров» IT, сегодня могут быть решены быстро и эффективно с помощью современных средств разработки, языков программирования и платформ, большинство из которых распространяется под лицензией MIT.

Итак, мы сформировали перечень функций, и стали выбирать платформу, на которой будет работать основная часть сервиса – сервер API. По нашему мнению, один сервер должен был держать не менее 10 тысяч запросов в секунду, чтобы из таких серверов можно было собирать кластеры, выдерживающие нагрузку до 50 тысяч запросов в секунду. Это число появилось не случайно. В одной из разрабатываемых нами промышленных систем есть именно такие требования к нагрузке, и мы приняли его за отправную точку, с прицелом на перевод backend этой системы в облако (кстати, использование требований к этой же системе нам позволило рассчитать экономические выгоды от использования облачного backend).

В итоге было протестировано 3 варианта реализации API с форматом обмена JSON. Тестирование проводилось с помощью Яндекс.Танк. Результаты:

  1. Node.js + Express.js – 4 000 запросов в секунду
  2. Node.js + Total.js – 1 500 запросов в секунду
  3. Собственный сервер, написанный на Golang – 20 000 запросов в секунду

Добавлю, что в качестве СУБД была единогласно выбрана mongoDB, как современная, масштабируемая СУБД, выдерживающая большие нагрузки, с подробной и качественной документацией и большим числом примеров и драйверов под популярные языки программирования.

Выбор был сделан в пользу собственной разработки, и мы начали прорабатывать архитектуру.

Архитектура


Основной задачей при построении архитектуры сервиса была реализация масштабируемой кластерной системы. После экспериментов мы пришли к следующей конфигурации:

  • Точка входа запросов к API – DNS Round Robin, распределяет вызовы между балансировщиками;
  • Балансирировщик – Nginx, распределяет запросы между серверами API;
  • Сервер API – собственная разработка на Golang, реализована в архитектуре MC (Model-Controller), каждый сервер получает данные о приложении из основной базы данных (mongoDB), в том числе адрес кластера данных, в котором хранятся данные приложения, кэшируя эти данные (кэш в Redis – 10 минут, со сбросом при внесении изменений в приложение);
  • Кластер данных – кластер mongoDB и инстанс Redis;
  • Файловое хранилище – OpenStack Swift;
  • Сервер очередей – RabbitMQ, используется для постановки в очередь заданий на запуск серверных скриптов, отправки сообщений и т.п.
  • Микросервисы – собственные разработки на Golang: миграция с Parse, отправка сообщений (email, PUSH, SMS), выполнение серверного кода (модуль, использующий движок Google V8)

В процессе разработки и тестирования возникало много мелких задач, но в целом архитектура оказалась жизнеспособной и комплекс успешно прошел испытания.

Функции


Как я уже писал выше, на начальном этапе мы реализовали базовый функционал. Границы минимального набора базировались на необходимости миграции пользователей Parse и минимальными требованиями к функциям backend для разработки не очень сложных приложений.

В ходе реализации функциональности возникали серьёзные и не очень проблемы. Пару характерных привожу ниже.

Проблема 1. Скорость парсинга BSON.


Как вы знаете, mongoDB отдает данные в формате BSON, который достаточно просто разбирается и конвертируется в JSON. Тем не менее на больших объемах парсинг BSON занимает довольно приличное время. К примеру, на выборке 1000 документов среднего размера парсинг BSON в JSON занимает более 1,5 секунд. Для нас такая скорость была неприемлемой.

Попробовали полностью переписать парсер драйвера mgo.v2. Не помогло. Пришли к выводу, что уменьшить время можно было либо увеличением частоты и количества ядер на сервере, либо перекладыванием этой задачи на клиента.

В итоге было принято решение все выборки возвращать в формате BSON с последующим разбором в SDK на клиенте. Так это и работает по сей день.

Проблема 2. Скорость работы триггеров JavaScript.


Изначально движком, который будет выполнять серверные скрипты, был выбран Google V8, и он прекрасно справился со своей задачей для асинхронных скриптов. А вот с триггерами на операции с данными возникли проблемы.

Сам движок V8 очень шустрый, но стартует он относительно медленно – 150-300 миллисекунд. А у нас было ограничение на время работы триггера – 500 миллисекунд. Отдавать половину этого времени на старт движка было неразумно. Создавать пул заранее запущенных «воркеров» – нажить кучу проблем с переключением контекстов.

Поэтому для триггеров нами был выбран самый быстрый вариант для выполнения кода JavaScript в Golang – библиотека Otto Роберта Кримена. Да, у нее есть определенные ограничения, но для задачи выполнения триггеров она подошла идеально. На основе этой библиотеки нами был реализован «терминатор» стека вызовов для прерывания бесконечного цикла вызовов триггеров (например, когда в триггере beforeInsert вызывается операция insert).

О проблемах и задачах, возникающих в процессе реализации, можно писать бесконечно. Надеюсь, что аудитория сама укажет технические темы, о которых интересно было бы почитать, и я с удовольствием о них расскажу.

Что дальше?


Сейчас мы запланировали и начали работы над новыми функциями системы. Учитывая стабильно высокий уровень интереса к сервису Scorocode, мы бы хотели узнать мнение сообщества о необходимости реализации таких функций. Готовы ответить на все ваши вопросы в комментариях к статье.
Какие из функций вы хотели бы увидеть в облачном сервисе Scorocode?

Проголосовало 33 человека. Воздержалось 15 человек.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Поделиться с друзьями
-->

Комментарии (7)


  1. DiegoV
    10.08.2016 13:51
    +1

    Хотелось бы увидеть от вас какую-либо обучающую статью для тех, кто ни разу не работал с Backend сервисами. Объяснить что это, с чем это едят, как правильно использовать, ну и конечно же простые, но реальные примеры взаимодействия (желательно с кодом) приложения и scorocode. Сам я занимаюсь разработкой на Xamarin (C#.Net), и был бы очень рад подобному уроку от профессионалов.


    1. juggleru
      10.08.2016 13:54
      +1

      Спасибо за комментарий, Павел.

      Уже готовим туториалы и планируем выпуск SDK для других языков, в частности C#. Следите за обновлениями платформы.


      1. DiegoV
        11.08.2016 11:39

        Обязательно, сервис за интересовал и уже руки чушутся применить его в своих проектах. Осталось дождаться примеров и документации.


  1. InstaRobot
    11.08.2016 01:33

    Здравствуйте! npm прикрутите, тогда цены вам не будет


    1. watsonstudio
      11.08.2016 09:42

      Здравствуйте. Уже работаем в данном направлении.


  1. filatoff
    12.08.2016 13:24

    Перечислите, пожалуйста, основные отличия от Firebase


    1. rockyou
      12.08.2016 17:15

      Мы предлагаем подобную Firebase функциональность, но различаемся по реализации. В другом — мы ориентированы на русскоязычный сегмент разработчиков, размещаем данные в надёжном IaaS облаке на территории России, предоставляем поддержку на русском языке и документацию, открыты к изменениям и пожеланиям сообщества.