Comments 101
Я об этом говорил авторам тарантула чуть ли не с самого начала: посмотрите на го :).
С другой стороны, они все же немного о разном. В tarantool хранимые процедуры на lua и их можно (атомарно) обновлять без перезагрузки сервера и не теряя кеши. Если бы такое можно было делать в golang, то наверное ниши для тарантула не осталось бы. А пока что go не может целиком заменить ни nginx+lua, ни tarantool+lua, к сожалению :(.
С другой стороны, они все же немного о разном. В tarantool хранимые процедуры на lua и их можно (атомарно) обновлять без перезагрузки сервера и не теряя кеши. Если бы такое можно было делать в golang, то наверное ниши для тарантула не осталось бы. А пока что go не может целиком заменить ни nginx+lua, ни tarantool+lua, к сожалению :(.
+2
Как понял здесь роль хранилища выполняет leveldb, а go используется лишь как быстрый веб сервер, поэтому не надо все перезапускать
0
Не совсем, leveldb встроен как библиотека и по сути хранит все в файле. Т.е. перезапускается все.
+1
Я, кстати, вот про это атомарное обновление не нашел, хороший момент. С другой стороны — раз уж мы говорим про http — то есть https://github.com/fvbock/endless который как раз и делает атомарное обновление — им мы на работе и пользуемся чтобы там, имея тысячи запросов в секунду к бэкэнду — без потерь запросов обновлять код.
0
Есть вариант подключить интерпретатор LUA и менять скрипты атомарно уже в Golang сервере с LevelDB или любой другой встраиваемой базой.
Готовые интерпретаторы LUA пока не попадались, а вот javascript уже пару раз видел. Похоже что с такой целью его (js) в телефонной платформе ITooLabs используют (судя по докладу www.youtube.com/watch?v=HoEn7lXNQOU )
Готовые интерпретаторы LUA пока не попадались, а вот javascript уже пару раз видел. Похоже что с такой целью его (js) в телефонной платформе ITooLabs используют (судя по докладу www.youtube.com/watch?v=HoEn7lXNQOU )
+1
> Обновлять код без перезагрузки сервера можно в Erlang ;)
Ну я абсолютно лично за то, чтобы это было во всех языках :)
Ну я абсолютно лично за то, чтобы это было во всех языках :)
0
это очень легко делается в языках, где код и данные разнесены, но практически нерешаемая задача в языках, где код и данные живут в одном пространстве.
Даже в Эрланге есть ситуация, когда обновление кода становится проблемой из-за склейки кода и данных и её решают брутально.
Даже в Эрланге есть ситуация, когда обновление кода становится проблемой из-за склейки кода и данных и её решают брутально.
0
В Tarantool как раз код и данные живут в одном процессе, и при этом код можно менять без перезагрузки Tarantool :)
+1
Может вы достанете птицу феникса? (я про javascript)
Его знают многие, его изучение оправдано с так же с использованием на клиент сайде, да и нода-пользователи…
Его знают многие, его изучение оправдано с так же с использованием на клиент сайде, да и нода-пользователи…
0
UFO just landed and posted this here
В первую очередь, Слава, спасибо вам огромное за тест!
Я же правильно понимаю, что тест запускался на той же машине, что и тестируемая система?
Я же правильно понимаю, что тест запускался на той же машине, что и тестируемая система?
+1
Все верно, как и сказано — сугубо ненаучно :) Моя задача была понять для себя — есть ли в Tarantool такое огромное преимущство, что стоит отказаться от Golang или использовать рядом с ним. Для этого вполне достаточно на одной машине сравнить — ведь нагружающий `wrk` одинаковое количество ресурсов скушает, так что отличие по производительности будет зависеть только от тестируемой стороны. Какая быстрее — та и быстрее :)
0
На самом деле, тест хороший. И хоть и назван «ненаучным» он показывает явно, что golang + leveldb в каких-то кейсах быстрее Tarantool.
При этом у Tarantool перед goland + leveldb есть вполне себе очевидные преимущества:
1. Обновление кода без перезагрузки сервера
2. Хранимые процедуры
3. Репликация master-slave и master-master (важное преимущество — ибо с leveldb придется данные куда-то как минимум rsync'ать, ибо иначе стремно)
4. Другие СУБД-фишки (транзакции, например)
5. Поддержка других языков кроме Lua (сейчас это C и Swift, в будущем появятся и другие)
Кроме того, очевидно, что выставлять http-сервер на go в интернет плохо, т.к. надо терминировать SSL, надо делать различные административные действия (типа как rewrite и прочие), надо хорошо обрабатывать медленных клиентов, надо отдавать статику в конце концов. Со всем этим как мы прекрасно знаем прекрасно справляется nginx. Т.е. ставить nginx перед своим любимым http-сервером — это сейчас самый массовый кейс. А раз спереди ставится nginx, то его можно пускать в Tarantool не по медленному http, а по быстрому бинарному протоколу, например, как это было сказано тут: https://habrahabr.ru/company/mailru/blog/272141/
Кажется, что такая связка должна уделать golang, мы это обязательно протестируем, используя ваши тесты и выложим результаты.
Кроме того, если в app server'е есть внутри хранилище, то надо чтобы кто-то сверху роутил запросы на слейв, если упал мастер. В случае Тарантула есть стандартный nginx-модуль, который умеет это делать (см. статья выше). А в случае go + leveldb что делать? Плюс, как я сказал уже выше, репликацию leveldb придется писать руками.
В целом же, спасибо, что показали, что http-сервер в Тарантуле еще далек по производительности от совершенства. Мы стремимся к тому, чтобы даже на одном ядре работать быстрее чем все аналоги на всем сервере. Будем улучшать! :)
При этом у Tarantool перед goland + leveldb есть вполне себе очевидные преимущества:
1. Обновление кода без перезагрузки сервера
2. Хранимые процедуры
3. Репликация master-slave и master-master (важное преимущество — ибо с leveldb придется данные куда-то как минимум rsync'ать, ибо иначе стремно)
4. Другие СУБД-фишки (транзакции, например)
5. Поддержка других языков кроме Lua (сейчас это C и Swift, в будущем появятся и другие)
Кроме того, очевидно, что выставлять http-сервер на go в интернет плохо, т.к. надо терминировать SSL, надо делать различные административные действия (типа как rewrite и прочие), надо хорошо обрабатывать медленных клиентов, надо отдавать статику в конце концов. Со всем этим как мы прекрасно знаем прекрасно справляется nginx. Т.е. ставить nginx перед своим любимым http-сервером — это сейчас самый массовый кейс. А раз спереди ставится nginx, то его можно пускать в Tarantool не по медленному http, а по быстрому бинарному протоколу, например, как это было сказано тут: https://habrahabr.ru/company/mailru/blog/272141/
Кажется, что такая связка должна уделать golang, мы это обязательно протестируем, используя ваши тесты и выложим результаты.
Кроме того, если в app server'е есть внутри хранилище, то надо чтобы кто-то сверху роутил запросы на слейв, если упал мастер. В случае Тарантула есть стандартный nginx-модуль, который умеет это делать (см. статья выше). А в случае go + leveldb что делать? Плюс, как я сказал уже выше, репликацию leveldb придется писать руками.
В целом же, спасибо, что показали, что http-сервер в Тарантуле еще далек по производительности от совершенства. Мы стремимся к тому, чтобы даже на одном ядре работать быстрее чем все аналоги на всем сервере. Будем улучшать! :)
+10
Отличные комментарии. Пару вещей хотелось бы правда, уточнить:
> 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 раз лучше — ну тогда бы имело смысл, конечно. А так переход не имеет большого смысла.
> 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 раз лучше — ну тогда бы имело смысл, конечно. А так переход не имеет большого смысла.
+1
> Обновление кода без перезагрузки сервера
Чуть ошибся. Имел в виду, что возможно это делать «без потери запросов», а не без перезагрузки :) Пардон.
Чуть ошибся. Имел в виду, что возможно это делать «без потери запросов», а не без перезагрузки :) Пардон.
0
Перезагрузка сбрасывает все кэши в LevelDB и приводит к холодному старту. Холодный старт — это одна из главных болей on-disk storage engine.
+1
В Вашем примере новый инстанс сервера будет ждать (не обрабатывать новые запросы) пока старый инстанс не обработает ВСЕ текущие запросы (и не отпустит leveldb чтобы новый инстанс мог ее взять).
Это в общем случае может приводить к большому лагу во время обновления кода.
Или я неправильно понял пример?
Это в общем случае может приводить к большому лагу во время обновления кода.
Или я неправильно понял пример?
0
Все верно. Для моего случая это скорее недостаток, для кого-то, вероятно, — критично.
0
Можно написать код по передаче горячих данных от одного инстанца к другому. А так же сделать прослойку из goprotobuf, net/rpc поверх unix socket или любого другого протокола для связи с приложениями которым только доступ к данным нужен без вмешательство в работу самой базы.
Репликацию (sync) данных между двумя и более инстансами (даже сетевыми) делать на Golang не так сложно — это лишь всеголиш данные которые можно пушить сразу на два и более серверов, можно даже помечать в мастере те данные что успешно запушились куда-то ещё и при старте смотреть какие данные не помечены и отправлять их на реплику.
Думаю в статье основной посыл в следующем — разрабатывают Tarantool только +- десять человек, по большей части из Mail.Ru Group для себя или для корпоративных клиентов которым нужна поддержка, в то же время Golang пилится тысячей-другой человек по всему миру по всем возможным направлениям и то чего нет в Golang сейчас может совершенно спокойно появиться в течении пары дней, а не месяцев.
Репликацию (sync) данных между двумя и более инстансами (даже сетевыми) делать на Golang не так сложно — это лишь всеголиш данные которые можно пушить сразу на два и более серверов, можно даже помечать в мастере те данные что успешно запушились куда-то ещё и при старте смотреть какие данные не помечены и отправлять их на реплику.
Думаю в статье основной посыл в следующем — разрабатывают Tarantool только +- десять человек, по большей части из Mail.Ru Group для себя или для корпоративных клиентов которым нужна поддержка, в то же время Golang пилится тысячей-другой человек по всему миру по всем возможным направлениям и то чего нет в Golang сейчас может совершенно спокойно появиться в течении пары дней, а не месяцев.
+1
Это распространенное заблужение, что golang разрабатывают много человек. Контрибьютят, возможно. много, но именно активную разработку ведут все те же 10 человек плюс-минус лапоть (пруф предоставить не могу, ибо по «google dev team» ничего внятного не находится, но о размере своей команды они довольно часто говорят на разных презентациях).
+1
Я имел в виду разработку 100500 всевозможных пакетов на Golang и для Golang. Понятно что в сам рантайм коммитят не многие. Но всё что вокруг — это уже тысячи людей. Другой вопрос — как много людей пишут плагины и прочий код сопутствующий к Tarantool?
Понятно что сюда входят все кто пишет на LUA и для LUA, но… тогда надо сравнивать экосистему и сообщество LUA и Golang разработчиков как таковых.
Так же не маловажно — хочется ли конкретным разработчикам разбираться и использовать LUA только ради базы данных или же у них вся инфраструктура на LUA. Не видел ни одной компании у которых всё пишется на LUA. В тоже время есть не мало компаний в которых пишут исключительно на Golang.
Понятно что сюда входят все кто пишет на LUA и для LUA, но… тогда надо сравнивать экосистему и сообщество LUA и Golang разработчиков как таковых.
Так же не маловажно — хочется ли конкретным разработчикам разбираться и использовать LUA только ради базы данных или же у них вся инфраструктура на LUA. Не видел ни одной компании у которых всё пишется на LUA. В тоже время есть не мало компаний в которых пишут исключительно на Golang.
+2
3. master-master: http://tarantool.org/doc/book/replication/index.html, п. 4.8. Насчет master-slave — данные меняются только на master, поэтому такой проблемы нет. Однако на master-master такая проблема может быть, и если ваш application не может хэндлить этот кейс, то лучше использовать master-slave. При этом не надо вмешательство админов и ничего не останавливается. Могу рассказать детально как это работает, например, позвонив по скайпу. Мой скайп danikin2. Стучитесь, не стесняйтесь :)
4. Кстати, да. Соглашусь :)
5. Если у вас go смотрит в интернет и сам все это делает, включая терминацию SSL, статику и все остальное, то это очень круто! Было бы интересно почитать статью про это, а также про сравнение с nginx!
6. «nginx upstream + proxy_next_upstream» — ну, не совсем. Если, к примеру, у вас локально все затормозило, и в этот конкретный сервер ходить нельзя, то nginx это не запомнит, насколько я знаю, и будет пытаться ходить туда каждый раз. Но, в целом, если такое решение устраивает, то да, почему бы нет. Вообще, я неоднократно это говорил — я за мир во всем мире и за те решения, которые решают проблемы. Если у вас с вашим решением проблем нет, то все круто и менять его не на что не надо! :)
4. Кстати, да. Соглашусь :)
5. Если у вас go смотрит в интернет и сам все это делает, включая терминацию SSL, статику и все остальное, то это очень круто! Было бы интересно почитать статью про это, а также про сравнение с nginx!
6. «nginx upstream + proxy_next_upstream» — ну, не совсем. Если, к примеру, у вас локально все затормозило, и в этот конкретный сервер ходить нельзя, то nginx это не запомнит, насколько я знаю, и будет пытаться ходить туда каждый раз. Но, в целом, если такое решение устраивает, то да, почему бы нет. Вообще, я неоднократно это говорил — я за мир во всем мире и за те решения, которые решают проблемы. Если у вас с вашим решением проблем нет, то все круто и менять его не на что не надо! :)
+1
Раз уж речь зашла не только о быстродействии, но и о эксплуатационных качествах, то есть вопрос. Как правильно бекапить приложение, базирующееся на leveldb?
0
Я тут без понятия — я просто знал что для Go есть несколько KV хранилищ, взял первые два попавшиеся ради интереса :) Никогда не эксплуатировал ее. Насколько я понимаю, авторы (Facebook) рекомендуют все же идти дальше и пользовать RocksDB (который у меня просто не скомпилировался в виде embedded, только в виде shared библиотеки, что не очень мне понравилось, поэтому открыл им issue и оставил за рамками статьи)
Думаю гугление на тему backup leveldb должно раскрыть тайну :)
Думаю гугление на тему backup leveldb должно раскрыть тайну :)
0
Для бинарного протокола можно же взять http/2 до go.
0
Сам тестил leveldb, sophia, rocksdb на Go.
C leveldb всё было отлично, но как только повышал количество документов с нестандартно большой длиной, он начинал тупить, это было предсказуемо и понятно.
sophia реально удивила, очень быстро, и при возрастании нагрузки деградирует очень медленно, но при длительных тестах заметил, что (WAL был отключён) терят некоторые записи. Свежих биндингов я не нашёл, сварганил их быстро сам, поэтому есть подозрение, что виной всему кривые руки.
rocksdb начали тестировать когда было окончательно принято решение, что сервак будет ssd-шным. Перетестировав предыдущие решения и сравнив их с rocksdb — последний остался победителем.
Но sophia, оставила очень тёплые впечатления и я обязательно попробую расковырять причины моих неудачных.
C leveldb всё было отлично, но как только повышал количество документов с нестандартно большой длиной, он начинал тупить, это было предсказуемо и понятно.
sophia реально удивила, очень быстро, и при возрастании нагрузки деградирует очень медленно, но при длительных тестах заметил, что (WAL был отключён) терят некоторые записи. Свежих биндингов я не нашёл, сварганил их быстро сам, поэтому есть подозрение, что виной всему кривые руки.
rocksdb начали тестировать когда было окончательно принято решение, что сервак будет ssd-шным. Перетестировав предыдущие решения и сравнив их с rocksdb — последний остался победителем.
Но sophia, оставила очень тёплые впечатления и я обязательно попробую расковырять причины моих неудачных.
+2
А можете чуть детальней расписать про софию? Например, мне в скайп danikin2. Нам было бы очень интересно поисследовать ваши кейсы, особенно с потерей записей? С выключенным WAL, кстати, записи и должны теряться, софия же в памяти все не хранит, лучше WAL включить, он особой нагрузки не делает, а если делает, то нам было бы интересно взглянуть на это :)
+2
я не очень понял сравнение. Тарантул — это кортежная БД с кучей фич. leveldb — это примитивный keyvalue с заявленным хранением хуже чем в тарантуле.
Чего сравнивали то?
Чего сравнивали то?
0
С таким подходом вообще ничего в мире сравнивать нельзя. Как пример: MySQL это база со многими engine, а Redis это key-value кэш с другими характеристиками. Но неужели это автоматически обозначает что я не могу одну и ту же задачу решить на MySQL и на Redis? В одном случае мне одни плюшки предоставит система, а другие придется делать руками, в другом — другие предоставит другая система, а в первой их придется делать руками.
Тот же случай и тут. Я взял общий делитель — операцию которую можно сделать в обоих случаях. И сравнил ее по скорости. В чем проблема?
Тот же случай и тут. Я взял общий делитель — операцию которую можно сделать в обоих случаях. И сравнил ее по скорости. В чем проблема?
+6
Решение поставленной задачи сравнивали. Её еще на mysql можно решить, а еще на perl скрипт написать и в файлах хранить, а ещё на node.js + mongodb. Задача оттого не изменится.
+1
ИМХО Сравнение очень даже интересно, с учетом что тут не только DB тестировалось, но и способы доставки.
0
Я вот думаю, а почему не совместить приятное с полезным? HTTP-сервер писать на Go, а при этом в качестве СУБД оставить Tarantool. Скорее всего это будет быстрее чем Go + LevelDB. И при этом все свойства СУБД автоматом останутся.
+5
На один комментарий ниже отписался. https://habrahabr.ru/post/282299/#comment_8867187
0
Добавил сравнение в конец статьи, оказалось, к сожалению, не быстрее. Думаю что это сильно связано с тем, что постоянно приходится типы из interface{} в строки переводить — но тут так реализован клиент — процессоры горят на полную.
+1
А что если попробовать провести тесты не с leveldb, а с tarantool? Т.е. Go+go-tarantool и замерить.
https://github.com/tarantool/go-tarantool
https://github.com/tarantool/go-tarantool
0
tarantool http не оптимизирован под большие нагрузки, для этого есть nginx upstream http://github.com/tarantool/nginx_upstream_module
Надо собрать nginx с этим модулем, взять master пока, тег не добавил.
Немного под хачил lua, чтобы через nginx можно было ходить
https://gist.github.com/dedok/bd6b32914dbbedf3d9a78bd50ad83f48
nginx.conf — он с новыми фичами
https://gist.github.com/dedok/d84b82b2863b778f47ca05c17cbf3b25
Ну и разбалансировать либо на 1-н, как ты сделал, но выставить go runtime.GOMAXPROCS(1)
Либо балансировать на некое кол-во cpu.
С nginx CPU подлетит, но, как правило, у всех стоит nginx перед backend'ом.
Так что его в потребителях можно учесть :)
Думаю, так будет немного по научному.
Кстати спасибо автору, благодаря статье, первый раз по трогал go, очень понравилось.
Надо собрать nginx с этим модулем, взять master пока, тег не добавил.
Немного под хачил lua, чтобы через nginx можно было ходить
https://gist.github.com/dedok/bd6b32914dbbedf3d9a78bd50ad83f48
nginx.conf — он с новыми фичами
https://gist.github.com/dedok/d84b82b2863b778f47ca05c17cbf3b25
Ну и разбалансировать либо на 1-н, как ты сделал, но выставить go runtime.GOMAXPROCS(1)
Либо балансировать на некое кол-во cpu.
С nginx CPU подлетит, но, как правило, у всех стоит nginx перед backend'ом.
Так что его в потребителях можно учесть :)
Думаю, так будет немного по научному.
Кстати спасибо автору, благодаря статье, первый раз по трогал go, очень понравилось.
0
Ну ок, у всех сейчас многоядерные сервера и машины и как бы в один поток ограничивать go — смысла большого нет, ибо на бою хочется именно использовать по-максимуму ресурсы системы, и вот тут вопрос.
А как использовать все ядра-то на Tarantool? Т.е. я так понял что для этого надо запускать несколько tarantool и включать на них master-master репликацию и потенциально связываться с конфликтами записи? Master-slave я так понимаю не решит тут, если речь идет о равном количестве записей и чтений (т.е. условно write-bound нагрузка)
А как использовать все ядра-то на Tarantool? Т.е. я так понял что для этого надо запускать несколько tarantool и включать на них master-master репликацию и потенциально связываться с конфликтами записи? Master-slave я так понимаю не решит тут, если речь идет о равном количестве записей и чтений (т.е. условно write-bound нагрузка)
0
Согласен — насчет ядер.
Да надо несколько tarantool запускать, из либо sharding(https://github.com/tarantool/shard) в tarantoolы ходить, или делать хитрый балансинг на уровне nginx upstreams (писать на lua/ngscript).
Репликация скорей всего не подойдет, мы же не про put(const, const) говорим?:)
Да надо несколько tarantool запускать, из либо sharding(https://github.com/tarantool/shard) в tarantoolы ходить, или делать хитрый балансинг на уровне nginx upstreams (писать на lua/ngscript).
Репликация скорей всего не подойдет, мы же не про put(const, const) говорим?:)
+1
И я с этим согласен.
Тарантул не потребляет все ядра эффективно, на серверах у нас их 12*2HT.
В этом случае частый ответ разработчиков: запустить несколько инстанцев.
Такое разделение
— резко снижает объем памяти одного инстанца, т.к. они его между собой не шарят,
— требуется писать код шардинга, и, иногда, стыковать данные из разных шардов.
Проблему неиспользованных ядер в целом можно решить, если на тот же сервер сажать еще какие-то демоны, тот же Nginx, например.
Тарантул не потребляет все ядра эффективно, на серверах у нас их 12*2HT.
В этом случае частый ответ разработчиков: запустить несколько инстанцев.
Такое разделение
— резко снижает объем памяти одного инстанца, т.к. они его между собой не шарят,
— требуется писать код шардинга, и, иногда, стыковать данные из разных шардов.
Проблему неиспользованных ядер в целом можно решить, если на тот же сервер сажать еще какие-то демоны, тот же Nginx, например.
+1
Да, там еще нюанс упущен
https://gist.github.com/dedok/d84b82b2863b778f47ca05c17cbf3b25
Я финальным шагом `bar` в json конвертирую, т.е. в `«bar»` — конвертация в JSON и обратно зачастую тоже довольно медленная вещь. Поэтому и в Go, и в Tarantool проверял это последним шагом.
https://gist.github.com/dedok/d84b82b2863b778f47ca05c17cbf3b25
Я финальным шагом `bar` в json конвертирую, т.е. в `«bar»` — конвертация в JSON и обратно зачастую тоже довольно медленная вещь. Поэтому и в Go, и в Tarantool проверял это последним шагом.
0
Если необходим действительно быстрый http на Go:
https://github.com/valyala/fasthttp
Кстати, у Go есть достойная Lua VM:
https://github.com/yuin/gopher-lua
Сам сейчас в раздумьях, какую k-v использовать в своих проектах для решения различных задач. На работе мы используем свои биндинги к LMDB, для меня это не подходит, т.к. мне нужна кросс-компиляция в некоторых случаях. Посмотрел на tarantool — ручной шардинг мне не понравился, хочется чтобы «оно само».
Из интересных проектов, есть еще tikv:
https://github.com/pingcap/tikv
Распределенная key-value c транзакциями на Rust, которая будет использоваться в качестве бекенда для другого проекта (tidb) на го.
https://github.com/valyala/fasthttp
Кстати, у Go есть достойная Lua VM:
https://github.com/yuin/gopher-lua
Сам сейчас в раздумьях, какую k-v использовать в своих проектах для решения различных задач. На работе мы используем свои биндинги к LMDB, для меня это не подходит, т.к. мне нужна кросс-компиляция в некоторых случаях. Посмотрел на tarantool — ручной шардинг мне не понравился, хочется чтобы «оно само».
Из интересных проектов, есть еще tikv:
https://github.com/pingcap/tikv
Распределенная key-value c транзакциями на Rust, которая будет использоваться в качестве бекенда для другого проекта (tidb) на го.
+1
Как я понял, тест был многопоточный и запросы шли один за другим.
1. При таком подходе сетевой стек линукса довольно быстро ограничит RPS еще до того как все CPU будут использованы (речь про средние сервера, а не десктоп).
2. Тарантул хорошо себя показывает в batch запросах, где пачками грузятся запросы, и так же пачками получаются ответы. Но при этом сами запросы должны быть простые: не более одного меняющего данные операции (в CALL) для 1.5 или же нужно использовать транзакции в 1.6.
3. Плохое использование ядер окупается ускорением за счет отсутствия локов. На практике это надо мерить, но любители корутин/файберов будут бить в грудь даже без тестов (что обычно бывает оправданным).
Протестируйте на таких кейсах как batch запросы, используя его бинарный протокол. На таких кейсах он наверняка обгонит что-то самописное.
Надо понимать, что дает конкретное СУБД и чем за это придется платить. Для каждой базы есть как свои плюсы, так и свои минусы.
1. При таком подходе сетевой стек линукса довольно быстро ограничит RPS еще до того как все CPU будут использованы (речь про средние сервера, а не десктоп).
2. Тарантул хорошо себя показывает в batch запросах, где пачками грузятся запросы, и так же пачками получаются ответы. Но при этом сами запросы должны быть простые: не более одного меняющего данные операции (в CALL) для 1.5 или же нужно использовать транзакции в 1.6.
3. Плохое использование ядер окупается ускорением за счет отсутствия локов. На практике это надо мерить, но любители корутин/файберов будут бить в грудь даже без тестов (что обычно бывает оправданным).
Протестируйте на таких кейсах как batch запросы, используя его бинарный протокол. На таких кейсах он наверняка обгонит что-то самописное.
Надо понимать, что дает конкретное СУБД и чем за это придется платить. Для каждой базы есть как свои плюсы, так и свои минусы.
+1
Тест через wrk = многопоточный + мультиплексирование (4 потока, 10 соединений и 10 потоков, 100 соединений)
К сожалению, уже не осталось времени тестировать что-то подобное. Вполне возможно, хотя последний добавленный тест go+go-tarantool, в общем-то, надежды большой не дал.
К сожалению, уже не осталось времени тестировать что-то подобное. Вполне возможно, хотя последний добавленный тест go+go-tarantool, в общем-то, надежды большой не дал.
0
Жаль. т.к. в текущем виде этот тест больше смахивает на тест http серверов go и tarantool
0
Хотелось бы увидеть тест где вы реализуете ВЕСЬ функционал tarantool. А то так можно и с фотошопом сравнивать Go, реализовав только какой либо один фильтр картинки =)
0
Ну, я думал это само собой разумеется, что тест для отдельного случая и я вовсе не говорю что Tarantool надо забросить и он никуда не годится.
Просто в обратную сторону тоже можно также бросить — реализуйте в Tarantool ВЕСЬ функционал всех библиотек Go, а потом сравнивайте…
Сравнение вполне конкретное, более того — Tarantool выглядит достойно. Я описал минусы по которым он мне в моем случае не подходит, но это ж не значит что это случай всех и вся.
Просто в обратную сторону тоже можно также бросить — реализуйте в Tarantool ВЕСЬ функционал всех библиотек Go, а потом сравнивайте…
Сравнение вполне конкретное, более того — Tarantool выглядит достойно. Я описал минусы по которым он мне в моем случае не подходит, но это ж не значит что это случай всех и вся.
0
Так вы же начали сравнивать, потому сравнивайте не тёплое с мягким, а реализацию ПОЛНОГО функционала Tarantool на C/C++ с реализацией этого же функционала на Go. А то какая-то манипулирование неокрепшими умами получается…
0
Я уже отвечал на этот аргумент тут
Если мне нужен Фотошоп для одного фильтра — я имею право сравнивать Фотошоп и программу, имеющую только этот один фильтр.
Реализация k-v хранилища тут примерно одинаковая. Да, в Tarantool есть другие возможности — я это написал в статье и в комментариях несколько раз. Да, сравнивается конкретный случай — я это тоже написал и в статье, и в комментариях.
Если мне нужен Фотошоп для одного фильтра — я имею право сравнивать Фотошоп и программу, имеющую только этот один фильтр.
Реализация k-v хранилища тут примерно одинаковая. Да, в Tarantool есть другие возможности — я это написал в статье и в комментариях несколько раз. Да, сравнивается конкретный случай — я это тоже написал и в статье, и в комментариях.
+1
Судя по коду ваша задача заключается в том, чтобы класть bar в foo, десятки тысяч раз общаясь через HTTP протокол, да тут вряд ли какие-либо коробочные решения помогут =).
Мало того даже в сравниваемом коде разный функционал, в tarantool, например используется лог файл, что по определению создаёт неслабую нагрузку на дисковую подсистему.
Да и понятно бы было если бы хотя бы свою реализацию KV хранилища показали бы, а то получается что тестируем кастрированный веб-сервер на Go + KV хранилище на C vs целую базу данных и сервер аппликаций.
Мало того даже в сравниваемом коде разный функционал, в tarantool, например используется лог файл, что по определению создаёт неслабую нагрузку на дисковую подсистему.
Да и понятно бы было если бы хотя бы свою реализацию KV хранилища показали бы, а то получается что тестируем кастрированный веб-сервер на Go + KV хранилище на C vs целую базу данных и сервер аппликаций.
0
Забавный момент, пустил go(во все потоки) через nginx(1 worker) proxy_pass с keepalive получил:
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 23.76ms 21.26ms 165.45ms 94.74%
Req/Sec 477.19 106.88 594.00 87.35%
Latency Distribution
50% 19.23ms
75% 19.93ms
90% 21.46ms
99% 153.41ms
16361 requests in 5.10s, 2.59MB read
Requests/sec: 3206.89 (максимум ~5к было — скачет CPU — вырубать все лень, мак домашний!)
Transfer/sec: 519.87KB
Пусканул tarantool (tnt_pass)
Running 5s test @ http://127.0.0.1:8081/tnt
10 threads and 100 connections
Thread Stats Avg Stdev Max ± Stdev
Latency 7.48ms 2.44ms 18.02ms 74.22%
Req/Sec 1.33k 386.69 5.49k 86.45%
Latency Distribution
50% 7.71ms
75% 8.76ms
90% 9.80ms
99% 14.88ms
66431 requests in 5.10s, 13.12MB read
Requests/sec: 13017.25(максимум ~17к было, скачет CPU — вырубать все лень, мак домашний!)
Transfer/sec: 2.57MB
PS keepalive выкрутил, даже dtrace accept сделал
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 23.76ms 21.26ms 165.45ms 94.74%
Req/Sec 477.19 106.88 594.00 87.35%
Latency Distribution
50% 19.23ms
75% 19.93ms
90% 21.46ms
99% 153.41ms
16361 requests in 5.10s, 2.59MB read
Requests/sec: 3206.89 (максимум ~5к было — скачет CPU — вырубать все лень, мак домашний!)
Transfer/sec: 519.87KB
Пусканул tarantool (tnt_pass)
Running 5s test @ http://127.0.0.1:8081/tnt
10 threads and 100 connections
Thread Stats Avg Stdev Max ± Stdev
Latency 7.48ms 2.44ms 18.02ms 74.22%
Req/Sec 1.33k 386.69 5.49k 86.45%
Latency Distribution
50% 7.71ms
75% 8.76ms
90% 9.80ms
99% 14.88ms
66431 requests in 5.10s, 13.12MB read
Requests/sec: 13017.25(максимум ~17к было, скачет CPU — вырубать все лень, мак домашний!)
Transfer/sec: 2.57MB
PS keepalive выкрутил, даже dtrace accept сделал
+2
Копаюсь почему — самому объяснить интересно стало.
+1
Заинтриговали, пойду tnt_pass попробую :)
+1
надо на epoll попробовать это все с kqueue, завтра вчером с epoll, сегодня нет возможности, протестирую скину все результаты и trace будем считать accept и т.д.
А вообще гоу к нам в чат :)
А вообще гоу к нам в чат :)
+1
Вроде поставил все, но результат что-то немного другой:
➜ nginx git:(master) ✗ curl 127.0.0.1:8081/tnt
{"id":0,"result":[["bar"]]}
а должен быть
"bar"
хотя вроде
return { var[2] } -- только bar
А где чат?
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
0
А если на go backend через proxy_pass с keepalive?
+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
+1
А ты число workers уменьшил до 1-го?
+1
Брал все из gist. Воркеров чего nginx или golang? Если golang — то я в самом начале статьи сказал, что на одно ядро производительность сравнима (или, может, даже лучше :) ).
0
nginx.conf
worker_processes 1; # ходим в 1 процесс - увиличивем если балансируем в N tnt
0
tnt_pass ожидаемо дает больше, т.к. в этом случае:
1. http часть работ вынесена в nginx
2. запросы идут мультиплексом, т.е. batch
Это и показывает, что тесты из статьи в основном
— тестируют реализацию http, а она там в том же потоке луа работает.
— не загружают сам тарантул, утыкаясь в узкое горлышко на http уровне.
Вывод: для http лучше использовать nginx модуль с tnt_pass.
1. http часть работ вынесена в nginx
2. запросы идут мультиплексом, т.е. batch
Это и показывает, что тесты из статьи в основном
— тестируют реализацию http, а она там в том же потоке луа работает.
— не загружают сам тарантул, утыкаясь в узкое горлышко на http уровне.
Вывод: для http лучше использовать nginx модуль с tnt_pass.
+1
[удален, не туда ответил]
0
Да, если еще актуально)
У библиотеки goleveldb, которую вы подключаете есть mem storage, было бы тоже интересно посмотреть в сравнении с tarantool, которая позиционирует себя как in-memory db
У библиотеки goleveldb, которую вы подключаете есть mem storage, было бы тоже интересно посмотреть в сравнении с tarantool, которая позиционирует себя как in-memory db
0
Если нужно in-memory, то можно взять обычный Map.
0
1. Обычный map не thread safe
2. Различные KV-хранилища зачастую показывают производительность даже выше чем встроенный map.
2. Различные KV-хранилища зачастую показывают производительность даже выше чем встроенный map.
0
2. Различные KV-хранилища зачастую показывают производительность даже выше чем встроенный map.
Зачастую? Вот я сейчас сделал тест на питоне, выдает более 7Млн «записей» в сек на моем ноутбуке в один поток (на Го будет больше), приведите пример хранилища которое хотя бы отдаленно дотягивает до этих цифр.
0
Я имею в виду KV-хранилища, реализованные в виде Go-библиотек. С сетевым оверхедом, пусть даже на локалхосте, естественно никто не обгонит map.
Например, вот: https://github.com/coocood/freecache
Set-операция в два раза быстрее встроенного Map, но Get в два раза медленнее :) Но т.к. оно thread-safe, то в реальном использовании будет на порядок быстрее блокируемого целиком mutex-ом map-а.
Минус — память нужно выделять заранее, map же растет пока не кончится RAM.
Или вот еще — https://github.com/allegro/bigcache
Например, вот: https://github.com/coocood/freecache
Set-операция в два раза быстрее встроенного Map, но Get в два раза медленнее :) Но т.к. оно thread-safe, то в реальном использовании будет на порядок быстрее блокируемого целиком mutex-ом map-а.
Минус — память нужно выделять заранее, map же растет пока не кончится RAM.
Или вот еще — https://github.com/allegro/bigcache
0
Только вот характеристики тут тогда принципиально отличаются. Тарантул (насколько я понимаю) если сказал "сделано" — то оно сохранено на диске. А вот in-memory не сохраняют на диск ничего.
0
Sign up to leave a comment.
Сугубо ненаучно: Tarantool 1.6 vs Golang (по скорости)