Pull to refresh

Comments 91

Теперь нужна статья «Как сэкономить миллион баксов с помощью nginx», начало такое: «решили мы сделать CDN, и запустили ферму из 16 апачей..».
Техничку приводить как обычно не надо, достаточно писать в стиле этой же статьи, что для определенных задач redis tarantool шустрее чем mysql.
Ваш кэп!
Я рад, что статья получилась настолько понятной, что я выгляжу кэпом :) Насчет технических деталей — можете задать любые вопросы, и мы вам обязательно ответим! :)
А почему бы и не написать? Кстати в такую свзяку можно взять lua-resty-tarantool и получить ещё больше плюсов!
Ну идея хорошая. Просто вопрос что именно написать? Если конкретные case study, то уже много статей буквально недавно вышло про Тарантул. Вот, например:

habrahabr.ru/company/mailru/blog/254727
habrahabr.ru/company/mailru/blog/272141
habrahabr.ru/company/mailru/blog/272669
habrahabr.ru/company/mailru/blog/272769

Поэтому я тут решил написать что-то более общее и кэпское :) Хотя, надо и про профили и про другие кейсы сделать статьи. Работаем над этим :)
Когда будет что-то менее маргинальное чем lua?
А что вам нужно?
SQL — обещают.
Хранимые процедуры не lua?

Был интересный кейс на митапе, когда хранимая процедура дергала Asterisk, вот такие кейсы и дают понимание, чем отличается tarantool.
там же есть интерфейс на Си
use case: «как поднять tarantool в режиме memcached» («для чайников»)
с персистентностью и без — с плюсами и минусами.
Отличная идея! Надо будет написать статью про это. Спасибо! :)
И ещё хотелось бы внятного описания, для чего Тарантул подходит хорошо и для чего он не подходит.
А то по вопросам и ответам кажется, что его пытаются представить как то, что подходит вообще для всего и что работает он во всех областях лучше, чем всё остальное, что только есть. Это же не так, правда?
Хотелось бы понять область применения.
Тарантул подходит для авторитетного хранения и обработки горячих данных. Т.е. данных, к которым много запросов, как на чтение так и на запись, и данных, которые хранятся в тарантуле как в единственном их источнике (единственном в том плане, что Тарантул — не надстройка над другой базой в виде кэша, а он сам по себе полноценная база).

Тарантул, по сути, это база данных и кэш в одном лице.

По каким признакам понять, что Тарантул вам поможет?

1. У вас данные хранятся в базе. А вы хотите, чтобы эта база обладала свойствами кэша, как то большая пропускная способность по количеству запросов, маленькое время выполнения запроса, большее количество update в секунду.
2. У вас данные хранятся в базе. База порезана на много шардов. А вы хотите, чтобы все жило в одном шарде.
3. У вас данные хранятся в кэше (memcached, redis). А вы хотите, чтобы этот кэш обладал свойствами базы, как то — персистенс, репликация, вторичные индексы, таблицы, хранимые процедуры, курсоры, рэйндж сканы, фул сканы.
4. У вас данные хранятся в базе, а сверху от базы есть кэш. В этом случае у вас есть некоторые свойства кэша (быстрая скорость работы запросов, болшая пропускная способность на чтения) и некоторые свойства базы (репликация, персистенс), но при этом вы теряете другие свойства базы, например, транзакции, хранимые процедуры, вторичные индексы, рэйнд сканы и другие свойства кэша, например, большая пропускная способность на запись, маленькое количество серверов, expire данных (если нужно), отсутствие maintenance окна. А вы хотите, чтобы ваша система обладала всеми свойствами и базы и кэша.

Каждая из ситуаций выше — это признак того, что Тарантул вам поможет. Тарантул — это база данных для горячих данных.
Одно из часто используемых свойств популярных РСУБД — обеспечение целостности базы путём различных ограничений, прежде всего ограничений по внешним ключам. Как у Тарантула с этим?
Решаемо через хранимые процедуры на LUA (можно реализовать почти что любой сложный SQL-запрос — вопрос лишь в вашем терпении).
Область применения у tarantool весьма специфичная, не предполагающая вот таких вот сложных use cases.
Ни в коем случае не покупайтесь на сравнения с реляционными СУБД. В лучшем случае tarantool можно сравнить с HandlerSocket в MySQL, где в «терминах грубой силы» победит MySQL (за счет multicore), а по гибкости однозначно tarantool.
То есть он больше документная СУБД, со всеми вытекающими, типа обеспечения целостности полностью на совести разработчика?
Да. Целостность лучше поддерживать руками. Constraints у нас нет.
По нашему опыту и тестам Тарантул быстрее HandlerSocket, причем в разы быстрее. Тарантул даже быстрее Memcached. Вот тут полностью открытая информация по тестам, с исходниками и образами тестируемых машин: articles.rvncerr.org/how-to-chose-an-in-memory-nosql-solution-performance-measuring

Будем благодарны вам, если расскажете конкретный кейс, когда HandlerSocket побеждал Тарантул за счет грубой силы. Мы бы потрепарировали его и повыясняли, как так получилось, что Тарантул проиграл.
Ну вот например в синтетическом тесте (по циклу делаем 100к записей и 100к выборки) Redis vs Tarantool в скорости обработки insert/set и select/get, Redis Все таки выигрывал у меня. Относительно QPS пока ничего сказать не могу.

Тест проводился на Centos 7.2, Tarantool 1.6.7-558, Redis 3.0.5 + php 5.4.45 & clients redis(+redis-igbinary) & tarantool( последний из репозитория). Но тесты проводились на виртуальной машине Virtualbox с 2 ядрами и 3гб ОЗУ. Вставлялся многомерный массив.

Результаты были приблизительно такие:
Tarantool 100k insert с включенным wal_mode режим write — 10сек., с выключенным wal_mode — 7сек., primary index type=«HASH», STR
Redis: 7сек.
На чтение:
Tarantool: 7сек.
Redis: 5сек.

О, отличный тест, спасибо! Можно ли попросить у вас исходники теста и конфигурации Tarantool и Redis? Если да, то вот мой email: anikin@corp.mail.ru

