diff options
| author | George Hazan <ghazan@miranda.im> | 2019-12-06 17:15:42 +0300 |
|---|---|---|
| committer | George Hazan <ghazan@miranda.im> | 2019-12-06 17:15:42 +0300 |
| commit | 5077fc56fbde196cdf821e044b607d39a34ce258 (patch) | |
| tree | 9d46e9d8ddc22696e48d5073ef046ce3aebae85f /libs/libmdbx/src/README-RU.md | |
| parent | 3bb16e798cb51d5764aacbefd4edf26f52d8c4f0 (diff) | |
libmdbx: upgrade to 0.4.0
Diffstat (limited to 'libs/libmdbx/src/README-RU.md')
| -rw-r--r-- | libs/libmdbx/src/README-RU.md | 830 |
1 files changed, 0 insertions, 830 deletions
diff --git a/libs/libmdbx/src/README-RU.md b/libs/libmdbx/src/README-RU.md deleted file mode 100644 index e040b5c4bb..0000000000 --- a/libs/libmdbx/src/README-RU.md +++ /dev/null @@ -1,830 +0,0 @@ -### The [repository now only mirrored on the Github](https://abf.io/erthink/libmdbx) due to illegal discriminatory restrictions for Russian Crimea and for sovereign crimeans. -<!-- Required extensions: pymdownx.betterem, pymdownx.tilde, pymdownx.emoji, pymdownx.tasklist, pymdownx.superfences --> ------ - -libmdbx -====================================== -Доработанный и расширенный потомок [Lightning Memory-Mapped Database](https://ru.bmstu.wiki/LMDB_(Lightning_Memory-Mapped_Database)) (aka _LMDB_). -English version is [here](README.md). - -_libmdbx_ превосходит LMDB по возможностям и надежности, не уступая в -производительности. _libmdbx_ работает на Linux, FreeBSD, MacOS X и -других ОС соответствующих POSIX.1-2008, а также поддерживает Windows в -качестве дополнительной платформы. - -Отдельно ведётся не-публичная разработка следующей версии, в которой -будет кардинальное изменение как API, так и формата базы данных. Цель -этой революции - обеспечение более четкого и надежного API, добавление -новых функций, а также наделение базы данных новыми свойствами. - -*Всё будет хорошо. The Future will (be) [Positive](https://www.ptsecurity.ru).* - -[](https://travis-ci.org/leo-yuriev/libmdbx) -[](https://ci.appveyor.com/project/leo-yuriev/libmdbx/branch/master) -[](https://scan.coverity.com/projects/reopen-libmdbx) - -## Содержание -- [Обзор](#Обзор) - - [Сравнение с другими базами данных](#Сравнение-с-другими-базами-данных) - - [История & Выражение признательности](#История) -- [Описание](#Описание) - - [Ключевые свойства](#Ключевые-свойства) - - [Доработки и усовершенствования относительно LMDB](#Доработки-и-усовершенствования-относительно-lmdb) - - [Недостатки и Компромиссы](#Недостатки-и-Компромиссы) - - [Проблема долгих чтений](#Проблема-долгих-чтений) - - [Сохранность данных в режиме асинхронной фиксации](#Сохранность-данных-в-режиме-асинхронной-фиксации) -- [Использование](#Использование) - - [Сборка](#Сборка) - - [Привязки к другим языкам](#Привязки-к-другим-языкам) -- [Сравнение производительности](#Сравнение-производительности) - - [Интегральная производительность](#Интегральная-производительность) - - [Масштабируемость чтения](#Масштабируемость-чтения) - - [Синхронная фиксация](#Синхронная-фиксация) - - [Отложенная фиксация](#Отложенная-фиксация) - - [Асинхронная фиксация](#Асинхронная-фиксация) - - [Потребление ресурсов](#Потребление-ресурсов) - ------ - -## Обзор -_libmdbx_ - это встраиваемый key-value движок хранения со специфическим -набором свойств и возможностей, ориентированный на создание уникальных -легковесных решений с предельной производительностью. - -_libmdbx_ позволяет множеству процессов совместно читать и обновлять -несколько key-value таблиц с соблюдением -[ACID](https://ru.wikipedia.org/wiki/ACID), при минимальных накладных -расходах и амортизационной стоимости любых операций Olog(N). - -_libmdbx_ обеспечивает -[serializability](https://en.wikipedia.org/wiki/Serializability) -изменений и согласованность данных после аварий. При этом транзакции, -изменяющие данные, никак не мешают операциям чтения и выполняются строго -последовательно с использованием единственного -[мьютекса](https://en.wikipedia.org/wiki/Mutual_exclusion). - -_libmdbx_ позволяет выполнять операции чтения с гарантиями -[wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom), -параллельно на каждом ядре CPU, без использования атомарных операций -и/или примитивов синхронизации. - -_libmdbx_ не использует -[LSM](https://en.wikipedia.org/wiki/Log-structured_merge-tree), а -основан на [B+Tree](https://en.wikipedia.org/wiki/B%2B_tree) с -[отображением](https://en.wikipedia.org/wiki/Memory-mapped_file) всех -данных в память, при этом текущая версия не использует -[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging). Это -предопределяет многие свойства, в том числе удачные и противопоказанные -сценарии использования. - - -### Сравнение с другими базами данных - -На данный момент, пожалуйста, обратитесь к [главе "сравнение BoltDB с -другими базами -данных"](https://github.com/coreos/bbolt#comparison-with-other-databases), -которая также (в основном) применима к MDBX. - - -### История -_libmdbx_ является результатом переработки и развития "Lightning -Memory-Mapped Database", известной под аббревиатурой -[LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database). -Изначально доработка производилась в составе проекта -[ReOpenLDAP](https://github.com/leo-yuriev/ReOpenLDAP). Примерно за год -работы внесенные изменения приобрели самостоятельную ценность. Осенью -2015 доработанный движок был выделен в отдельный проект, который был -[представлен на конференции Highload++ -2015](http://www.highload.ru/2015/abstracts/1831.html). - -В начале 2017 года движок _libmdbx_ получил новый импульс развития, -благодаря использованию в [Fast Positive -Tables](https://github.com/leo-yuriev/libfpta), aka ["Позитивные -Таблицы"](https://github.com/leo-yuriev/libfpta) by [Positive -Technologies](https://www.ptsecurity.ru). - - -### Выражение признательности - -Говард Чу (Howard Chu) <hyc@openldap.org> является автором движка LMDB, от -которого в 2015 году произошел MDBX. - -Мартин Хеденфальк (Martin Hedenfalk) <martin@bzero.se> является автором кода -`btree.c`, который использовался для начала разработки LMDB. - ------ - -Описание -======== - -## Ключевые свойства - -_libmdbx_ наследует все ключевые возможности и особенности своего -прародителя -[LMDB](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database), -но с устранением ряда описываемых далее проблем и архитектурных -недочетов. - -1. Данные хранятся в упорядоченном отображении (ordered map), ключи -всегда отсортированы, поддерживается выборка диапазонов (range lookups). - -2. Данные отображается в память каждого работающего с БД процесса. К -данным и ключам обеспечивается прямой доступ в памяти без необходимости -их копирования. - -3. Транзакции согласно [ACID](https://ru.wikipedia.org/wiki/ACID), -посредством [MVCC](https://ru.wikipedia.org/wiki/MVCC) и -[COW](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8). -Изменения строго последовательны и не блокируются чтением, конфликты -между транзакциями невозможны. При этом гарантируется чтение только -зафиксированных данных, см [relaxing -serializability](https://en.wikipedia.org/wiki/Serializability). - -4. Чтение и поиск [без -блокировок](https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B0%D1%8F_%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F), -без [атомарных -операций](https://ru.wikipedia.org/wiki/%D0%90%D1%82%D0%BE%D0%BC%D0%B0%D1%80%D0%BD%D0%B0%D1%8F_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F). -Читатели не блокируются операциями записи и не конкурируют между собой, -чтение масштабируется линейно по ядрам CPU. - > Для точности следует отметить, что "подключение к БД" (старт первой - > читающей транзакции в потоке) и "отключение от БД" (закрытие БД или - > завершение потока) требуют краткосрочного захвата блокировки для - > регистрации/дерегистрации текущего потока в "таблице читателей". - -5. Эффективное хранение дубликатов (ключей с несколькими значениями), -без дублирования ключей, с сортировкой значений, в том числе -целочисленных (для вторичных индексов). - -6. Эффективная поддержка коротких ключей фиксированной длины, в том -числе целочисленных. - -7. Амортизационная стоимость любой операции Olog(N), -[WAF](https://en.wikipedia.org/wiki/Write_amplification) (Write -Amplification Factor) и RAF (Read Amplification Factor) также Olog(N). - -8. Нет [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) и -журнала транзакций, после сбоев не требуется восстановление. Не -требуется компактификация или какое-либо периодическое обслуживание. -Поддерживается резервное копирование "по горячему", на работающей БД без -приостановки изменения данных. - -9. Отсутствует какое-либо внутреннее управление памятью или -кэшированием. Всё необходимое штатно выполняет ядро ОС. - - -## Доработки и усовершенствования относительно LMDB - -1. Автоматическое динамическое управление размером БД согласно -параметрам задаваемым функцией `mdbx_env_set_geometry()`, включая шаг -приращения и порог уменьшения размера БД, а также выбор размера -страницы. Соответственно, это позволяет снизить фрагментированность -файла БД на диске и освободить место, в том числе в **Windows**. - -2. Автоматическая без-затратная компактификация БД путем возврата -освобождающихся страниц в область нераспределенного резерва в конце -файла данных. При этом уменьшается количество страниц находящихся в -памяти и участвующих в в обмене с диском. - -3. Режим `LIFO RECLAIM`. - - Для повторного использования выбираются не самые старые, а - самые новые страницы из доступных. За счет этого цикл - использования страниц всегда имеет минимальную длину и не - зависит от общего числа выделенных страниц. - - В результате механизмы кэширования и обратной записи работают с - максимально возможной эффективностью. В случае использования - контроллера дисков или системы хранения с - [BBWC](https://en.wikipedia.org/wiki/BBWC) возможно - многократное увеличение производительности по записи - (обновлению данных). - -4. Быстрая оценка количества элементов попадающих в запрашиваемый -диапазон значений ключа посредством функций `mdbx_estimate_range()`, -`mdbx_estimate_move()` и `mdbx_estimate_distance()` для выбора -оптимального плана выполнения запроса. - -5. Утилита `mdbx_chk` для проверки целостности структуры БД. - -6. Поддержка ключей и значений нулевой длины, включая сортированные -дубликаты. - -7. Возможность связать с каждой завершаемой транзакцией до 3 -дополнительных маркеров посредством `mdbx_canary_put()`, и прочитать их -в транзакции чтения посредством `mdbx_canary_get()`. - -8. Возможность посредством `mdbx_replace()` обновить или удалить запись -с получением предыдущего значения данных, а также адресно изменить -конкретное multi-значение. - -9. Генерация последовательностей посредством `mdbx_dbi_sequence()`. - -10. Обработчик `OOM-KICK`. - - Посредством `mdbx_env_set_oomfunc()` может быть установлен - внешний обработчик (callback), который будет вызван при - исчерпании свободных страниц по причине долгой операцией чтения - на фоне интенсивного изменения данных. - Обработчику будет передан PID и pthread_id виновника. - В свою очередь обработчик может предпринять одно из действий: - - * нейтрализовать виновника (отправить сигнал kill #9), если - долгое чтение выполняется сторонним процессом; - - * отменить или перезапустить проблемную операцию чтения, если - операция выполняется одним из потоков текущего процесса; - - * подождать некоторое время, в расчете на то, что проблемная операция - чтения будет штатно завершена; - - * прервать текущую операцию изменения данных с возвратом кода - ошибки. - -11. Возможность открыть БД в эксклюзивном режиме посредством флага - `MDBX_EXCLUSIVE`, в том числе на сетевом носителе. - -12. Возможность получить отставание текущей транзакции чтения от -последней версии данных в БД посредством `mdbx_txn_straggler()`. - -13. Возможность явно запросить обновление существующей записи, без -создания новой посредством флажка `MDBX_CURRENT` для `mdbx_put()`. - -14. Исправленный вариант `mdbx_cursor_count()`, возвращающий корректное -количество дубликатов для всех типов таблиц и любого положения курсора. - -15. Возможность получить посредством `mdbx_env_info()` дополнительную -информацию, включая номер самой старой версии БД (снимка данных), -который используется одним из читателей. - -16. Функция `mdbx_del()` не игнорирует дополнительный (уточняющий) -аргумент `data` для таблиц без дубликатов (без флажка `MDBX_DUPSORT`), а -при его ненулевом значении всегда использует его для сверки с удаляемой -записью. - -17. Возможность открыть dbi-таблицу, одновременно с установкой -компараторов для ключей и данных, посредством `mdbx_dbi_open_ex()`. - -18. Возможность посредством `mdbx_is_dirty()` определить находятся ли -некоторый ключ или данные в "грязной" странице БД. Таким образом, -избегая лишнего копирования данных перед выполнением модифицирующих -операций (значения, размещенные в "грязных" страницах, могут быть -перезаписаны при изменениях, иначе они будут неизменны). - -19. Корректное обновление текущей записи, в том числе сортированного -дубликата, при использовании режима `MDBX_CURRENT` в -`mdbx_cursor_put()`. - -20. Возможность узнать есть ли за текущей позицией курсора строка данных -посредством `mdbx_cursor_eof()`. - -21. Дополнительный код ошибки `MDBX_EMULTIVAL`, который возвращается из -`mdbx_put()` и `mdbx_replace()` при попытке выполнить неоднозначное -обновление или удаления одного из нескольких значений с одним ключом. - -22. Возможность посредством `mdbx_get_ex()` получить значение по -заданному ключу, одновременно с количеством дубликатов. - -23. Наличие функций `mdbx_cursor_on_first()` и `mdbx_cursor_on_last()`, -которые позволяют быстро выяснить стоит ли курсор на первой/последней -позиции. - -24. Возможность автоматического формирования контрольных точек (сброса -данных на диск) при накоплении заданного объёма изменений, -устанавливаемого функцией `mdbx_env_set_syncbytes()`. - -25. Управление отладкой и получение отладочных сообщений посредством -`mdbx_setup_debug()`. - -26. Функция `mdbx_env_pgwalk()` для обхода всех страниц БД. - -27. Три мета-страницы вместо двух, что позволяет гарантированно -консистентно обновлять слабые контрольные точки фиксации без риска -повредить крайнюю сильную точку фиксации. - -28. Гарантия сохранности БД в режиме `WRITEMAP+MAPSYNC`. - > В текущей версии _libmdbx_ вам предоставляется выбор между безопасным - > режимом (по умолчанию) асинхронной фиксации, и режимом `UTTERLY_NOSYNC` - > когда при системной аварии есть шанс полного разрушения БД как в LMDB. - > Для подробностей смотрите раздел - > [Сохранность данных в режиме асинхронной фиксации](#Сохранность-данных-в-режиме-асинхронной-фиксации). - -29. Возможность закрыть БД в "грязном" состоянии (без сброса данных и -формирования сильной точки фиксации) посредством `mdbx_env_close_ex()`. - -30. При завершении читающих транзакций, открытые в них DBI-хендлы не -закрываются и не теряются при завершении таких транзакций посредством -`mdbx_txn_abort()` или `mdbx_txn_reset()`. Что позволяет избавится от ряда -сложно обнаруживаемых ошибок. - -31. Все курсоры, как в транзакциях только для чтения, так и в пишущих, -могут быть переиспользованы посредством `mdbx_cursor_renew()` и ДОЛЖНЫ -ОСВОБОЖДАТЬСЯ ЯВНО. - > - > ## _ВАЖНО_, Обратите внимание! - > - > Это единственное изменение в API, которое значимо меняет - > семантику управления курсорами и может приводить к утечкам - > памяти. Следует отметить, что это изменение вынужденно. - > Так устраняется неоднозначность с массой тяжких последствий: - > - > - обращение к уже освобожденной памяти; - > - попытки повторного освобождения памяти; - > - повреждение памяти и ошибки сегментации. - -32. На **MacOS X** для синхронизации данных с диском _по-умолчанию_ -используется системная функция `fcntl(F_FULLFSYNC)`, так как [только -этим гарантируется сохранность -данных](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html) -при сбое электропитания. К сожалению, в сценариях с высокой -интенсивностью пишущих транзакций, использование `F_FULLFSYNC` приводит -к существенной деградации производительности в сравнении с LMDB, где -используется системная функция `fsync()`. Поэтому _libmdbx_ позволяет -переопределить это поведение определением опции -`MDBX_OSX_SPEED_INSTEADOF_DURABILITY=1` при сборке библиотеки. - -33. На **Windows** _libmdbx_ использует файловые блокировки -`LockFileEx()`, так как это позволяет размещать БД на сетевых дисках, а -также обеспечивает защиту от некомпетентных действий пользователя -([защиту от -дурака](https://ru.wikipedia.org/wiki/%D0%97%D0%B0%D1%89%D0%B8%D1%82%D0%B0_%D0%BE%D1%82_%D0%B4%D1%83%D1%80%D0%B0%D0%BA%D0%B0)). -Поэтому _libmdbx_ может немного отставать в тестах производительность от -LMDB, где используются именованные мьютексы. - - -## Недостатки и Компромиссы - -1. Единовременно может выполняться не более одной транзакция изменения данных - (один писатель). Зато все изменения всегда последовательны, не может быть - конфликтов или логических ошибок при откате транзакций. - -2. Отсутствие [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) - обуславливает относительно большой - [WAF](https://en.wikipedia.org/wiki/Write_amplification) (Write - Amplification Factor). Поэтому фиксация изменений на диске может быть - достаточно дорогой и являться главным ограничением производительности - при интенсивном изменении данных. - > В качестве компромисса _libmdbx_ предлагает несколько режимов ленивой - > и/или периодической фиксации. В том числе режим `MAPASYNC`, при котором - > изменения происходят только в памяти и асинхронно фиксируются на диске - > ядром ОС. - > - > Однако, следует воспринимать это свойство аккуратно и взвешенно. - > Например, полная фиксация транзакции в БД с журналом потребует минимум 2 - > IOPS (скорее всего 3-4) из-за накладных расходов в файловой системе. В - > _libmdbx_ фиксация транзакции также требует от 2 IOPS. Однако, в БД с - > журналом кол-во IOPS будет меняться в зависимости от файловой системы, - > но не от кол-ва записей или их объема. Тогда как в _libmdbx_ кол-во - > будет расти логарифмически от кол-ва записей/строк в БД (по высоте - > b+tree). - -3. [COW](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8) - для реализации [MVCC](https://ru.wikipedia.org/wiki/MVCC) выполняется на - уровне страниц в [B+ - дереве](https://ru.wikipedia.org/wiki/B-%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE). - Поэтому изменение данных амортизационно требует копирования Olog(N) - страниц, что расходует [пропускную способность оперативной - памяти](https://en.wikipedia.org/wiki/Memory_bandwidth) и является - основным ограничителем производительности в режиме `MAPASYNC`. - > Этот недостаток неустраним, тем не менее следует дать некоторые пояснения. - > Дело в том, что фиксация изменений на диске потребует гораздо более - > значительного копирования данных в памяти и массы других затратных операций. - > Поэтому обусловленное этим недостатком падение производительности становится - > заметным только при отказе от фиксации изменений на диске. - > Соответственно, корректнее сказать, что _libmdbx_ позволяет - > получить персистентность ценой минимального падения производительности. - > Если же нет необходимости оперативно сохранять данные, то логичнее - > использовать `std::map`. - -4. В _LMDB_ существует проблема долгих чтений (приостановленных читателей), - которая приводит к деградации производительности и переполнению БД. - > В _libmdbx_ предложены средства для предотвращения, быстрого выхода из - > некомфортной ситуации и устранения её последствий. Подробности ниже. - -5. В _LMDB_ есть вероятность разрушения БД в режиме `WRITEMAP+MAPASYNC`. - В _libmdbx_ для `WRITEMAP+MAPASYNC` гарантируется как сохранность базы, - так и согласованность данных. - > Дополнительно, в качестве альтернативы, предложен режим `UTTERLY_NOSYNC`. - > Подробности ниже. - - -### Проблема долгих чтений -*Следует отметить*, что проблема "сборки мусора" так или иначе -существует во всех СУБД (Vacuum в PostgreSQL). Однако в случае _libmdbx_ -и LMDB она проявляется более остро, прежде всего из-за высокой -производительности, а также из-за намеренного упрощения внутренних -механизмов ради производительности. - -Понимание проблемы требует некоторых пояснений, которые -изложены ниже, но могут быть сложны для быстрого восприятия. -Поэтому, тезисно: - -* Изменение данных на фоне долгой операции чтения может - приводить к исчерпанию места в БД. - -* После чего любая попытка обновить данные будет приводить к - ошибке `MAP_FULL` до завершения долгой операции чтения. - -* Характерными примерами долгих чтений являются горячее - резервное копирования и отладка клиентского приложения при - активной транзакции чтения. - -* В оригинальной _LMDB_ после этого будет наблюдаться - устойчивая деградация производительности всех механизмов - обратной записи на диск (в I/O контроллере, в гипервизоре, - в ядре ОС). - -* В _libmdbx_ предусмотрен механизм аварийного прерывания таких - операций, а также режим `LIFO RECLAIM` устраняющий последующую - деградацию производительности. - -Операции чтения выполняются в контексте снимка данных (версии -БД), который был актуальным на момент старта транзакции чтения. Такой -читаемый снимок поддерживается неизменным до завершения операции. В свою -очередь, это не позволяет повторно использовать страницы БД в -последующих версиях (снимках БД). - -Другими словами, если обновление данных выполняется на фоне долгой -операции чтения, то вместо повторного использования "старых" ненужных -страниц будут выделяться новые, так как "старые" страницы составляют -снимок БД, который еще используется долгой операцией чтения. - -В результате, при интенсивном изменении данных и достаточно длительной -операции чтения, в БД могут быть исчерпаны свободные страницы, что не -позволит создавать новые снимки/версии БД. Такая ситуация будет -сохраняться до завершения операции чтения, которая использует старый -снимок данных и препятствует повторному использованию страниц БД. - -Однако, на этом проблемы не заканчиваются. После описанной ситуации, все -дополнительные страницы, которые были выделены пока переработка старых -была невозможна, будут участвовать в цикле выделения/освобождения до -конца жизни экземпляра БД. В оригинальной _LMDB_ этот цикл использования -страниц работает по принципу [FIFO](https://ru.wikipedia.org/wiki/FIFO). -Поэтому увеличение количества циркулирующий страниц, с точки зрения -механизмов кэширования и/или обратной записи, выглядит как увеличение -рабочего набор данных. Проще говоря, однократное попадание в ситуацию -"уснувшего читателя" приводит к устойчивому эффекту вымывания I/O кэша -при всех последующих изменениях данных. - -Для устранения описанных проблемы в _libmdbx_ сделаны существенные -доработки, подробности ниже. Иллюстрации к проблеме "долгих чтений" -можно найти в [слайдах презентации](http://www.slideshare.net/leoyuriev/lmdb). - -Там же приведен пример количественной оценки прироста производительности -за счет эффективной работы [BBWC](https://en.wikipedia.org/wiki/BBWC) -при включении `LIFO RECLAIM` в _libmdbx_. - -### Сохранность данных в режиме асинхронной фиксации -При работе в режиме `WRITEMAP+MAPSYNC` запись измененных страниц -выполняется ядром ОС, что имеет ряд преимуществ. Так например, при крахе -приложения, ядро ОС сохранит все изменения. - -Однако, при аварийном отключении питания или сбое в ядре ОС, на диске -может быть сохранена только часть измененных страниц БД. При этом с -большой вероятностью может оказаться, что будут сохранены мета-страницы -со ссылками на страницы с новыми версиями данных, но не сами новые -данные. В этом случае БД будет безвозвратна разрушена, даже если до -аварии производилась полная синхронизация данных (посредством -`mdbx_env_sync()`). - -В _libmdbx_ эта проблема устранена путем полной переработки -пути записи данных: - -* В режиме `WRITEMAP+MAPSYNC` _libmdbx_ не обновляет - мета-страницы непосредственно, а поддерживает их теневые копии - с переносом изменений после фиксации данных. - -* При завершении транзакций, в зависимости от состояния - синхронности данных между диском и оперативной памятью, - _libmdbx_ помечает точки фиксации либо как сильные (strong), - либо как слабые (weak). Так например, в режиме - `WRITEMAP+MAPSYNC` завершаемые транзакции помечаются как - слабые, а при явной синхронизации данных - как сильные. - -* В _libmdbx_ поддерживается не две, а три отдельные мета-страницы. - Это позволяет выполнять фиксацию транзакций с формированием как - сильной, так и слабой точки фиксации, без потери двух предыдущих - точек фиксации (из которых одна может быть сильной, а вторая слабой). - В результате, _libmdbx_ позволяет в произвольном порядке чередовать - сильные и слабые точки фиксации без нарушения соответствующих - гарантий в случае неожиданной системной аварии во время фиксации. - -* При открытии БД выполняется автоматический откат к последней - сильной фиксации. Этим обеспечивается гарантия сохранности БД. - -Такая гарантия надежности не дается бесплатно. Для сохранности данных, -страницы, формирующие крайний снимок с сильной фиксацией, не должны -повторно использоваться (перезаписываться) до формирования следующей -сильной точки фиксации. Таким образом, крайняя точка фиксации создает -описанный выше эффект "долгого чтения". Разница же здесь в том, что при -исчерпании свободных страниц ситуация будет автоматически исправлена, -посредством записи изменений на диск и формирования новой сильной точки -фиксации. - -Таким образом, в режиме безопасной асинхронной фиксации _libmdbx_ будет -всегда использовать новые страницы до исчерпания места в БД или до -явного формирования сильной точки фиксации посредством -`mdbx_env_sync()`. При этом суммарный трафик записи на диск будет -примерно такой же, как если бы отдельно фиксировалась каждая транзакция. - -В текущей версии _libmdbx_ вам предоставляется выбор между безопасным -режимом (по умолчанию) асинхронной фиксации, и режимом `UTTERLY_NOSYNC` -когда при системной аварии есть шанс полного разрушения БД как в LMDB. - -В последующих версиях _libmdbx_ будут предусмотрены средства для -асинхронной записи данных на диск с автоматическим формированием сильных -точек фиксации. - --------------------------------------------------------------------------------- - -Использование -============= - -## Сборка - -Для сборки на всех платформах кроме Windows вам потребуются не-дремучие -версии: GNU Make, [bash](https://ru.wikipedia.org/wiki/Bash), компиляторы C и C++ совместимые с GCC или CLANG. - -Исторически сборка _libmdbx_ основывается на одном -[Makefile](https://ru.wikipedia.org/wiki/Makefile), что предполагает -разные рецепты сборки в зависимости от целевой платформы. В следующих -версиях планируется переход на использование -[CMake](https://ru.wikipedia.org/wiki/CMake), с отказом от поддержки -других инструментов. - -#### Выгрузка DSO/DLL и деструкторы Thread-Local-Storage объектов -При сборке _libmdbx_ в виде разделяемой библиотеки, либо использовании -статической _libmdbx_ в составе другой динамической библиотеке, -желательно убедиться, что ваша система обеспечивает корректность вызова -деструкторов Thread-Local-Storage объектов при выгрузке динамических -библиотек. - -Если это не так, то при выгрузке динамической библиотеки с _libmdbx_ -внутри возможна либо утечка ресурсов, либо падения из-за вызова -деструкторов из уже выгруженного DSO/DLL объекта. Проблема может -проявляться только в многопоточном приложении, которое производит -выгрузку разделяемых динамических библиотек с кодом _libmdbx_ внутри, -после использования _libmdbx_. Заведомо известно, что TLS-деструкторы -корректно обслуживаются: - -- На всех актуальных версиях Windows (Windows 7 и последующих). - -- На системах c функцией -[`__cxa_thread_atexit_impl()`](https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables) -в стандартной библиотеке C. В том числе на системах с GNU libc версии -2.18 и выше. - -- На системах с libpthread/ntpl из состава GNU libc с исправлением -ошибок [#21031](https://sourceware.org/bugzilla/show_bug.cgi?id=21031) и -[#21032](https://sourceware.org/bugzilla/show_bug.cgi?id=21032), либо -где нет подобных ошибок в реализации pthreads. - -### Linux и другие платформы с GNU Make -Для сборки библиотеки достаточно выполнить `make all` в директории с -исходными текстами, а для выполнения базовых тестов `make check`. - -Если установленный в система `make` не является GNU Make, то при попытке -сборки будет масса ошибок от make. В этом случае, возможно, вместо -`make` вам следует использовать `gmake`, либо даже `gnu-make` и т.п. - -### FreeBSD и родственные платформы -Как правило, на таких системах по-умолчанию используется Berkeley Make. -А GNU Make вызывается командой `gmake` или может отсутствовать. Кроме -этого может отсутствовать [`bash`](https://ru.wikipedia.org/wiki/Bash). - -Вам необходимо установить требуемые компоненты: GNU Make, bash, -компиляторы C и C++ совместимые с GCC или CLANG. После этого для сборки -библиотеки достаточно выполнить `gmake all` (или `make all`) в -директории с исходными текстами, а для выполнения базовых тестов `gmake -check` (или `make check`). - -### Windows -Для сборки libmdbx_ для ОС Windows рекомендуется использовать [Microsoft -Visual Studio](https://ru.wikipedia.org/wiki/Microsoft_Visual_Studio), -но не такие инструменты как MinGW, MSYS или Cygwin. Для этого в набор -исходных кодов _libmdbx_ входят соответствующие файлы проектов -совместимые с Visual Studio 2015, Windows SDK для Windows 8.1 и более -поздними версиями. Достаточно открыть `mdbx.sln` и выполнить сборку -библиотеки. - -Для сборки с более новыми версиями SDK или Visual Studio должно быть -достаточно выполнить "Retarget solution". Для сборки под старые версии -Windows (например Windows XP) или более старыми компиляторами вам -потребуется самостоятельно преобразовать или воссоздать файлы проектов. - -Сборка посредством MinGW, MSYS или Cygwin потенциально возможна. Однако, -эти сценарии не тестируются и вероятно потребуют от вас доработки -`Makefile`. Следует отметить, что в _libmdbx_ предприняты усилия для -устранения runtime зависимостей от CRT и других библиотек Visual Studio. -Для этого достаточно при сборке определить опцию `MDBX_AVOID_CRT`. - -Пример запуска базового сценария тестирования можно найти в -[CI-сценарии](appveyor.yml) для [AppVeyor](https://www.appveyor.com/). -Для выполнения [сценария длительного стохастического -тестирования](test/long_stochastic.sh) потребуется -[`bash`](https://ru.wikipedia.org/wiki/Bash), а само тестирование -рекомендуется выполнять с размещением тестовых данных на -[RAM-диске](https://ru.wikipedia.org/wiki/RAM-%D0%B4%D0%B8%D1%81%D0%BA). - -### MacOS X -Актуальные [нативные сборочные -инструменты](https://ru.wikipedia.org/wiki/Xcode) для MacOS X включают -GNU Make, CLANG и устаревшую версию bash. Поэтому для сборки библиотеки -достаточно выполнить `make all` в директории с исходными текстами, а для -выполнения базовых тестов `make check`. Если же что-то пойдет не так, то -рекомендуется установить [Homebrew](https://brew.sh/) и попробовать ещё -раз. - -Для выполнения [сценария длительного стохастического -тестирования](test/long_stochastic.sh) потребуется установка актуальной -(не устаревшей) версии [`bash`](https://ru.wikipedia.org/wiki/Bash). Для -этого рекомендуется установить [Homebrew](https://brew.sh/), а затем -выполнить `brew install bash`. - -## Привязки к другим языкам - - | Runtime | GitHub | Author | - | -------- | ------ | ------ | - | Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) | - | .NET | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) | - --------------------------------------------------------------------------------- - -Сравнение производительности -============================ - -Все представленные ниже данные получены многократным прогоном тестов на -ноутбуке Lenovo Carbon-2, i7-4600U 2.1 ГГц, 8 Гб ОЗУ, с SSD-диском -SAMSUNG MZNTD512HAGL-000L1 (DXT23L0Q) 512 Гб. - -Исходный код бенчмарка [_IOArena_](https://github.com/pmwkaa/ioarena) и -сценарии тестирования [доступны на -github](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015). - - -## Интегральная производительность - -Показана соотнесенная сумма ключевых показателей производительности в трёх -бенчмарках: - - - Чтение/Поиск на машине с 4-мя процессорами; - - - Транзакции с [CRUD](https://ru.wikipedia.org/wiki/CRUD)-операциями - (вставка, чтение, обновление, удаление) в режиме **синхронной фиксации** - данных (fdatasync при завершении каждой транзакции или аналог); - - - Транзакции с [CRUD](https://ru.wikipedia.org/wiki/CRUD)-операциями - (вставка, чтение, обновление, удаление) в режиме **отложенной фиксации** - данных (отложенная запись посредством файловой систем или аналог); - -*Бенчмарк в режиме асинхронной записи не включен по двум причинам:* - - 1. Такое сравнение не совсем правомочно, его следует делать с движками - ориентированными на хранение данных в памяти ([Tarantool](https://tarantool.io/), [Redis](https://redis.io/)). - - 2. Превосходство libmdbx становится еще более подавляющим, что мешает - восприятию информации. - - - --------------------------------------------------------------------------------- - -## Масштабируемость чтения - -Для каждого движка показана суммарная производительность при -одновременном выполнении запросов чтения/поиска в 1-2-4-8 потоков на -машине с 4-мя физическими процессорами. - - - --------------------------------------------------------------------------------- - -## Синхронная фиксация - - - Линейная шкала слева и темные прямоугольники соответствуют количеству - транзакций в секунду, усредненному за всё время теста. - - - Логарифмическая шкала справа и желтые интервальные отрезки - соответствуют времени выполнения транзакций. При этом каждый отрезок - показывает минимальное и максимальное время, затраченное на выполнение - транзакций, а крестиком отмечено среднеквадратичное значение. - -Выполняется **10.000 транзакций в режиме синхронной фиксации данных** на -диске. При этом требуется гарантия, что при аварийном выключении питания -(или другом подобном сбое) все данные будут консистентны и полностью -соответствовать последней завершенной транзакции. В _libmdbx_ в этом -режиме при фиксации каждой транзакции выполняется системный вызов -[fdatasync](https://linux.die.net/man/2/fdatasync). - -В каждой транзакции выполняется комбинированная CRUD-операция (две -вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует -на пустой базе, а при завершении, в результате выполняемых действий, в -базе насчитывается 10.000 небольших key-value записей. - - - --------------------------------------------------------------------------------- - -## Отложенная фиксация - - - Линейная шкала слева и темные прямоугольники соответствуют количеству - транзакций в секунду, усредненному за всё время теста. - - - Логарифмическая шкала справа и желтые интервальные отрезки - соответствуют времени выполнения транзакций. При этом каждый отрезок - показывает минимальное и максимальное время, затраченное на выполнение - транзакций, а крестиком отмечено среднеквадратичное значение. - -Выполняется **100.000 транзакций в режиме отложенной фиксации данных** -на диске. При этом требуется гарантия, что при аварийном выключении -питания (или другом подобном сбое) все данные будут консистентны на -момент завершения одной из транзакций, но допускается потеря изменений -из некоторого количества последних транзакций, что для многих движков -предполагает включение -[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) (write-ahead -logging) либо журнала транзакций, который в свою очередь опирается на -гарантию упорядоченности данных в журналируемой файловой системе. -_libmdbx_ при этом не ведет WAL, а передает весь контроль файловой -системе и ядру ОС. - -В каждой транзакции выполняется комбинированная CRUD-операция (две -вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует -на пустой базе, а при завершении, в результате выполняемых действий, в -базе насчитывается 100.000 небольших key-value записей. - - - --------------------------------------------------------------------------------- - -## Асинхронная фиксация - - - Линейная шкала слева и темные прямоугольники соответствуют количеству - транзакций в секунду, усредненному за всё время теста. - - - Логарифмическая шкала справа и желтые интервальные отрезки - соответствуют времени выполнения транзакций. При этом каждый отрезок - показывает минимальное и максимальное время, затраченное на выполнение - транзакций, а крестиком отмечено среднеквадратичное значение. - -Выполняется **1.000.000 транзакций в режиме асинхронной фиксации -данных** на диске. При этом требуется гарантия, что при аварийном -выключении питания (или другом подобном сбое) все данные будут -консистентны на момент завершения одной из транзакций, но допускается -потеря изменений из значительного количества последних транзакций. Во -всех движках при этом включался режим предполагающий минимальную -нагрузку на диск по записи, и соответственно минимальную гарантию -сохранности данных. В _libmdbx_ при этом используется режим асинхронной -записи измененных страниц на диск посредством ядра ОС и системного -вызова [msync(MS_ASYNC)](https://linux.die.net/man/2/msync). - -В каждой транзакции выполняется комбинированная CRUD-операция (две -вставки, одно чтение, одно обновление, одно удаление). Бенчмарк стартует -на пустой базе, а при завершении, в результате выполняемых действий, в -базе насчитывается 10.000 небольших key-value записей. - - - --------------------------------------------------------------------------------- - -## Потребление ресурсов - -Показана соотнесенная сумма использованных ресурсов в ходе бенчмарка в -режиме отложенной фиксации: - - - суммарное количество операций ввода-вывода (IOPS), как записи, так и - чтения. - - - суммарное затраченное время процессора, как в режиме пользовательских - процессов, так и в режиме ядра ОС. - - - использованное место на диске при завершении теста, после закрытия БД - из тестирующего процесса, но без ожидания всех внутренних операций - обслуживания (компактификации LSM и т.п.). - -Движок _ForestDB_ был исключен при оформлении результатов, так как -относительно конкурентов многократно превысил потребление каждого из -ресурсов (потратил процессорное время на генерацию IOPS для заполнения -диска), что не позволяло наглядно сравнить показатели остальных движков -на одной диаграмме. - -Все данные собирались посредством системного вызова -[getrusage()](http://man7.org/linux/man-pages/man2/getrusage.2.html) и -сканированием директорий с данными. - - - --------------------------------------------------------------------------------- - -``` -$ objdump -f -h -j .text libmdbx.so - -libmdbx.so: file format elf64-x86-64 -architecture: i386:x86-64, flags 0x00000150: -HAS_SYMS, DYNAMIC, D_PAGED -start address 0x0000000000003870 - -Sections: -Idx Name Size VMA LMA File off Algn - 11 .text 000173d4 0000000000003870 0000000000003870 00003870 2**4 - CONTENTS, ALLOC, LOAD, READONLY, CODE - -``` |
