Как стать автором
Обновить
98
0
Денис Аникин @danikin

Пользователь

Отправить сообщение
Ну так для этого хаб с Tarantool на нем и существует — он общается с интернетом по защищенному протоколу (SSL) и он является открытым решением. Т.е. вы всегда можете залезть на него (если железка под вашим контролем) и посмотреть на код, который на нем исполняется (в том смысле, чтобы убедиться, что кто-то физически не подменил железку или не залил туда свой код, обладая физическим доступом).
Ну т.е. проблема локализована, вопрос исчерпан?
1. А зачем использовать в виде индекса дерево (O(log(N)), если и хэш (O(1)) подходит? В Tarantool специально для этого есть разные виды индексов — TREE и HASH.

2. Это обман оптимизатора. Чтобы он по честному прошел весь цикл. Важно, что там внутри цикла есть как минимум одно обращение по индексу. Моделируем SIZE обращений по индексу.

3. https://habrahabr.ru/company/mailru/blog/317274/#comment_9959174
Про Транзакции почитайте тут: http://kostja.github.io/misc/2017/01/24/tarantool-design-principles.html и тут: https://tarantool.org/doc/book/box/atomic.html

По поводу второго вашего вопроса — правильно понимаете. Но скорее всего у вас нет и не будет таких нагрузок, чтобы одна машина с Тарантулом не справилась. Даже у мейла редко бывают такие нагрузки — и мы ставим 4 машины, шардим на уровне приложения и это работает на долгие годы впероед.
ACID обеспечивает. SQL в процессе. Если интересен недекларативный язык запросов, то это Lua, работает в виде хранимых процедур внутри Tarantool.
В базе все пишется внутри на Lua. Вы лукапите в один индекс, находите поле, далее по этому полю лукапите в другой индекс. Все занимает как два обращения по индексу. По времени — плюс-минус как два раза в std::unordered_map сходить в терминах С++ + накладные расходы на сетевой вызов.
«Обычно в таких случаях я локализовывал проблему до минимальной программы, на которой она воспроизводится, т.е. откусывал от нее куски «методом половинного деления», пока не оставалась минимальная по размеру программа, в которой устойчиво воспроизводилась проблема.» — до какой программы вы в итоге дошли?
Более менее простые. Или выборки/обновления по первичному/вторичному индексу или Lua-код из, условно, 5-10 строчек, внутри которого один-два подобных запроса.
Мы пока размышляем на эту тему. Как вариант предлагаем вам попробовать написать на Lua прямо внутри Tarantool, используя его не только как СУБД, но и как сервер приложений.
«Нереляционные СУБД правильно будет сравнивать с другими нереляционными СУБД.» — я не понимаю, по какому принципу в вашей голове сортируется правильно/не правильно, поэтому сразу вопрос — нельзя ли в той же логике сказать, что СУБД правильно сравнивать с другими СУБД, а не с движками? RocksDB — это движок, т.е. бибиотека, которую вы вкомпиливаете себе в код, в нем нет клиент-серверной модели, нет репликации, все это надо делать ручками.

«когда вся БД расположена на виртуальном диске размещенном в оперативной памяти» — мне трудно представить кейс, когда бы я стал такое делать. Компьютер перезагрузился и данные пропали. Поэтому я пока не вижу повода писать статью. Напишите вы, я почитаю.

Но раз уж вы настаиваете, то Redis и RocksDB были созданы для разных видов нагрузок. Redis — это ин-мемори кэш с персистенсом и репликацией. Он используется для высоких нагрузок на чтение-запись и обеспечивает скорость ответа в милисекунды. RocksDB — это дисковый движок, построенный на LSM дереве. Используется там, где надо хранить данные, не влезающие в память (в отличие от Redis) и на которые большая нагрузка на запись. RocksDB сильно медленнее Redis на чтение, медленнее и на запись, но уже не так драмматично (цифры под рукой есть, но не пишу их сюда, дабы не развивать отдельный холи вор, ибо цифры цифрам рознь, получены при разных условиях и тд). Чем Redis лучше RocksDB? Он быстрее, у него есть репликация из коробки, он работает как клиент-сервер. Чем RocksDB лучше Redis? Он менее требователен к оперативной памяти чем Redis на одном и том же объеме данных.
Читать с конца :-)

Denis Anikin <danikin1@gmail.com> Mon, Dec 12, 2016 at 8:45 AM
Reply-To: Denis Anikin <danikin1@gmail.com>
To: Robert <robert.ayrapetyan@gmail.com>
В целом, идея интересная. Надо экспериментировать и считать, какой там реально выигрыш по цпу и какой проигрыш по памяти на реальных кейсах.

Sent from myMail for iOS

Monday, 12 December 2016, 06:20 +0300 from Robert <robert.ayrapetyan@gmail.com>:
У себя использую Boost.Interprocess segregated storage pool, перемещений там не используется, и память мендежеру сегмента никогда не возвращается (как у вас), но для моих целей это и не нужно.
Это нечто похожее на ваш аллокатор (набор chunks поделенных на ноды фиксированного размера).

Так вот зная положения всех используемых chunk-s, и нод в них и копируя их линейно побайтово одну за другой (ноды), мы получим копию своей структуры с некоторым кол-вом дырок (неиспользуемого пространства в ноде),

Т.е. выделив изначально 256Гб памяти под структуру и заполнив их данными, а затем освободив почти всю память и оставив полными только две ноды в одном чанке, мы копируем только эти две ноды, остальные ноды (заранее известные дыры в других чанках) копировать не нужно.

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

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

Поэтому — фактически хуже по памяти (незначительно), но ускорение в копировании — в 10 раз (судя по вашим данным в статье, где вы пишите: скорость может составлять 200-500 Мбайт/с для более-менее продвинутых структур данных).

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

On 12/11/16 13:01, Dennis Anikin wrote:
Давайте по порядку.

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

2. Ваши оптимизации вышеуказанного алгоритма лучше чем вышеуказанный алгоритм по скорости, но хуже по памяти (временная копия будет занимать больше, из-за копирования дырок). Память vs скорость — извечный вопрос. Нельзя, ИМХО, говорить, что жертвовать одним или другим лучше — надо разбираться в конкретной ситуации глубже, а если разобраться нельзя, то хотя бы оставлять юзеру опцию.

3. Нулей (если вы так называете дырки) может быть много. Что я имею в виду тут? Мы аллоцируем сразу столько памяти, сколько пользователь разрешил нам в конфиге и потом уже в ней выделяем все собственными аллокаторами. Если юзер нам сказал аллоцировать 256Гб, и размер базы был сначала 256Гб, а потом оттуда поудалялось случайных записей так, что ее размер упал до 1Гб, то процесс будет потреблять по прежнему 256Гб (в RSS). Потому что мы не перемещаем участки, чтобы они шли подряд — мы оставляем дырки, фиксированного размера, разделенные на группы (каждая группа — свой размер), а потом их заполняем, чтобы выделение памяти было за O(1) (используем алгооритмы сходные с этими https://en.wikipedia.org/wiki/Slab_allocation). В ваших алгооритмах и структурах, возможно, есть перемещение, причем так, что оно не влияет сильно на скорость доступа и при этом, чтобы дырки все убирались изнутри в конец, предполагая таким образом, что копировать надо не все максимальные 256Гб как в нашем случае, а до какой-то отсечки, после которой точно уже идут только дырки. Поделитесь ими, пожалуйста. Почитаем. Если перемещения у вас нет, то 1Гбайтная база будет копироваться в укромное место в памяти путем копирования всех 256Гбайт вместе с дырками.

41 GMT+03:00 Robert <robert.ayrapetyan@gmail.com>:
Голосом я общаться не боюсь, считаю, что технические вопросы обсуждать голосом не продуктивно.

Если вы не против — продолжим общаться письменно (тем более что по сути уже все озвучено, думаю).
Относительная адресация — это лишь один из способов реализации. Есть еще другой — явно запросить линейный адрес начала сегмента при выделении у ОС. Тогда внутри структуры вы можете пользоваться абсолютными адресами и оверхеда на конвертацию не будет. По поводу дырок — ничего страшного, скопируете эти дырки вместе с полезными данными. Это небольшая плата за максимально возможную скорость копирования. Конечно, если у вас в среднем объем дырок сопоставим с объемом данных, то данная стратегия не выгодна, но здесь возникает вопрос об эффективности реализации аллокатора памяти в ваших структурах.
Цитирую ваш комментарий с хабра:

«Если вы сделаете в Тарантул pull-request, который мы примем и который бы поменял там все структуры таким образом, чтобы они копировались в среднем со скоростью 5Gb/s для баз данных в 256Gb, и которые при этом не занимали бы больше памяти, чем имеющиеся, то я вам тут же заплачу 3 миллиона рублей.»

Насколько я понял, скорость здесь важна только для минимизации лока базы при первоначальном копировании (RAM to RAM), а дальше (дамп на диск) уже не критичен по скорости (т.к. здесь уже база разлочена и ничего не мешает работе клиента). Мое предложение отвечает данному запросу (5Гб\с, 256Gb данных и нулей копируются в 256Гб данных и нулей, но не бойтесь — коммитить я не собираюсь и 3 миллиона рублей вы можете раздать своей команде на реализацию этой простой идеи или другой идеи с похожей идеей в основе).

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

On 12/11/16 11:10, Dennis Anikin wrote:
Вопросы-то те же самые остались. Относительная адресация — это круто! Но во-первых, надо каждый раз при обращении конвертить адреса, что слегка затормозит работу, во-вторых, наши структуры данных содержат «дырки» (но если ваши работают без дырок, то я бы послушал с удовольствием про них). Эти дырки сериализовать — это дополнительная нагрузка на диск, что сделает сериализацию медленнее, потому что узкое место у нас по прежнему диск при сериализации. Итого, ваш метод, если я правильно его понял, в нашем конкретном случае сделает все только хуже. И в качестве дополнительного бонуса при рассериализации сейчас у нас дефрагментация данных автоматом. В вашем случае это будет не так. Надо будет явно дефрагментировать.

Ну и самое главное, что даже в случае 5Гб/сек база данных все равно залипнет на минуту и потребление памяти удвоится (даже больше чем удвоится, если вспомнить про дырки), поэтому решение с копированием, даже с очень быстрым все равно пришлось бы отмести.

Если не боитесь пообщаться голосом, то я готов. Мне кажется, мы так быстрее придем к истине.

2016-12-11 21:49 GMT+03:00 Robert <robert.ayrapetyan@gmail.com>:
Отлично!

Теперь, как же так получается, что разные процессы по разным линейным адресам видят одни и те же данные?

Реализаций тут несколько. Одна из них — использование относительной адресации в струкрурах (т.е. нет никаких ссылок внутри структур, которые бы сконвертились в разные физические адреса в разных процессах, получится каша и несколько процессов не смогут работать с такой разделяемой структурой).
Остановимся на данной реализации.
Я утверждаю, что любую структуру (в том числе и используемую в вашем проекте), можно реализовать используя относительную адресацию. Действительно, относительная адресация есть частный случай абсолютной. Т.е. к некоему заранее известному базовому адресу (начало сегмента памяти) прибавляется некое смещение, хранящееся в полях вашей струкруры).

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

Собственно про это я и пытался сказать на хабре.

Теперь готов выслушать ваши вопросы, и постараться на них ответить.

On 12/11/16 10:39, Dennis Anikin wrote:
Привет.

Ок, звучит разумно.

Ответ на обо заданных вами вопроса — «Да».

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

2016-12-11 20:25 GMT+03:00 Robert <robert.ayrapetyan@gmail.com>:
Привет, раз уж ввязался, то готов разъяснить и ответить на вопросы по поводу расположения любой структуры в непрерывно выделенном участке памяти.

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

Вопрос первый:

приходилось ли вам когда-нибудь пользоваться разделяемой памятью (shared memory)?

Если да, то вам известно, что все процессы, получившие доступ к разделяемой памяти, видят и оперируют одним и тем же непрерывно выделенным участком памяти

и структурами любой сложности в ней расположенными.

Известно ли вам о механизмах, лежащих в основе такого поведения?


Regards, Dennis


Regards, Dennis


Regards, Dennis

Пришли к общему знаменателю. Роберт, вы не против, если я опубликую нашу переписку?
Я, возможно, криво сформулировал. Но имелось в виду ровно то, что вы написали :-)
Для этих целей надо делать медленную реплику дисковой СУБД к быстрой in-memory СУБД и там спокойно и неспеша ворочать терабайтами.

А если неспеша нельзя?


По идее, ей ничего не мешает иметь аналогичный механизм скидывания временных таблиц на диск. Но вот имеет ли в реальности — не знаю.


Если не спеша нельзя, то значит репликация в СУБД, где будут ворочаться эти 10Гб не устраивает? Если так, то чем скидывание на диск поможет? :-)

Плюс, давайте рассмотрим ваш кейс. Очень вероятно, что все будет именно так как рассказал коллега в параллельном ответе.
Ну вы конечно мастрер общения…
Вот цитата, вы пишите, что в МТС биллинг был окружен самописной IMDB, и тут же добавляете, что Билайн переходит на Тарантула.
Речь о биллинге, не?
«переходит на Тарантула» <> «меняет базу на Тарантула»?


Билайн переходит. Пока не Биллинг. Но это только начало.

Давайте закругляться, Ок :-)
Устал уже говорить, что это давно используется в других системах.


Ну и отлично. IMDB это хорошо, даже в составе Биллинга. Что раньше, если я правильно понял коллег из этого чата, отрицалось намертво. Простите, если я неверно понял.

И на место тарантула можно выбрать кучу кандидатов.


Конечно.

Проблема в том, что они уже были выбраны давно в системах о которых шла речь.


Ну да.
Вы же заявили на весь свет, что Билайн меняет базу на Тарантула.
С вашей стороны это было совсем нескромное обобщение…
И я же еще и обобщаю что-то.


Цитату можно?

Насчет СиБОСС и всего, что вы написали ниже — кто-то масштабирует базу, кто-то окружает ее IMDB-решениями. Говорить, что одно заведомо лучше чем другое — мне кажется, слишком… эм… серьезное обобщение.
Обычно в таких случаях я локализовывал проблему до минимальной программы, на которой она воспроизводится, т.е. откусывал от нее куски «методом половинного деления», пока не оставалась минимальная по размеру программа, в которой устойчиво воспроизводилась проблема. Далее я превращал все в ассемблер и разбирался, как на самом деле выглядит код. В вашем случае — во что конкретно развернулось end()-begin().

Другой способ поиска проблемы, если программа точно однопоточная (надо в этом убедиться, ибо потоки могут юзаться где-то в либах глубоко внутри), то надо искать в выходы за границы массива и аккуратно проверить, что арифметика указателей везде корректная + надо посмотреть на const_cast, static_cast и reinterpret_cast (а также C-style cast) — нет ли там опасного.

Информация

В рейтинге
Не участвует
Откуда
Москва и Московская обл., Россия
Работает в
Дата рождения
Зарегистрирован
Активность