Тест и базы работали на одной и той же машине? Результаты теста повторяются устойчиво, т.е. если раза 3-4 прогнать, то результаты примерно такие же?

Плюс, можете чуть чуть пояснить

Включенный wal, только запись
Tarantool: 10s
Redis: 7s

Выключенный wal, только запись
Tarantool: 7s
Redis: 7s

Только чтение
Tarantool: 7s
Redis: 5s

Все верно?

Т.е. у Redis включенность wal не влияет на скорость?
Да конечно, сейчас повторю тест но уже на живой машине и вышлю Вам на почту и пхп скрипт и настройки и более подробное время.
Плюс к Redis set ошибся со временем, не 7 а 5сек.
Плюс выкл./вкл. wal был выставлен у Tarantool, редис был с выключенным save.
>По нашему опыту и тестам Тарантул быстрее HandlerSocket, причем в разы быстрее
Вот здесь http://yoshinorimatsunobu.blogspot.ru/2010/10/using-mysql-as-nosql-story-for.html пишут о 750k select-ов по primary key в секунду. Честно говоря, я недоумеваю, каким образом однопоточный процесс может выиграть у многопоточного, когда в современных процессорах число логических ядер доходит до 24.
Tarantool в пике делает 300К селектов на 1 ядре. На один физический сервер — умножайте на 24. Но в реальности больше 2 миллионов не получалось. Насчет однопоточности — его можно шардить по ядрам. Насчет handlersocket — по нашему опыту нам не получалось больше 30-40К select/sec на одной машине выжать из handlersocket.

Если у вас для вашей задачи на вашем железе получится сделать 750K select в секунду на один сервер в MySQL и при этом в эту базу будут идти конкурирующие updates и вы будете сохранять те же 750K select в секунду, то это будет супер круто и вам, конечно, Tarantool не нужен. Скажу даже больше, вы сможете конкурировать легко с Percona или другими сапортерами MySQL и озолотитесь.

Я просто к чему говорю, что бенчмарк бенчмарку — рознь. Надо всегда проверять на конкретной нагрузке для конкретной задачи и сравнивать, сравнивать и сравнивать. Чем мы собственно всегда и занимаемся. Давно бы ушли с Тарантула на что-то, если бы это что-то было бы тоже базой данных с транзакциями и server-side-scripting и работало бы реально на наших кейсах быстрее. Но пока ничего такого не нашли :-)
>Tarantool в пике делает 300К селектов на 1 ядре
Это при каких условиях?
На официальном сайте тарантула есть бенчмарк http://tarantool.org/benchmark.html, показывающий в районе 100k select-ов в секунду, а вы говорите о 300k.

>На один физический сервер — умножайте на 24
А память на 24 умножать не затратно будет?

>Шардить по ядрам
А потому ходить в шарды черед прокси (кстати, многопоточную или single-threaded?) и в итоге придем к тому, что «лучше бы вовсе не шардили».
Кстати, availability (не говоря уже о запросах «посчитать что-то среди имеющихся данных) страдает от шабрдинга, т. к. возрастает вероятность недоступности одного из шардов. Плюс увеличивается время старта при использовании AVLTREE-индексов.
1. 300K в прыжке. Это суперсинтетика.

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

3. Не обязательно прокси. Можно поделить базу по сервисам так, чтобы одни сервисы ходили в один кусок, а другие в другой. Даже 100К на одном ядре достаточно для большинства сервисов, поэтому можно на одну машине помещать, грубо говоря, по отдельной сущности на ядро.

4. Шардинг привносит проблемы, это факт. Поэтому первое правило шардинга — do not shard. И именно поэтому один из главных принципов Тарантула — это добиться максимальной производительности на 1-2 ядрах (на 2, потому что он умеет разносить transaction processor и networking на разные ядра), чтобы в шардинге вообще не было необходимости кроме супервысоконагруженных сервисов. Но и про шардинг мы не забываем и в версии 1.7 планируем его зарелизить. Чтобы все шардилось не только по ядрам, но и по машинам.

5. 750КRPS на одну машину — это потрясающий результат. Тот, кто его достиг на HandlerSocket, должен использовать HandlerSocket и ничего больше. Единственное что, я бы глянул на следующее:
— как оно работает с параллельными апдейтами
— как оно работает с транзакциями (когда не просто set/get value, а какая-нибудь хранимка вызывается, и когда эта хранимка должна отработать по принципу ACID)
— очевидно, что при таких скоростях весь dataset в памяти, а значит надо посмотреть на memory footprint. MySQL не самым оптимальным образом хранит данные в памяти, у него большие оверхеды per field и per row.

И если все это устраивает, то можно и нужно юзать HandlerSocket! А если нет, то надо обратиться в сторону Redis/Tarantool и других решений.

Надо использовать правильный инструмент для работы, который наиболее эффективен для данного workload.
Проблема №1 решается т.н. двухфазным коммитом: мы либо пишем и в базу и в кеш, либо никуда не пишем, а читаем потом только из кэша. Моргание сети и прочее тут не является принципиальной проблемой, т.к. это всё устранимо (в конце концов, когда-то и электричество может «моргнуть», и без репликации по разным стойкам/дц тут ничего не поделаешь).

Далее, имея двухфазный коммит для пары кэш+бд, используем персистентный кэш с включённым LRU — например тот же Redis. На выходе получаем и гарантированную запись, и быстрые чтения, и быстрый холодный старт, и как бонус — автоматическое, а не ручное разделение горячих и холодных данных, используя при этом стандартные проверенные решения — что является большим плюсом, перевешивающим заморочки с малоизвестным, пусть и навороченным софтом (я это говорю со стороны, как внешний наблюдатель — всё-таки популярность и удобство Redis'а — это тоже немаловажный фактор на фоне десятка-другого процентов скорости).

В итоге имеем решение аналогичное предложенному, плюс сокращаем работу по ручному отделению горячих данных от холодных, плюс ещё экономим память на горячих данных (у вас ведь всё лежит в памяти, несмотря на то что горячих данных там от силы половина, а то и меньше). И экономим тот же самый миллион долларов.

Если я не прав — ЧЯДНТ?
1. Двухфазный комит надо разрабатывать. И это на деле сложнее чем в теории. Вот можете прям в деталях пояснить как бы вы его написали? Было бы круто привести примеры кода для MySQL + Redis или еще какой-нибудь популярной связки.

Кроме того какой бы крутой не был у вас двухфазный коммит все равно в самом конце вы должны завершить этот коммит в двух местах синхронно (или оба да или оба нет), что не совсем понятно как сделать, т.е. вероятность, что данные разъедутся остается. И они точно разъедутся в самый неподходящий момент и вы не будете про это знать :)

