Строим сервисы на базе Nginx и Tarantool

от автора

Вам знакома такая архитектура? Хоровод демонов, пляшущих между web-server, cache и storage.

Какие минусы такой архитектуры можно отметить? Решая задачи в рамках такой архитектуры, мы сталкиваемся с кучей вопросов: какой язык(и?) взять, какой I/O framework выбрать, как синхронизировать cache и storage? Куча инфраструктурных вопросов. А зачем решать инфраструктурные вопросы, когда надо решить задачу? Безусловно, можно сказать, что нам нравятся некие технологии X и Y, и перевести эти минусы в рамки идеологических. Но нельзя отрицать тот факт, что данные располагаются на неком расстоянии от кода (картинка выше), что добавляет latency, что может уменьшить RPS.

Цель данной статьи — рассказать об альтернативе, которая построена на базе Nginx как web-server, bаlancer и Tarantool как App Server, Cache, Storage.

Улучшаем cache и storage

У Tarantool есть несколько интересных свойств. Tarantool — это не только эффективная inmemory DB, но и полноценный Application Server, приложения пишутся на Lua (luajit), C, C++, т.е. можно написать логику любой сложности, ограничение одно: фантазия. Если данных больше, чем доступно памяти, часть данных можно хранить на диске, используя движок Sophia. Если Sophia не подходит, можно взять что-то другое и скидывать «холодные» данные, т.е. данные, которые не нужны прямо сейчас, из Tarantool в другой Storage, а «горячую» часть хранить в Tarantool, т.е. в памяти. Какие преимущества это дает нам?

  • Нет посредников. Как минимум горячая часть данных находится на одном уровне с кодом.
  • Горячие данные в памяти.
  • Код достаточно простой и легко обновляется, если мы говорим о Lua.
  • Транзакции, репликация, шардинг и можество других возможностей Taranool.

Улучшаем web-server

Конечным потребителем данных является пользователь. Обычно, пользователь получает данные от Application Server через Nginx как балансер/прокси. Вариант написания демона, который умеет общаться и с Tarantool, и с HTTP не подходит, так как приведет нас к первому рисунку, и мы опять вернёмся к тому, с чего начали. Поэтому попробуем взглянуть на ситуацию с другой стороны, и задать другой вопрос: «Как избавиться от посредников между данными и пользователем?». Ответом на этот вопрос и стала реализация Tarantool Nginx Upstream Module.

Nginx Upstream

Nginx Upstream — это персистентное (см. Upstream Keepalive) соединение через pipe/socket к backend, далее будем называть это «проксированием». Nginx предоставляет много разнообразного функционала для написания правил Upstream, для проксирования HTTP в Tarantool особое значение приобретают следующие возможности:

  1. возможность указывать несколько backend, на которые Nginx будет балансировать нагрузку;
  2. возможность указывать backup, т.е. указывать, куда ходить, если Upstream не работает.

Эти возможности позволяют:

  1. распределять нагрузку на N Tarantool, например, вкупе с шардингом можно построить кластер с равномерной загрузкой по нодам;
  2. можно сделать отказоустойчивую систему при помощи репликации;
  3. используя п. а) и п. b) получим отказоустойчивый кластер.

Пример конфига для Nginx, частично иллюстрирующий возможности настроек:

   # Настройки проксирования в Tarantool    upstream tnt    {       server  127.0.0.1:10001;      # первый сервер живет на localhost       server  node.com:10001;     # второй где-то еще       server  unix:/tmp/tnt;           # третий через unix socket        server  node.backup.com  backup; # а тут backup     }     # HTTP-сервер     server     {         listen 8081 default;         location = /tnt/pass {           # Говорим Nginx что надо использовать Tarantool Upstream Module           # и указываем имя Upstream           tnt_pass tnt;          }     } 

Более детально о конфигурировании Nginx Upstream можно прочитать тут: http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream.

Nginx Tarantool Upstream Module (v0.1.4 Stable)

Основной функционал:

  • модуль активируется в Nginx.conf директивой — tnt_pass UPSTREAM_NAME;
  • быстрое потоковое преобразование HTTP + JSON <-> Tarantool Protocol, минимальные блокировки (на время парсинга) Nginx worker;
  • неблокирующее I/O Nginx в оба направления;
  • как приятный бонус: все фичи Nginx, Nginx Upstream;
  • модуль позволяет вызывать хранимые процедуры Tarantool через JSON-based Protocol;
  • данные доставляются через HTTP(S) POST, что удобно для Modern WebApps и не только.

Входные данные

[ { "method": STR, "params":[arg0 ... argN], "id": UINT }, ...N ]

«method»
Имя хранимой процедуры. Имя должно совпадать с именем процедуры в Tarantool. Например, чтобы вызвать lua-функцию do_something(a, b), надо: “method”: “do_something”

