yoihj
0

Только вот характеристики тут тогда принципиально отличаются. Тарантул (насколько я понимаю) если сказал "сделано" — то оно сохранено на диске. А вот in-memory не сохраняют на диск ничего.

yoihj
0
конвертация в JSON и обратно зачастую тоже довольно медленная вещь

я пытался в минимальном самом простом виде воспроизвести JSON API доступный по HTTP. последним шагом в JSON API идет конвертация в JSON

yoihj
0

nginx.conf


 worker_processes 1; # ходим в 1 процесс - увиличивем если балансируем в N tnt
yoihj
0

Брал все из gist. Воркеров чего nginx или golang? Если golang — то я в самом начале статьи сказал, что на одно ядро производительность сравнима (или, может, даже лучше :) ).

yoihj
+1

nginx.conf


upstream go {
  server 127.0.0.1:8080;
  keepalive 10000;
}

upstream tnt {
  server 127.0.0.1:10001; # ходим в 1 tarantool -- можно балансировать в больше
  keepalive 10000;
}

server {
    listen 8081 default;

    server_name tnt;

    location = /tnt {
      tnt_pass_http_request on; # пропускам http данные
      tnt_http_rest_methods get; # только get
      tnt_method 'handler'; # вызываем function handler()
      tnt_pass tnt;
    }

    location = /go {
      proxy_pass go;
    }
}

Test:


➜  nginx git:(master) ✗ curl 127.0.0.1:8081/go
"bar"%                                                                                                                                                                                                                                                                        ➜  nginx git:(master) ✗ wrk -t 4 -c 10 -d 5 --latency http://127.0.0.1:8081/go
Running 5s test @ http://127.0.0.1:8081/go
  4 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   297.07us  188.09us   5.74ms   92.84%
    Req/Sec     6.79k   353.23     7.91k    79.80%
  Latency Distribution
     50%  268.00us
     75%  352.00us
     90%  444.00us
     99%  841.00us
  137159 requests in 5.10s, 15.83MB read
Requests/sec:  26896.15
Transfer/sec:      3.10MB
➜  nginx git:(master) ✗ wrk -t 10 -c 100 -d 5 --latency http://127.0.0.1:8081/go
Running 5s test @ http://127.0.0.1:8081/go
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.11ms    1.33ms  17.15ms   76.48%
    Req/Sec     3.24k     1.05k   25.94k    99.60%
  Latency Distribution
     50%    3.02ms
     75%    3.73ms
     90%    4.60ms
     99%    7.18ms
  161791 requests in 5.10s, 18.67MB read
Requests/sec:  31711.10
Transfer/sec:      3.66MB
yoihj
0

[удален, не туда ответил]

yoihj
0

давайте, только не обещаю сильно активно участвовать — работа тоже есть :)

yoihj
0

В целом (у меня тоже мак, так что оставил kqueue) nginx_upstream получилось так (код взят из gist)


➜  nginx git:(master) ✗ curl 127.0.0.1:8081/tnt
{"id":0,"result":[["bar"]]}%                                                                                                                                                                                                                                                  ➜  nginx git:(master) ✗ wrk -t 4 -c 10 -d 5 --latency http://127.0.0.1:8081/tnt
Running 5s test @ http://127.0.0.1:8081/tnt
  4 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   550.88us  144.06us   2.28ms   74.29%
    Req/Sec     3.61k   536.23     4.10k    81.37%
  Latency Distribution
     50%  516.00us
     75%  610.00us
     90%  766.00us
     99%    0.96ms
  73337 requests in 5.10s, 14.55MB read
Requests/sec:  14381.01
Transfer/sec:      2.85MB
➜  nginx git:(master) ✗ wrk -t 10 -c 100 -d 5 --latency http://127.0.0.1:8081/tnt
Running 5s test @ http://127.0.0.1:8081/tnt
  10 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     9.14ms    2.49ms  18.70ms   66.40%
    Req/Sec     1.09k   437.60     9.36k    93.01%
  Latency Distribution
     50%    9.31ms
     75%   10.88ms
     90%   12.11ms
     99%   13.64ms
  54184 requests in 5.10s, 10.75MB read
Requests/sec:  10626.29
Transfer/sec:      2.11MB
yoihj
0

Вроде поставил все, но результат что-то немного другой:


➜  nginx git:(master) ✗ curl 127.0.0.1:8081/tnt
{"id":0,"result":[["bar"]]}

а должен быть


"bar"

хотя вроде


  return { var[2] } -- только bar

А где чат?

yoihj
0
Вы задали ровно тот же вопрос, на который я уже ответил.
yoihj
+1
Заинтриговали, пойду tnt_pass попробую :)
yoihj
0
Да, там еще нюанс упущен

https://gist.github.com/dedok/d84b82b2863b778f47ca05c17cbf3b25

Я финальным шагом `bar` в json конвертирую, т.е. в `«bar»` — конвертация в JSON и обратно зачастую тоже довольно медленная вещь. Поэтому и в Go, и в Tarantool проверял это последним шагом.
yoihj
0
P.S. Бинарный протокол-то я протестировал из Go (там добавил в статью) и результат примерно на уровне. Т.е. теории 2 у меня — либо клиент go-tarantool тормозит (что не исключено из-за использования interface{}, но оно тут неизбежно), либо все же дело не в http сервере tarantool.
yoihj
+1
Я уже отвечал на этот аргумент тут

Если мне нужен Фотошоп для одного фильтра — я имею право сравнивать Фотошоп и программу, имеющую только этот один фильтр.

Реализация k-v хранилища тут примерно одинаковая. Да, в Tarantool есть другие возможности — я это написал в статье и в комментариях несколько раз. Да, сравнивается конкретный случай — я это тоже написал и в статье, и в комментариях.
yoihj
0
Ну, я думал это само собой разумеется, что тест для отдельного случая и я вовсе не говорю что Tarantool надо забросить и он никуда не годится.

Просто в обратную сторону тоже можно также бросить — реализуйте в Tarantool ВЕСЬ функционал всех библиотек Go, а потом сравнивайте…

Сравнение вполне конкретное, более того — Tarantool выглядит достойно. Я описал минусы по которым он мне в моем случае не подходит, но это ж не значит что это случай всех и вся.
yoihj
0
https://github.com/valyala/fasthttp выглядит интересно, но как-то не очень понятно как это скрестить с zero-downtime restarts — а это, в общем-то, довольно важно.
yoihj
0
Тест через wrk = многопоточный + мультиплексирование (4 потока, 10 соединений и 10 потоков, 100 соединений)

К сожалению, уже не осталось времени тестировать что-то подобное. Вполне возможно, хотя последний добавленный тест go+go-tarantool, в общем-то, надежды большой не дал.
yoihj
+1
Добавил сравнение в конец статьи, оказалось, к сожалению, не быстрее. Думаю что это сильно связано с тем, что постоянно приходится типы из interface{} в строки переводить — но тут так реализован клиент — процессоры горят на полную.
yoihj
+1
Добавил сравнение в конец статьи.
yoihj
0
Все верно. Для моего случая это скорее недостаток, для кого-то, вероятно, — критично.
yoihj
0
Я тут без понятия — я просто знал что для Go есть несколько KV хранилищ, взял первые два попавшиеся ради интереса :) Никогда не эксплуатировал ее. Насколько я понимаю, авторы (Facebook) рекомендуют все же идти дальше и пользовать RocksDB (который у меня просто не скомпилировался в виде embedded, только в виде shared библиотеки, что не очень мне понравилось, поэтому открыл им issue и оставил за рамками статьи)

Думаю гугление на тему backup leveldb должно раскрыть тайну :)
yoihj
0
На один комментарий ниже отписался. https://habrahabr.ru/post/282299/#comment_8867187
yoihj
0
Собственно, меня от этого остановило то, что хотелось попробовать именно «сервер БД прямо рядом с кодом» — как это и сделано в tarantool.
yoihj
0
Ну ок, у всех сейчас многоядерные сервера и машины и как бы в один поток ограничивать go — смысла большого нет, ибо на бою хочется именно использовать по-максимуму ресурсы системы, и вот тут вопрос.

А как использовать все ядра-то на Tarantool? Т.е. я так понял что для этого надо запускать несколько tarantool и включать на них master-master репликацию и потенциально связываться с конфликтами записи? Master-slave я так понимаю не решит тут, если речь идет о равном количестве записей и чтений (т.е. условно write-bound нагрузка)
yoihj
0
> Обновление кода без перезагрузки сервера

Чуть ошибся. Имел в виду, что возможно это делать «без потери запросов», а не без перезагрузки :) Пардон.
yoihj
+6
С таким подходом вообще ничего в мире сравнивать нельзя. Как пример: MySQL это база со многими engine, а Redis это key-value кэш с другими характеристиками. Но неужели это автоматически обозначает что я не могу одну и ту же задачу решить на MySQL и на Redis? В одном случае мне одни плюшки предоставит система, а другие придется делать руками, в другом — другие предоставит другая система, а в первой их придется делать руками.

Тот же случай и тут. Я взял общий делитель — операцию которую можно сделать в обоих случаях. И сравнил ее по скорости. В чем проблема?
yoihj
+1
Отличные комментарии. Пару вещей хотелось бы правда, уточнить:

> 1. Обновление кода без перезагрузки сервера

Это я показал уже в статье после комментария — это более чем возможно.

> 2. Хранимые процедуры

Собственно говоря, Golang это и есть в данном случае «хранимая процедура». Просто склейка получается в другом направлении — к языку мы приклеиваем базу (golang + leveldb/rocksdb), а не к базе приклеиваем язык (tarantool.box + lua), но результат-то тот же получается — быстрый язык рядом с базой.

> 3. Репликация master-slave и master-master

Это абсолютно верно и это я и указал в статье — репликация, пока что, это важное достоинство, что есть у Tarantool. Хотя master-master я что-то не нашел (плохо искал?) А вот master-slave меня напугал когда прочитал что-то в духе, что изменение одних и тех же данных на двух разных slave полностью останавливают базу и требуется вмешательство админов… Вот тут у меня наступил некий ступор с тем как Mail.Ru справляется с этим на огромных объемах.

> 4. Другие СУБД-фишки (транзакции, например)

LevelDB, вроде, не поддерживает (не специалист тут, к сожлению), но вот RocksDB (следующее поколение от LevelDB) уже поддерживает.

Еще, к списку я бы добавил secondary index — это действительно тоже сильная сторона Tarantool.

> Кроме того, очевидно, что выставлять http-сервер на go в интернет плохо

Моя задача на самом деле не написание серверов для интернета, а бэкэндовых серверов для внутреннего потребления. Но я не скажу что выставлять go http это плохо или прямо драматично хуже чем nginx. Да, мы используем nginx почти везде и его преимущества очевидны, но, не все описанное Вами верно. Некоторые из них:

> делать различные административные действия (типа как rewrite и прочие)

Собственно, через gorilla/mux это решается примитивнейше в go.

> хорошо обрабатывать медленных клиентов

Golang с этим справляется ничуть не хуже nginx, в общем-то. Такие же мультиплексированные потоки на несколько тредов + асинхронная обработка.

> надо отдавать статику в конце концов

Тоже, в общем-то, достойно работает в Go.

Я не говорю что nginx это плохо, опять же — мы его используем почти везде, но я бы не был так категоричен с «выставлять http-сервер на go в интернет плохо».

> мы это обязательно протестируем, используя ваши тесты и выложим результаты.

Будет очень интересно прочитать. Я, если честно, вообще удивился что тестирования golang+X vs tarantool не нашел сходу.

> А в случае go + leveldb что делать?

Не очень понятна сложность, это вроде стандартный nginx upstream + proxy_next_upstream умеют делать?

> Будем улучшать! :)

:thumbs_up:

Ну и как бы мое мнение не является тут окончальным для всех — всегда нужен контекст. Наш контекст что у нас уже есть специалисты на Go + много кода и если бы вдруг Tarantool показал бы результаты там в 10 раз лучше — ну тогда бы имело смысл, конечно. А так переход не имеет большого смысла.
yoihj
0
> Обновлять код без перезагрузки сервера можно в Erlang ;)

Ну я абсолютно лично за то, чтобы это было во всех языках :)
yoihj
0
Все верно, как и сказано — сугубо ненаучно :) Моя задача была понять для себя — есть ли в Tarantool такое огромное преимущство, что стоит отказаться от Golang или использовать рядом с ним. Для этого вполне достаточно на одной машине сравнить — ведь нагружающий `wrk` одинаковое количество ресурсов скушает, так что отличие по производительности будет зависеть только от тестируемой стороны. Какая быстрее — та и быстрее :)
yoihj
0
Добавил в конец статьи пример замены кода.
yoihj
0
Верная мысль, в теории можно попробовать RocksDB или какие-то другие которые более хорошо умеют с lockами работать. Там в принципе, лок-то нужен только на время рестарта.
yoihj
0
Можно подробнее? Что имеется в виду под «отдельные ноды»? Ноды серверов? И что именно в нотации JSON нужно?
yoihj
0
Я, кстати, вот про это атомарное обновление не нашел, хороший момент. С другой стороны — раз уж мы говорим про http — то есть https://github.com/fvbock/endless который как раз и делает атомарное обновление — им мы на работе и пользуемся чтобы там, имея тысячи запросов в секунду к бэкэнду — без потерь запросов обновлять код.
yoihj
+1
Не совсем, leveldb встроен как библиотека и по сути хранит все в файле. Т.е. перезапускается все.
yoihj
+13
> От игр и 3d веб сайтов на мультитач-устройства, до embeded систем на микроконтроллеры.

«Вакансия: водитель.Требования: профессиональные навыки в управлении легковыми и грузовыми автомобилями, троллейбусами, трамваями, поездами метрополитена и фуникулёра, экскаваторами и бульдозерами, спецмашинами на гусеничном ходу, боевыми машинами пехоты и современными легкими/средними танками, находящимися на вооружении стран СНГ и НАТО. Навыки раллийного и экстремального вождения обязательны… „

далее тут
yoihj
+1
пардон, «интереса»
yoihj
+1
Чисто ради интересна — и как же это на PHP можно оптимизировать кэш L1/L2?