2. Запись в базу будет идти медленно. Из-за синхронного коммита вы сможете не справиться в нагрузкой, т.к. запись будет работать не быстрее чем со скоростью MySQL.

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

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

Кстати, у нас для таких профилей нагрузки есть репликация из Tarantool в MySQL. Причем сам Tarantool можно автоматом подчищать по принципу LRU, если памяти не хватает. Это решает проблему двухфазного коммита (репликация всегда рано или поздно произойдет, потому что работает через очередь). И это дает функционально ровно то решение, о котором написали вы. Просто, насколько я знаю, между MySQL и Redis'ом стандартной репликации нет.
> Вот можете прям в деталях пояснить как бы вы его написали?
Сходу нет, но с mysql и redis это не выглядит как совсем уж космическая задача. А вот поинт насчет скорости записи выглядит существенный. В обычную базу, действительно, очень быстро писать не выйдет.
Ну вот стандартных механизмов по связи MySQL и Redis через двухфазный коммит нет. Уже проблема. А Тарантул реплицироваться с MySQL умеет. Т.е., даже если вы не доверяете Tarantool как авторитетному хранилищу данных (что вполне логично для новой для вас базы, даже если она 7 лет уже существует), то как раз репликация в MySQL спасает.

У нас, на самом деле, полно кейсов, когда вроде как с виду решение есть без Tarantool (мы тоже всегда его челленджим, ищем, что еще есть нового-хорошего), но начинаешь копать глубоко и понимаешь, что там нужен костыль, здесь доработка, тут будет поттормаживать, там будут данные теряться и возвращаемся к старому доброму Tarantool :)
А можно ли потом будет вытащить данные из MySQL в Tarantool? Ну вот например Tarantool данные хранятся только в памяти, перезагружаем сервер/тарантул и что бы данные считались с MySQL?

Так же чуть отклоняясь от данного поста вопрос: Можно ли хранить данные Тарантула параллельно и в памяти и на диске по принципу например Cassandra? Вопрос в том что есть база например 200гб и как то дорого выходит хранить всю это базу в памяти.
Если настроена репликация между ними, то да, можно. Но в описанном вами кейсе в этом нет необходимости, потому что после перегрузки сервера/тарантула, тарантул поднимает все данные из snapshot + xlog и тут же находится в том же состоянии, что был до перезагрузки.

У Тарантула есть disk store. Он в версии 1.6 пока не считается стабильным. Но будет стабильным в 1.7.

Насчет базы в 200Г. У Тарантула очень оптимальный memory footprint. Если это 200Г в MySQL, то в Тарантуле они уже будут весить 100Г или меньше. MySQL при таком размере базы для нормальной работы требует 32Г. Кроме того, MySQL требует SSD диск, а Тарантул может работать и с SATA диском, который в разы дешевле. Плюс, Тарантуле в отличие от MySQL не обязательно иметь крутейший процессор на 16-32 ядер, ему достаточно для нормальной работы 1-2 ядра (и на 1-2 ядрах он будет быстрее чем MySQL на 16-32 ядрах). Т.е. в сумме получается, что затраты на сервер существенно дешевле. Плюс, если ваша нагрузка, к примеру 100KQPS и больше, то в случае MySQL вам придется ставить уже ферму из 10 серверов, т.е. эти 32Г превратятся в 320Г и все остальные ресурсы тоже удесетярятся. Тарантул же легко держит ту же нагрузку на одном сервере с все теми же 100Г памяти.
>тарантул поднимает все данные из snapshot + xlog
Т.е. тарантул умеет делать автоматические снапшоты во время работа?
Понятное дело что 100К QPS MySQL не вытянет (если брать 1 сервер), тут скорее был вопрос подтянет ли данные тарантул с мускула.
Спасибо за ответ.
> Т.е. тарантул умеет делать автоматические снапшоты во время работа?

Конечно. И этот снэпшот содержит целостную копию базы на определенный момент времени. При этом снэпшоттинг никак не блокирует ни чтение, ни запись и почти не потребляет дополнительной памяти (хранить приходится лишь новую версию тех апдейтов, которые пришли во время создания снэпшота).

Тарантулу нет нуждны синкаться из MySQL при старте. Он просто все поднимает из снэпшота.
А мускуль его догонит или есть иск не получит в мускуле часть данных, которые есть в тарантуле?
Если вы настроили репликацию из Тарнатула в MySQL, то MySQL все догонит рано или поздно. Ибо это делается через очередь, и, соответственно, потери невозможны.
> потери невозможны

хм, как это? Если в Тарантул льется 50Krps, а MySQL успевает всасывать 10K — через сколько дней захлебнется queue?
Все конечно зависит от типа проекта и настроек мускула, но как показывает практика 50Krps бывает не всегда, нагрузка в какой то период времени меньше, в какой то больше и когда нагрузка на тарантул падает тогда мускул все и догонет.
Это зависит от размера вашего диска. Репликацию из Tarantool в MySQL имеет смысл делать тогда, когда MySQL в среднем тянет нагрузку на запись, которая идет на Tarantool. Если он ее не тянет, но вам все равно эти данные надо иметь в MySQL, то я бы рекомендовал пошардить вашу MySQL базу на такое количество машин, которые бы понятнут нагрузку на запись. Но здесь надо вернуться к исходной задаче и понять, насколько реально необходима репликация в MySQL для вашей конкретной задачи. Если бы вы рассказали детали про вашу систему или проблемы, которые вы испытываете, то мне было бы проще выдать конкретный рецепт :-)
Тогда более конкретный вопрос: имеем сервер с 32гб ОЗУ, имеет базу Cassandra 160гб+, по вашему мнению можно ли будет перейти в конечном счете на Tarantool на этом же одном сервере? Ваш продукт меня заинтересовал, но вот то что он Memory only в моем случае это и плюс и минус. Так же еще пару вопросов:
1) Есть ли нормальная документация по PHP connector? Со списком методов, описанием и примерами.
2) На сколько я понял, TTL (expire) все таки можно ставить tuple (ключу?)?
3) И на сколько я понял сейчас есть режим master-master? Записываем не зависимо в какую ноду.

Спасибо.
У вас сейчас ровно один сервер? Какой примерно QPS (queries per second)? Какого рода данные там лежат? Можем, если хотите продолжить общаться в личке: anikin@corp.mail.ru :)

По вопросам 1 и 2 привлек разработчиков. Они сейчас ответят.

По вопросу 3 — да, именно так. И eventual consistency.
1) github.com/tarantool/tarantool-php-stubs/blob/master/src/Tarantool.php
2) Есть пакет github.com/tarantool/expirationd, который позволяет использовать какое-то из полей тапла под TTL
3) В 1.6 есть асинхиронный мастер-мастер, можно писать в любую ноду, но конфликты надо разруливать на клиенте (либо разбивать диапазоны). В 1.7 делаем дополнительный полный синхрон.
Заметил кстати что в пхп коннекторе нету метода upsert который уже есть в самой БД, можете пожалуйста подсказать на когда планируется ввести данный метод?
С двухфазным коммитом производительность связки на запись становится равна производительности базы. От недостатка которой нам собственно и понадобился кэш.
Вот именно. Но репликация из кэша в базу будет чуть лучше чем двухфазный коммит, т.к. она частично поможет тем, что сгладит пики запросов на запись.
Планируется ли коннектор для .Net?
В планах есть коннекторы ко всем языкам и системам
кто-то в рассылке даже собирался делать, но пока готового нет.
Можем помочь с протоколом, у нас все очень тупо (нужна лишь либа для MsgPack).
Ну, тупо, это вряд-ли, я все-таки был на хайлоаде ) Всё у вас хорошо. Мсгпак для шарпа конечно же есть. А протокол посмотреть всегда интересно.
Простите за вопрос. Скажите, где можно почитать про Tarantool, так чтобы «совсем для начинающих»?
я думаю, что на tarantool.org вполне понятная документация
А если воспользоваться подходом CQRS и писать все события в Kafka, а потом отражать изменения на кеше? Данный вариант тоже имеет право на жизнь?
Ну если Kafka использовать как лог изменений для кэша, из которого поднимать все данные при рестарте кэша, то вполне.
Была написана уже 28-ая пиар статья про таранатоол, но его так никто и не хотел внедрять. Даже даром.
Сравнивалось ли с Mysql Handlersocket/memcached plugin?
Насколько мне известно таких сравнений нет.
сравнивался Тарантул с дисковым движком, mysql, postgresql и еще что-то. Как откопаем картинку, запостим.
Сравнивались со всеми. В частности в указанном случае в статье с профилями мы пробовали MySQL именно с HandlerSocket. И Тарантул оказался минимум на порядок производительнее.

Вот тут статья, где мы сравнили с in-memory конкурентами, включая memcached. Тарантул рвет почти всех, кроме нескольких случаев: articles.rvncerr.org/how-to-chose-an-in-memory-nosql-solution-performance-measuring
Мы по нашим внутренним тестам быстрее. Aerospike даже медленнее Redis 3. Опубликуем эти тесты скоро. Плюс, в Аэроспайке нет server-side-scripting и ACID Transactions.
Спасибо, хорошая статья. Очень интересное решение и архитектура системы.
Делаете ли вы fsync журнала при каждом коммите?
В Tarantool можно включить и такой параноидальный режим работы.
Хотя и fsync тоже толком ничего не гарантирует.

1) При наличии BBWC — гарантирует, насколько я понимаю. Вы кстати используете такое железо?
2) Парой постов выше Вы сказали, что сравнивали тарантул с постгресом. Я надеюсь, это сравнение было тоже с fsync=off?

Вообще мой вопрос вызван тем, что описанный алгоритм персистентности ничем в целом не отличается от того, что делает тот же постгрес, но при этом обещается на два порядка лучшая производительности на запись.
Тарантул пишет на диск линейно. Postgres как и MySQL/InnoDB, как и любой другой движок базы данных, основанный на B-Tree на каждую запись делает много disk seek, то замедляет все на порядок и больше.

Кроме того, Тарантул сильно свежее Postgres (в плане движка хранения) или InnoDB, поэтому там многие вещи устроены оптимальней. Ну и потом, производительность было наше главное требование, когда мы писали Тарантул. Поэтому там все очень оптимально внутри. Мы можем проводить часовые митинги на тему как убрать лишний байт или даже бит на хранение поля или как избавиться от лишнего memcpy.

Тарантул быстрее и с fsync=off и тем более с fsync=on (потому что в последнем случае у вас в B-Tree based engines будут честные многократные перемещения дисковой головки при каждой записи).
Я бы хотел лучше понять утверждение про «на каждую запись делает много disk seek, то замедляет все на порядок и больше.»

Для простоты предположим что у нас есть апдейт поля, которое не входит в индекс.
И тарантул, и постгрес пишут последовательный журнал. По дефолту постгрес честно фсинкает этот файл, а тарантул нет, но допустим мы настроили одинаково.

Теперь тарантул запишет изменение у себя в памяти, а постгрес сделает fd.write (так что в вашем случае мы экономим на системном вызове). Этот write попадает в кэш ОСи, и теперь операционка и контроллер диска вольны откладывать запись на диск на сколько угодно (точнее до следующего чекпоинта), реордерить, объединять их в батч по признаку близости, etc. В любом случае изменения считаются персистентными и клиенту вернули «успех».

Где тут сики на каждую запись?
Во-первых, перед апдейтом надо считать с диска, чтобы понять, что апдейтим. К примеру, если это UPDATE t SET k='a' WHERE k='b', то надо сначала найти, где на диске лежит ключ k. И это уже как минимум один сик, а на деле 2-3. Тарантул же имеет все уже в памяти и такой проблемы там нет.

Далаее делается уже запись на диск. Допустим эта запись на диск не попала сразу на диск, а осела в кэше. Сиков нет. Есть лишь задания в памяи ядра записать в такое-то место на диске такие-то данные. Далее, на момент чекпойнта у вас обновились 100 случайных записей, то надо сделать как ни крути 100 движений головкой диска. Ибо на больших базах данных, которые целиком не влезают в кэш и расстояния между случайными записями большие. Да, может повезет, и скажем половина из этих данных будут рядом друг с другом. Ну тогда будет 50 сиков. Большой роли это не играет.
Ну, про поиск это нечестное сравнение. Мы же обсуждаем горячие данные, значит надо считать что вся база вместе с индексами влезает в память. Конечно, постгрес потребует в этом сценарии в несколько раз больше памяти на сервер и какой-нибудь скрипт прогрева, но какая разница.

Если поставить checkpoint_timeout равный частоте дампа в тарантуле и checkpoint_completion_target=0.99, то не будет ли поведение одинаковым? В смысле нам в обоих случаях надо в течении долгого времени переписать на диск (почти) весь массив данных.
Вы имеете в виду ситуацию, когда все влезает в память? Тогда другое дело. Сиков на записи не будет.

checkpoint_timeout ставить огромным можно. Но тогда в памяти будут храниться еще и все изменения.

А учитывая то, что memory footprint у Тарантула сильно оптимальней, чем у Postgres, то суммарно это будет в 3-5 раз больше весить в памяти чем Тарантул.

Кроме того при коммите всего этого огромного набора данных на диск Postgres будет тормозить (фактически downtime). И это не потому что Postgres плохой, это потому что он не предназначен для такого кейса.

Плюс, см. выше, Тарантул сам по себе сильно оптимальней Postgres и MySQL даже если в последних все влезает в память.

Резюме такое:

Если поставить в 5 раз больше памяти, то, да, это будет работать и с Postgres'ом. Но будет работать все равно раз в 10 медленнее. Ну т.е. не в 100, а в 10.

Просто, еще раз, надо использовать правильный инструмент для правильной работы. Если данные холодные, запросы к ним редкие, но сложные, то реляционные базы — это идеальный инструмент. А если это хранилище профилей, сессий или любой другой горячей информации, то Тарантул идеален.
Вы, конечно, очень радужно все описываете, однако какой как выглядит «холодный старт» тарантула? Я так понимаю, что ему необходимо прочитать с диска снапшот, затем проиграть «хвост» операций из журнала, затем перестроить индексы. И это все время полного простоя. Допустим, снапшот с нашими данными «весит» 80 гигабайт. Чтобы просто прочитать это с диска потребуется порядка 81920 / 200 ~ 409 секунд или почти 7 минут (200 mb/s вполне достойная скорость линейного чтения?). И это не какой-то «разогрев», когда «все тормозит». Это реальный 100%-й downtime.

Кстати, насчет сохранения снапшота: правильно ли я понял, что по факту нужен двойной объем RAM? Я так понимаю, что используется fork + COW, но ведь это может стрельнуть в самый неожиданный момент.

Да, а как быть со «сложными запросами», когда нужно использовать то один, то другой индекс, да еще дополнительно отфильтровывать результаты? Вы так настаиваете на сравнении с настоящими базами данных, что невольно хочется попросить предоставить кусок lua-процедуры, реализующий join в трех таблицах, где в where-условии также участвуют поля хотя бы из двух таблиц. Я представляю себе, как это выглядит, но не представляю человека, которому SELECT… FROM… JOIN… WHERE покажется сложнее, чем портянка аналогичного lua-кода.

Ну и напоследок: что у вас делают, когда в многогигабайтной расшардированной базе появляется необходимость делать выборку по новому полю? Как добавить индекс без простоя?
1. Можно использовать репликацию, тогда простой будет минимальный. Также у Tarantool есть режим hot standby, когда резервный сервер прямо на той же машине догоняется логами основного и, в случае проблем, занимает его место. Используется для апгрейда без простоя. Думаю автор поста расскажет подробнее.

2. Снапшот уже давно на основе MVCC в памяти без fork() и COW. Дополнительная память так или иначе требуется, объем зависит от характера нагрузки. Результаты MVCC при реальном использовании существенно лучше, чем на fork()'е.

3. Забудьте про JOIN в любой более-менее загруженном проекте. Тем более через SQL с планировщиком запросов.
Точно также как любая конференция по Java всегда начинается с рассказа о новых способах тюнинга garbage collector через настройку пяти десятков опций, так и любая конференция по той же PostgreSQL или MySQL (хорошие базы, привожу в качестве понятного примера) всегда включает в себя рассказ о «секретных» методах передачи подсказок несчастному планировщику для повышения его предсказуемости. USING INDEX и прочий не совсем SQL растёт оттуда же. SELECT… FROM… JOIN… WHERE на кластере так и вообще что-то из области ненаучной фантастики. Также хотел бы заметить, что хранить данные в нормализованном виде не всегда оправдано. В реальных задачах очень часто дешевле допустить некоторую избыточность, но при этом полностью избавиться от JOIN.

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

4. Изменение схемы данных в рабочем проекте — это тема для отдельной докторской диссертации статьи. Скажу лишь что в Tarantool можно добавлять и удалять таблички и индексы на лету.
>у Tarantool есть режим hot standby, когда резервный сервер прямо на той же машине догоняется логами основного
Ценой 2x по памяти?

>Забудьте про JOIN в любой более-менее загруженном проекте
Согласен. Но ведь в любом проекте рано или поздно наступает момент сбора и подсчета продуктовой статистики, где SQL начинает блистать, предоставляя возможность очень просто конструировать и выполнять сложные запросы с агрегатными функциями, join-ами, группировкой и прочими плюшками. В таких задачах хочется гибкости, а не писать руками join/avg и прочее на каждый чих.

>В реальных задачах очень часто дешевле допустить некоторую избыточность, но при этом полностью избавиться от JOIN.
Зависит от задач. Денормализация подразумевает дублирование данных, а дублирование, как правило, идет рука об руку с рассинхронизацией. И не надо забывать, что в РСУБД данные не хранятся в памяти и проблема JOIN-ов на самом деле лежит в области seek-ов по диску. Странно, что в тарантуле, где все хранится прямо в локальной оперативной памяти, могут быть какие-то проблемы с подобными запросами. Однако согласен, JOIN + WHERE + ORDER BY для результата на десятки тысяч строк ни к чему хорошему и в оперативной памяти не приведет.

Что же касается планировщика и USING INDEX… Как правило, планировщик действительно лучше знает, какие индексы использовать в сложных запросах, USING INDEX был хорош в древние времена, дабы избегать filesort'ы. Очень странно, что проводя аналогию Tarantool — *SQL, вы замалчиваете, что любой запрос в тарантуле — это явный USING INDEX.

>Скажу лишь что в Tarantool можно добавлять и удалять таблички и индексы на лету.
А как выглядит добавление индекса на лету в однопоточном сервере?
>у Tarantool есть режим hot standby, когда резервный сервер прямо на той же машине догоняется логами основного
Ценой 2x по памяти?

Да, именно так. Поэтому вариант с репликой мне нравится гораздо больше.

В таких задачах хочется гибкости, а не писать руками join/avg и прочее на каждый чих.

Для этого и хотим сделать SQL.

>Скажу лишь что в Tarantool можно добавлять и удалять таблички и индексы на лету.
А как выглядит добавление индекса на лету в однопоточном сервере?

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

А DELETE/UPDATE по вторичным индексам реализован в 1.6?
В дополнение к ответу выше. Мы всегда имеем горячую реплику. Если машина падает, то нагрузка автоматом уходит на реплику.

Насчет 100% downtime. Да, если ВСЕ реплики свалятся, то будет в указанном вами случае будут минуты даунтайма. 5-14 минут в зависимости от типа диска — для SSD линейное чтение — 300Mb/s, для SATA — 100Mb/s.

Но давайте вспомним про традиционные базы данных (MySQL/Postgress), они прогревают кэши хорошо если со скоростью 1-3Mb/s, и там будет 50% downtime на протяжении часов, что, согласитесь, еще хуже. Причем, в случае с MySQL вы даже ETA этого downtime предсказать не можете. Мы на это нарывались ни раз.

Насчет SQL. Да это удобнее Lua во многих случаях (но как сказал автор выше — не на heavy workloads). И именно поэтому мы сейчас в процессе прикручивания SQL к Тарантулу. Следите за обновлениями! :)
>Если машина падает, то нагрузка автоматом уходит на реплику.
Можно поподробнее с этого момента? Это встроенная возможность стандартного tarantool-коннектора, или вручную кодится в каждом клиенте? И если с SELECT-ами все понятно, то как быть с модифицирующими запросами в такой схеме? Как вы избегаете split brain-а при автоматических переключениях?

>Но давайте вспомним про традиционные базы данных (MySQL/Postgress), они прогревают кэши хорошо если со скоростью 1-3Mb/s
Откуда взята такая странная цифра? Традиционным базам нужно, чтобы индексы попали в page cache, что в некоторых случаях достижимо простым cat index.MYI > /dev/null на той же самой линейной скорости чтения.

>50% downtime на протяжении часов
Это как? Кроме того, разве в наше время такой downtime не решается установкой SSD для диска с данными? Будет ли хранение данных в RAM более экономным, чем использование SSD + «традиционная РСУБД»?
Отвечаю по порядку:

1. Это отличный вопрос! Прямо сейчас в стандартных коннекторах такой возможности нет. У нас есть внутренняя возможность в Mail.Ru, которую мы скоро отдадим в community. Там вся сложность в том, что это нельзя просто реализовать в коннекторе, надо делать прокси. А мы это у себя реализовали в своих собственных внутренних проксях, через которые мы из любого кода ходим в Тарантул.

Насчет update'ов. У нас есть уже в 1.6 асинхронная репликация мастер-мастер. Если вы в своем коде поддержите такую логику «не получилось в одну базу, сходили в другую», то вы сможете применять и апдейты тоже. В этой схеме будет eventual consistency и в случае конкурирующих изменений будет применяться грубо говоря случайное. Для многих задач такая логика вполне подходит.

В 1.7 у нас будет синхронный мастер-мастер на основе RAFT. Это даст возможность strong consistency, при этом с high availability, т.е. без downtime при падении машины. Разумеется, проблема network partitioning останется — если на кластере из 3 машин они разрежутся недоступной сетью на две группы 1 и 2, то та группа, где 1 машина будет недоступна ни на чтение ни на запись. Но тут уж ничего не поделаешь, CAP теорема :)

2. Это если у вас столько памяти, что вы готовы хранить индексы и в page cache и внутри базы целиком. Тогда, да. Вообще, если база почти целиком влезает в память, то все проще. Но как я написал в одном из коментов выше — даже в этом случае тарантул в разы быстрее + оптимальней в разы по памяти. Если же у вас нет лишней памяти на page cache под весь индекс или индекс целиком не влезает в память, то прогрев идет просто за счет запросов в базу, что медленно.

3. Пока база греется путем запросов в нее, то она вся стоит в диск и какую-то часть запросов не обрабатывает. 50% — это примерно то, что я знаю по нашему опыту подобных проблем эксплуатации MySQL и Postgres.

4. SSD для традиционной базы лучше чем SATA. Но все равно не дотягивает до Тарантула по производительности на порядок и больше. Хранение в RAM будет более экономной, потому что не надо много реплик (одна машина тарантула тянет такую же нагрузку как десятки машин с традиционными базами), потому что более оптимальный memory footprint, потому что не нужен SSD (SATA для Тарантула вполне достаточно). Если хотите, можете дать мне вашу конфигурацию, с количеством и спецификацией машин, с базами, которые там стоят и с QPS, а я прикину, какие бы и в каком количестве машины держали ту же самую нагрузку на Тарантуле.

По п.1 (фича-реквест): раз в Тарантуле нет никаких настроек, то может быть, для разных use case и разных проблем с сетью сделать флаги на чтение типа «отдать обязательно последние данные» либо «отдать какие-нибудь доступные данные»?
Просто иногда («для статистики») бывает полезнее получить хоть что-то, чем ничего.
Ну и при ответе можно ещё рядом сообщить, что именно отдали: последнее или определённой свежести.
>А мы это у себя реализовали в своих собственных внутренних проксях, через которые мы из любого кода ходим в Тарантул.
Что такого можно сделать во внешней проксе, чего нельзя сделать в коннекторе?

>У нас есть уже в 1.6 асинхронная репликация мастер-мастер
Дублирование запроса на соседа — это дублирование запросов на соседа. Репликация все-таки должна оставлять данные в консистентном состоянии.

>В 1.7 у нас будет синхронный мастер-мастер на основе RAFT.
Честно говоря, я не вполне понимаю вектор развития tarantool. То он позиционируется как «мемкеш на стеродидах», то как «lua application server». Судя по рекламе, которую вы даете в своих постах, это интересная наработка, которой мало кто пользуется, потому что не знают, как. Вы лучше определитесь с нишей, соберите набор best practices, дефолтные конфигурации для типовых задач, и т. д. Вот MySQL, сколько бы его ни ругали, используют повсеместно, потому что о нем полно информации.

>Вообще, если база почти целиком влезает в память, то все проще.
Кстати, а что делать, когда данные перестают влезать в один тарантул? Есть какие-то утилиты/гайды по шардингу или отдел эксплуатации каждый раз все заново изобретает?

>Если же у вас нет лишней памяти на page cache под весь индекс или индекс целиком не влезает в память
Я же писал, что можно параллельно cat'нуть индексный файл в /dev/null в некоторых случаях. И индекс всегда меньше данных. Взять, к примеру, базу постов хабра: реляционная база, хранящая только индексы по сообщениям и постам будет потреблять на это меньше памяти, чем tarantool, также хранящий в памяти тела сообщений.

>Хранение в RAM будет более экономной, потому что не надо много реплик (одна машина тарантула тянет такую же нагрузку как десятки машин с традиционными базами)
А можно с этого момента поподробнее? «Традиционные базы» могут использовать многоядерность современного железа и, как правило, успешно обрабатывают весьма нетривиальные запросы. Для простейших запросов по индексу у MySQL есть handlersocket, который в свое время позволял выжимать десятки тысяч запросов в секунду с одной железки. Более того, если база вдруг начинала «упираться в CPU», то можно было существенно все ускорить заменой железа: даешь больше ядер, получаешь лучшую производительность без каких-либо затрат на поддержку/разработку.
Это, кстати, весьма актуальный вопрос, т. к. я не нашел бенчмарков с простенькими луашками, которые делают, скажем, простенький left join для результата из одной записи.
> Что такого можно сделать во внешней проксе, чего нельзя сделать в коннекторе?

Прокси хранит состояние. Например, она помнит, какие сервера с этого конкретного сервера были недоступны. Кроме того, прокси помнит схему шардинга, т.е. на какой машине что живет и постоянно обновляет эту схему с центральной машины (если она недоступна — не страшно, все работает, нельзя только в этот момент доставлять новые сервера, т.е. downtime нет).

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

Кроме того, коннектор надо конфигурять (задать список машин, путь для лог файла (потому что надо вести лог и понимать, что успешно, а что нет)), что придется делать в клиентах, что неудобно.

В целом, у нас большой опыт по созданию fault-tolerance для различных хранилищ. Большой портал, многодесятко миллионная аудитория. Но если вы подскажите как правильно реализовать fault-tolerance в коннекторе и у вас есть такой опыт, то будем рады послушать :-)

В любом случае, мы задумались над этой темой. Будем думать как сделать fault-tolerant коннектор без прокси.

>Дублирование запроса на соседа — это дублирование запросов на соседа. Репликация все-таки должна оставлять данные в консистентном состоянии.

У нас есть на выбор 2 из 3 широко известных человечеству и часто используемых репликаций, а в 1.7 будет и третья. 3 — это я имею в виду master-slave, master-master, Paxos/RAFT. В MySQL, к примеру, есть только в стабильном виде master-slave.

Насчет консистентного состояния. Стандартный master-slave, который есть в Тарантуле и есть во всех популярных СУБД не является strong consistent. Т.е. данные на мастере поменялись, реплика этих изменений еще не видит, а клиентский код уже пошел на реплику. master-master, который дополнительно есть в танрантуле тоже не является strong consistent, но зато он позволяет создать почти 100% availability, потому что всегда есть сервер куда записать. С другой стороны он создает проблему конкурирующих апдейтов, которой нет в master-slave, но для некоторых кейсов это не страшно. Paxos/RAFT же решает эту проблему. Данные всегда consistent и всегда available за исключением случая network partitioning.

Какую схему выбирать — решаете вы. Но мы можем подсказать, в каком случае какая лучше. Если есть вопросы — обращайтесь :-)

>Честно говоря, я не вполне понимаю вектор развития tarantool. То он позиционируется как «мемкеш на стеродидах», то как «lua application server». Судя по рекламе, которую вы даете в своих постах, это интересная наработка, которой мало кто пользуется, потому что не знают, как. Вы лучше определитесь с нишей, соберите набор best practices, дефолтные конфигурации для типовых задач, и т. д. Вот MySQL, сколько бы его ни ругали, используют повсеместно, потому что о нем полно информации.

Тарантул — это СУБД и кэш в одном флаконе. Он обладает почти всеми основными фичами СУБД (транзакции, репликация, персистенс, хранимые процедуры, таблицы, вторичные индексы) и всеми свойствами кэшей (быстро работает, большой QPS, маленький latency). И это позволяет отказаться от схемы база + кэш и просто применять Тарантул. Что дает лучшую целостность данных, решает проблему холодного старта и самое главное — дает огромную пропускную способность на запись данных.

Т.е. Тарантул — это лучшая из нам известных замена база + кэш на единую базу, с, еще раз, улучшением при этом основных параметров работы (скорость, количество серверов, целостность данных).

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

>Кстати, а что делать, когда данные перестают влезать в один тарантул? Есть какие-то утилиты/гайды по шардингу или отдел эксплуатации каждый раз все заново изобретает?

Утилиты/гайды есть. Но они пока не совсем полностью отданы в community. Мы сейчас над этим работаем. Плюс, мы прямо сейчас работаем над механизмом автошардинга, чтобы можно было ставить кластер серверов, который бы автоматом бы шардился и реплицировался и был бы виден снаружи через коннектор просто как единая база.

>Я же писал, что можно параллельно cat'нуть индексный файл в /dev/null в некоторых случаях. И индекс всегда меньше данных. Взять, к примеру, базу постов хабра: реляционная база, хранящая только индексы по сообщениям и постам будет потреблять на это меньше памяти, чем tarantool, также хранящий в памяти тела сообщений.

Если индекс влезает в 50% памяти, то cat поможет отлично. Если нет — то не совсем, потому по результату работы cat весь индекс доожен попасть в буферный кэш, а потом весь индекс должен по тихоньку считаться из буферного кэша, но так чтобы во время чтения не вытеснить другие части буферного кэша на диск, которые еще предстоит считать. Т.е. если у вас памяти на машине 64G, а индекс весит, скажем 50G, то cat поможет не сильно. А если индекс весит >64G, то cat не факт, что поможет вообще.

Насчет постов хабра — тут надо смотреть. Если все данные весят, скажем 1Tb, а индексы весят, скажем 128G в базе и все работает на одном сервере, скажем MySQL, без шардинга, то тогда все круто и надо применять MySQL. Если же это все хозяйство надо шардить на, скажем 4 сервера с шардами и по 4 реплики на каждый, чтобы тянуло нагрузку и на каждом по, скажем, 32G памяти (как раз 1/4 индекса), то суммарно это будет весить в памяти на всех серверах 32*16 = 512G. В случае тарантула же можно весь 1Tb запихнуть в него на 1 машину и он потянет нагрузку. А поскльку у него memory footprint оптимальнее MySQL, то это реально будет весить 300-400Gb. Т.е. уже меньше потребляет памяти и 1 сервер вместо 16 (ну на самом деле 2 сервера, реплику-то тоже надо на всякий пожарный, но все же 2, а не 16). Это все грубые прикидки — надо смотреть как оно на самом деле.

Но мораль статьи-то простая — если все работает без шардинга и репликаций на 1-2 серверах MySQL и lanetcy устраивает, то все круто и трогать ничего не надо :-)

>А можно с этого момента поподробнее? «Традиционные базы» могут использовать многоядерность современного железа и, как правило, успешно обрабатывают весьма нетривиальные запросы. Для простейших запросов по индексу у MySQL есть handlersocket, который в свое время позволял выжимать десятки тысяч запросов в секунду с одной железки. Более того, если база вдруг начинала «упираться в CPU», то можно было существенно все ускорить заменой железа: даешь больше ядер, получаешь лучшую производительность без каких-либо затрат на поддержку/разработку.

Это все правда. Даже и спорить не буду. Просто, еще раз, если уже стоит много реплик/шардов баз данных и вы хотите сэкономить на железе + улучшить латенси, то надо смотреть в сторону тарантула. Если это 1-2 машины, пусть и мощные и вы не хотите экономить на них, или вам некуда их продать/отдать, то тогда пусть все остается на традиционной базе.

>Это, кстати, весьма актуальный вопрос, т. к. я не нашел бенчмарков с простенькими луашками, которые делают, скажем, простенький left join для результата из одной записи.

Должно работать также быстро как и выборка по key-value, если result set это 1 запись и есть индекс. Но вы правы, бенчмарков не хватает. Будем работать над этим. Спасибо! :-)
Планируется ли какое-то сжатие, в памяти или на диске, как в TokuDB? Для хранения и использования логов это было бы очень полезно.
Сжатие в disk store очень даже планируется. Кстати, скоро опубликуем тесты по disk store. Он бьет по производительности не только все B-Tree базы данных, но и новомодные движки типа TokuDB и RocksDB.
И правильно ли я понимаю, что если какие-то значения меняются по 100 раз (например цена товара, или постоянная правка описания), то на диске это будет занимать в 100 раз больше места? Есть какой ручной или фоновый режим очистки этих ненужных записей по типу mysql optimize table,
Простите, не туда написал комент. Дублирую сюда :)

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

Важное свойство transaction log — это то, что вероятность того, что база данных побьется (перейдет в нецелостное состояние) в случае аварийного падения сервера практически равна нулю. Ибо в снэпшоте уже есть целостное состояние базы на какой-то момент времени, а запись в transaction log происходит строго последовательно, поэтому в самом худшем случае просто откатятся несколько последних изменений (которые, кстати, применились на реплике, поэтому даже в этом случае не будет потери данных). В то время как в традиционных базах данных идет запись постоянно в table space, что в случае аварийного рестарта сервера можно привести к «фаршу» в данных. Фарш, конечно, чинится разными инструментами, но это, во-первых, downtime, а во-вторых, потеря не последних изменений, а просто рандомных данных.

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

Можете написать про ваш конкретный кейс (если хотите в личку: anikin@corp.mail.ru) и я вам расскажу подойдет ли Тарантул в вашем случае, и если подойдет, то как его настроить.
Да. И поэтому есть снэпшоттинг, который раз в настроенное вами время сбрасывает всю базу на диск. После чего все transaction logs до момента снэпшота можно удалять.

Важное свойство transaction log — это то, что вероятность того, что база данных побьется (перейдет в нецелостное состояние) в случае аварийного падения сервера практически равна нулю. Ибо в снэпшоте уже есть целостное состояние базы на какой-то момент времени, а запись в transaction log происходит строго последовательно, поэтому в самом худшем случае просто откатятся несколько последних изменений (которые, кстати, применились на реплике, поэтому даже в этом случае не будет потери данных). В то время как в традиционных базах данных идет запись постоянно в table space, что в случае аварийного рестарта сервера можно привести к «фаршу» в данных. Фарш, конечно, чинится разными инструментами, но это, во-первых, downtime, а во-вторых, потеря не последних изменений, а просто рандомных данных.

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

Можете написать про ваш конкретный кейс (если хотите в личку: anikin@corp.mail.ru) и я вам расскажу подойдет ли Тарантул в вашем случае, и если подойдет, то как его настроить.
А сумма в миллион долларов — это из расчета на год? А то как то странно выглядит стоимость, сейчас даже для юрлиц самые дорогие конфигурации в сумме меньше в ДЦ… Вроде как....
Sign up to leave a comment.