«params»
Аргументы хранимой процедуры. Например, чтобы передать аргументы в lua-функцию do_something(a, b), надо: “params”: [ “1”, 2 ]

«id»
Числовой идентификатор, устанавливается клиентом.

Выходные данные

[ { "result": JSON_RESULT_OBJECT, "id":UINT, "error": { "message": STR, "code": INT } }, ...N ]

«result»
Данные, которые вернула хранимая процедура. Например, lua-функция do_something(a, b) возвращает return {1, 2} то “result”: [[1, 2]]

«id»
Числовой идентификатор, установленный клиентом.

«error»
Если произошла ошибка, в этом поле будут данные о причинах.

Более детальней о протоколе тут: https://github.com/tarantool/nginx_upstream_module/blob/master/README.md

Hello World

Запускам Nginx

Nginx мы соберем из исходников:

$ git clone https://github.com/tarantool/nginx_upstream_module.git $ cd nginx_upstream_module $ git submodule update --init --recursive $ git clone https://github.com/nginx/nginx.git $ cd nginx && git checkout release-1.9.7 && cd - $ make build-all-debug  

Цель build-all-debug — это debug-версия. Делаем так, чтобы меньше конфигурировать Nginx. Для тех, кто хочет законфигурировать все с нуля, есть цель build-all.

Файл test-root/conf/nginx.conf

http {     # Добавляет один Tarantool как backend     upstream echo     {       server 127.0.0.1:10001;     }     server     {         listen 8081 default; # Nginx повесим на *:8081          server_name tnt_test;          location = /echo # на *:8081/echo вешаем ‘echo’ Tarantool Upstream         {           tnt_pass echo;         }     } } 
$ ./nginx/obj/nginx # запускаем nginx 

Запускаем Tarantool

Tarantool можно поставить из пакетов, либо собрать.

Файл hello-world.lua

-- Это и есть наша хранимая процедура, она предельно простая и не использует Tarantool как DB. -- Все что она делает - это просто возвращает свой 1-й аргумент. function echo(a)      return  {{a}} end  box.cfg {     listen = 10001; -- указываем куда вешаем Tarantool } 

Если вы поставили Tarantool из пакетов, запустить его можно так:

$ tarantool hello-world.lua # первым аргументом передаем имя lua-скрипта. 

Вызываем хранимую процедуру

Вызвать хранимую процедуру echo можно любым HTTP-коннектором, все что нужно сделать — HTTP POST по 127.0.0.1/echo и в теле передать следующий JSON (см. Входные данные):

{   "method":"echo", // имя метода, должно совпадать с именем метода в Tarantool    "params":[      {"Hello world": "!"} // 1-й аргумент - объект    ],    "id":1 // ID сообщения } 

Я вызову эту процедуру wget’ом

$ wget 127.0.0.1:8081/echo --post-data '{"method":"echo","params":[{"Hello world": "!"}],"id":1}' $ cat echo {"id":1,"result":[[{"hello world":"!"}]]} 

Еще несколько примеров:
https://github.com/tarantool/nginx_upstream_module/blob/master/examples/echo.html
https://github.com/tarantool/nginx_upstream_module/blob/master/test/client.py

Подведем итоги

Плюсы использования Nginx Tarantool Upstream Module:

  • нет посредников, код и данные, как правило, на одном уровне;
  • относительно простое конфигурирование;
  • балансировка нагрузки на N Tarantool;
  • высокая скорость работы, низкая latency;
  • JSON-based протокол вместо бинарного, не надо искать Tarantool Driver, JSON есть везде;
  • Tarantool Sharding/Replication и Nginx = кластерное решение, но это тема отдельной статьи;
  • решение используется в продакшене.

Минусы:

  • Overhead JSON вместо более компактного и быстрого MspPack;
  • решение не коробочное, нужно конфигурировать, нужно думать, как деплоить.

Планы:

  • поддержка OpenRasty и nginScript;
  • поддержка WebSocket и HTTP 2.0.

Результаты бенчмарка, а они очень даже интересные, будут в другой статье. Tarantool, как и Upstream Module, всегда открыт для новых пользователей, если у вас есть желание это все попробовать, использовать или выразить новую идею — обращайтесь на github, google group.

Ссылки

Сайт Tarantool — http://tarantool.org
Git Tarantool — https://github.com/tarantool/tarantool
Git Tarantool Nginx Upstream Module — github.com/tarantool/nginx_upstream_module
Google group — https://groups.google.com/forum/#!forum/tarantool

P.S. В следующей статье я покажу какие задачи можно решить, используя Tarantool.

ссылка на оригинал статьи http://habrahabr.ru/post/272141/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *