Я бы не смешивал key-value и вторичные индексы. Понятно что через первое можно сделать второе, но именно поэтому это разные вещи.
Следующий важный момент это — вопрос встраиваемости, включая неизбежный компромисс между легковесностью движка (простой встраивания) и предлагаемыми возможностями. Например: хорошая производительность во write-сценариях потребует WAL и запуск rollback/redo при открытии БД, LSM потребует фоновых потоков для выполнения слияния, а репликация потребует event loop + поддержку сети + массу настроек и средств диагностики.
Если к обозначенным критериям добавить легкость встраивания, то начать можно с SQLite и libfpta, затем Firebird Embedded и MySQL Embedded. Уверен что есть что-то еще подходящее, но нужно смотреть по остальным критериями, начиная с лицензии (пошла мода на двойное лицензирования с бесплатностью для open-source проектов, т.е. все меняется и нужно смотреть по-факту). Другими словами, при встраивании full-featured движка хранения можно прийти к пропорции "один конь / один рябчик".
UPDATE: Еще стоит подумать над "встраиванием" тарантула.
Безотносительно к самой статье, хочу раскритиковать как Berkeley DB, так и подход работы с БД как с stl-контейнером.
Berkeley DB (далее BDB) — очень старый продукт в области, которая активно развивалась в последнее время, перенесла несколько революций и родила массу альтернатив с учетом набитых шишек. Лучшее враг хорошего и сейчас при (пожалуй) любом наборе критериев можно выбрать альтернативу превосходящую BDB. К этому добавляется ряд проблем/недочетов BDB: плохая производительность и/или deadlock-и при конкурентной обработки транзакций, полу-ручное восстановление БД после падений, смена лицензии на AGPL (неприемлема для некоторых проектов).
BDB является встраиваемым движком хранения, который предлагает больше чем key-value. Но в результате получился комбайн, у которого что-то не так с каждой из features. Поэтому в последние годы (несмотря на усилия и деньги Oracle) разработчики предпочитают мигрировать с BDB, когда им нужна хотя-бы одна features (производительность, надежность, масштабируемость, репликация, шифрование и т.д.) на актуальном для индустрии уровне. Сомнительным, но всё-же аргументом, стало то, что при всей "чудесности" BDB (исходя из проспектов Oracle) удаленный из MySQL 5.1 бэкенд хранение так и не был возвращен (работы и багов много, а толку нет).
Поэтому рекомендую читателям десять раз подумать и посмотреть на альтернативы, прежде чем запрягать этого "старого мерина" в новые проекты.
Использование БД как stl-контейнера может порождать массу проблем, так как это разные абстракции. Основное отличие в том, что stl-контейнеры и их интерфейс предназначены для использования внутри одного процесса при монопольном доступе из одного потока выполнения.
В том время как у БД другое время жизни, (как правило) есть транзакции и доступ из нескольких процессов.
Тут можно резонно возразить, что достаточно вовремя открывать/закрывать БД и правильно расставить условные begin_transacton() и end_transaction(bool abort). Во многих случаях, особенно простых так и будет. Однако, дьявол в деталях:
У операций с БД другая стоимость, поэтому удобно применив stl-алгоритмы к stl-контейнеру вы можете получить неприемлемую производительность или огромное потребление ресурсов.
Вам могут потребоваться вложенные транзакции, которых нет у большинства встраиваемых storage engines и высокопроизводительных БД.
В некоторых БД вы можете обнаружить, что "запись" живет отдельно от "чтения" и после обновления виртуального stl-контейнера, чтение из него не видит изменений до коммита транзакции и/или сразу после.
В некоторых БД повторное чтение может дать другой результат, что позволит сделать трудно-обнаруживаемые ошибки при использовании stl-подхода.
В БД эксплуатирующих MVCC (коих большинство) долгое удержание транзакции на фоне изменений данных (скорее всего) приведет к накоплению мусора и/или деградации производительности. При этом вы можете обнаружить, что рестарт транзакции (переход от старого MVCC-снимка к новому) может потребовать "перечитать всё" и непонятно когда это делать.
Поэтому не советую работать с БД как с stl-контейнером, кроме совсем тривиальных и прозрачных случаев.
Прогрессивная общественность (без кавычек) — это Сноуден и Ассанж, оба объявлены преступниками от лица американской демократии дерьмократии с ее стабильными правовыми институтами.
А "прогрессивная общественность" (в кавычках) наслаждается божьей росой из под своих любимых соросов и кидается на всех кто с ними плохо делится или пытается выгнать ;)
The identification MAY be based on either the
key identifier (the subject key identifier in the issuer's
certificate) or the issuer name and serial number.
The keyIdentifier field of the authorityKeyIdentifier extension MUST
be included in all certificates generated by conforming CAs to
facilitate certification path construction.
Но меня несколько забавляет другой набор фактов:
Вот правительство Казакстана предложило (предполагаю что в соответствии со своими законами) поставить свой сертификат. Решение сомнительное по многим критериям, но озвучено явно и открыто. "Прогрессивная общественность" возмутилась и даже назвала это "атакой".
Примерно та же общественность: Не хотела замечать публикации о backdoor-е в генераторе NIST примерно до публикаций Сноудена и мягко замяла скандал по самому факту скрытой преднамеренной установки backdoor-а и прочей информации о преднамеренном внесении ошибок во всяческие openssl-и.
Более 10 лет не замечала "Патриотического акта" и сейчас примерно не замечает "Investigatory Powers Act". Упрямо не замечает, что всяческие гуглы и фейсбуки читают и перепродают все их данные, а также обязаны выдать всю инфу без какой-либо реальной защиты для не-граждан США. Ну и т.д. и т.п.
Я, конечно, не хочу сказать, что всё это хорошо (хотя, может и неизбежно). Но смешно смотреть на вой и битье казахов за их открытые действия. При том, что с другой стороны "прогрессивной общественности" давно вставили по самые гланды, и дрючат в полную силу уже несколько десятилетий ;)
Ну конечнно не по одной записи. Там есть ограничения, кажется до 1024 за раз. Мы пишем по 500-600 записей на транзакцию.
Никакого ограничения в 1024 операции в транзакции нет. Есть ограничения на "размер транзакции" по кол-ву грязных страниц, в MDBX это 4194302. Пока производимые изменения приводят к изменению/добавлению меньшего кол-ва страниц всё будет работать. При достижении лимита будет ошибка MDBX_TXN_FULL (Кстати, я ошибся написав что заполнение всей вашей БД поместится в одну транзакцию — потребуется порядка 30-50).
Так или иначе вставка по 500-600 записей — это очень мало. Тут нужно ворочить миллионами.
В strace видим pwrite вызовы с 4К кусочками. И их очень много.
Потому-что БД состоит из страниц, размер которых по-умолчанию равен 4096.
с WRITE_MAP пробовали. Получаем sparse file, который, хотя и занимает реально меньше места, чем показывает ls -la, всё же дико всех пугает, и всё же, он в итоге физически получается в разы больше, чем если создавать без WRITE_MAP.
LMDB не создает sparce-файлов и если это делает ядро ОС, то могут быть еще какие-то странности. Размер создаваемого файла задается через API (по умолчанию кажется 2 Mb), а затем он может увеличиваться пока есть место на диске. Но LMDB не умеет уменьшать файл и не выполняется компактификацию (только при копировании БД). Поэтому я рекомендую всё-таки перейти на MDBX и использовать mdbx_env_set_geometry().
Похоже там какие-то утечки или хуже дела с фрагментацией.
В LMDB были подобные ошибки. Текущую ситуацию не знаю, но крайний коммит связан с подобными ошибками, а проблема перебалансировки похоже так и осталась… В MDBX всё подобное поправлено и перепроверено, в том числе есть mdbx_chk и развитый тест, включая стохастический.
И даже без WRITE_MAP приходится потом перезаливать файл еще раз через внешний текстовый дамп. Файл становится где-то на 30-40% меньше.
Видимо вы не понимаете как работает B+Tree. При случайных вставках (т.е. несортированных данных) заполнение страниц может находиться в пределах от 25% до 100%. При вставке сортированных в порядке ключей с APPEND-флажком получаться ровно заполненные страницы.
Создавая тектовый дамп вы получаете отсортированные данные, а заливая базу из дампа получаете ровно заполненные страницы. При этом вы сначала заставляете LMDB выполнить сортировку вставками (с эффективностью O(N*2)), вместо того чтобы использовать сортировку слиянием (с эффективностью O(NLog(N)), как было предложено. Вы понимаете что на вашем объеме данных это примерно в миллиард раз медленнее?
SYNC — мы не видим никаких SYNC в strace.
На не-дремучих ядрах linux должен быть fdatasync, а не fsync (и ни в коем случае не sync).
RAM — 128GB, сравнимо с файлом. Но RAM поже используется никак. Совсем никак. Всё-же O_DIRECT.
O_DIRECT используется для записи мета-страниц (одна запись на транзакцию), а также включается при копировании БД без компактификации.
Поэтому сделайте как я написал (используйте MDBX вместо LMDB, используйте WRITEMAP + UTTERLY_NOSYNC при вливании данных).
В отличии от LMDB, в MDBX это работает корректно: движок не даст одновременно открыть БД в несовместимых режимах, движок поддерживает три мета-старицы вместо двух и поддерживает разные режимы фиксации (steady, weak, legacy).
Отсортировать полностью не получается — миллиард записей совсем не хочется вычитывать в память. А те куски, которые вычитываем за раз — конечно сортируем в памяти перед вставкой. Но это слабо помогает.
Частичная сортировка даст очень мало эффекта, точнее даст для первого куска, но не для следующих.
Загружать все данные в память не нужно. Вам нужен алгоритм сортировки слиянием, который прекрасно умеет утилита sort. При этом затраты на такую сортировку много-много-кратно ниже затрат на сортировку вставками внутри B+Tree и кратно ниже стандартных эвристик LSM.
Для скорости используйте --buffer-size=XYZ.
Похоже это тот случай, когда выгоднее сначала слить в LSM, а уже потом думать о чем-то другом.
Я пока не видел LSM работающий быстрее sort. Теоретически RocksDB может отработать быстрее на сильно сжимаемых данных, но не видел и думаю какой-нибудь lz4 sort его обгонит.
А можно ли как-то отключить O_DIRECT? Он точно там нужен даже без SYNC? Если устойчивость к крашам не нужна (в данном конкретном случае — при начальной заливке).
Я уже все вам написал и более-менее объяснил. Просто следуйте советам или вникайте глубже.
Во-первых, если каждую запись коммитеть в отдельной транзакции, то конечно будет жутко медленно. Заливать данные нужно с разумным батчингом, где-то по 10К-1000К записей за одну транзакцию. При этом лучше открыть БД в режиме MDBX_WRITEMAP|MDBX_UTTERLY_NOSYNC.
UPDATE: Наполение БД в 256 Гб с размером страницы в 4К должно поместиться в одну транзакцию, см MDBX_DPL_TXNFULL.
Во-вторых, если данных существенно больше чем размер ОЗУ, то вливая не-сортированные данные вы неизбежно и безвыходно заставите движок выполнять сортировку вставками со сложностью O(N**2). Этим породите множественные случайные изменения в B+Tree, с многократным перекладыванием всей БД с диска в память и обратно.
Поэтому, при большом кол-ве записей, в "миллион раз" выгоднее предварительно отсортировать данные сортировкой слиянием (сложность O(N*Log(N)) в порядке возрастания ключей. Утилита sort реализует алгоритм сортировки сама. А затем влить отсортированные данные в MDBX (с ключом MDBX_APPED будет еще быстрее). Такая заливка займет время сравнимое с копированием данных на используемый диск.
Такой трюк оправдан для всех БД, но движки на основе LSM более толерантны к массивной загрузке без сортировки — фактически БД будет выполнять сортировку слиянием внутри себя, т.е. какой-нибудь RocksDB будет еще достаточно долго жужжать диском после окончания загрузки (и все это время достаточно сильно тормозить со случайным чтением/обновлением).
Некоторые результаты для меня выглядят странно и вызывают серьезные сомнения. А отдельные цифры наводят на мысль о полной компрометации результатов.
Как разработчик libmdbx я хорошо представляю в каких сценариях и по каким причинам RocksDB будет "уделывать" MDBX / LMDB.
Собственно, это те сценарии где хорошо работает WAL и LSM:
много мелких апдеййтов, которые хорошо жмутся в WAL-страницы.
много коротко-живущих данных (перезаписываются, удаляются или умирают по TTL), тогда движку не приходиться искать вглубь LSM-дерева.
данные хорошо сживаются, тогда за счет сжатия в RocksDB больше данных поместиться в кэш страниц ядра ОС.
Однако, это не совпадает с наблюдаемым, плюс есть масса нестыковок и странностей:
Субъективно: Видно неуверенное (мягко говоря) владение настройками движков и понимание того, как именно и на что они влияют. Проще говоря, исполнители просто запускали ioarena "из коробки" не вникая в трансляцию опций на уровень движок хранения. Следовательно, результаты во многом зависят от удачности дефолтовых установок для сценария тестирования.
Из фразы "с RocksDB что-то случается после 800 млн ключей. К сожалению, не были выяснены причины происходящего." следует, что авторы не поняли как работает LSM, не догадались смотреть нагрузки на диски и не научились мониторить процессы внутри RocksDB. Отсюда рождается подозрение, что "программное регулирования" объема ОЗУ не включало страничный кэш файловой системы и поэтому RockDB работал волшебно быстро пока LSM-дерево помещалось в файловый кэш ОС. Это также косвенно подтверждается очень ровным графиком latency на первом миллиарде записей и фразой "А вот RocksDB в итоге спустился ниже 100k IOPS" при заполнении БД до 17 млрд записей, т.е. когда БД действительно перестала помещаться в ОЗУ.
В тексте есть фраза "В этом случае MDBX с отрывом уходит вперёд в тесте на чтение", но нет графиков или цифр, которые это демонстрируют. С ними (наверное) были-бы чуть понятнее причины остальных странностей и нестыковок.
При большом размере БД (сильно больше ОЗУ) MDBX ожидаемо тормозит, так как случайное чтение/обновление данных с большой вероятностью приводит к подкачке с диска. Но и RocksDB при этом также будет сильно проседать, за исключениям ситуаций:
в данных сильно большой статистический сдвиг: читаются/пишется подмножество данных, либо данные очень хорошо сживаются (повторяются).
записанные на диск данные кешируются ядром ОС или гипервизором.
В результатах подобного проседания не видно, хотя есть мега-странности с latency (см далее).
Если смотреть на max-latency для MDBX, то значения практически не меняется с самого начала до конца теста, т.е. время выполнения запроса к БД примерно не меняется, даже когда БД перестает помещаться в память и случайное чтение или запись ведет к подкачке с диска. Очевидно, что такого не может быть, т.е. налицо какая-то ошибка.
Если посмотреть на сводные диаграммы latency ближе к концу первой части статьи, то результаты вызывают полное непонимание:
Для RockDB максимальное время выполнения запроса порядка 0,5 секунд при чтении и около 3 секунд при смешанной нагрузке.
Предположим, что получив неудачный запрос RockDB может глубоко и неудачно (из-за фильтра Блума) искать в LSM-дереве, но 3 секунды на NVMe-диске — это невероятно много! Особенно с с учетом того, что слияние LSM делается фоновым тредом и механизм многократно "допиливали", в том числе для стабилизации latency.
Для MDBX максимум порядка 100 секунд (10**5 миллисекунд) при чтении на NVE-диске — это явная чушь и/или ошибка.
MDBX не делает ничего лишнего, просто поиск по B+Tree. Поэтому, в худшем случае, MDBX прочитает кол-во страниц на 2 больше высоты B+Tree дерева. При не-длинных ключах (как в рассматриваемом случае), на одну branch-страницу поместиться 50-100-200 ключей (размер страницы 4К или 8К, примерно делим на размер ключа). Т.е. будет максимум 10 чтений с NVMe (модель указана), который имеет производительность более 500K IOPS при случайном чтении. Поэтому мы должны увидеть max-latency близкую к 10 / 500K = 0,2 миллисекунды. Откуда взялось 100 секунд?
Даже в начале прогонов, когда размер БД еще небольшой и полностью помещается в память, производительность MDBX почему-то меньше чем на моём ноуте с i7-4600U @ 2.1 GHz. Для сравнения см. мои скрипты и результаты тестирования производительности.
Поэтому, в сухом остатке — показанным цифрам, графика и выводам нельзя верить.
На всякий — аналогичный комментарий я добавил ко второй части статьи.
Что-то я не заметил вторую часть статьи вовремя. Только сейчас наткнулся посредством поиска.
Кроме этого, еще в 2017 году я обещал выдать критику — думаю лучше поздно чем никогда.
Некоторые результаты для меня выглядят странно и вызывают серьезные сомнения. А отдельные цифры наводят на мысль о полной компрометации результатов.
Как разработчик libmdbx я хорошо представляю в каких сценариях и по каким причинам RocksDB будет "уделывать" MDBX/LMDB.
Собственно, это те сценарии где хорошо работает WAL и LSM:
много мелких апдеййтов, которые хорошо жмутся в WAL-страницы.
много коротко-живущих данных (перезаписываются, удаляются или умирают по TTL), тогда движку не приходиться искать вглубь LSM-дерева.
данные хорошо сживаются, тогда за счет сжатия в RocksDB больше данных поместиться в кэш страниц ядра ОС.
Однако, это не совпадает с наблюдаемым, плюс есть масса нестыковок и странностей:
Субъективно: Видно неуверенное (мягко говоря) владение настройками движков и понимание того, как именно и на что они влияют. Проще говоря, исполнители просто запускали ioarena "из коробки" не вникая в трансляцию опций на уровень движок хранения. Следовательно, результаты во многом зависят от удачности дефолтовых установок для сценария тестирования.
Из фразы "с RocksDB что-то случается после 800 млн ключей. К сожалению, не были выяснены причины происходящего." следует, что авторы не поняли как работает LSM, не догадались смотреть нагрузки на диски и не научились мониторить процессы внутри RocksDB. Отсюда рождается подозрение, что "программное регулирования" объема ОЗУ не включало страничный кэш файловой системы и поэтому RockDB работал волшебно быстро пока LSM-дерево помещалось в файловый кэш ОС. Это также косвенно подтверждается очень ровным графиком latency на первом миллиарде записей и фразой "А вот RocksDB в итоге спустился ниже 100k IOPS" при заполнении БД до 17 млрд записей, т.е. когда БД действительно перестала помещаться в ОЗУ.
В тексте есть фраза "В этом случае MDBX с отрывом уходит вперёд в тесте на чтение", но нет графиков или цифр, которые это демонстрируют. С ними (наверное) были-бы чуть понятнее причины остальных странностей и нестыковок.
При большом размере БД (сильно больше ОЗУ) MDBX ожидаемо тормозит, так как случайное чтение/обновление данных с большой вероятностью приводит к подкачке с диска. Но и RocksDB при этом также будет сильно проседать, за исключениям ситуаций:
в данных сильно большой статистический сдвиг: читаются/пишется подмножество данных, либо данные очень хорошо сживаются (повторяются).
записанные на диск данные кешируются ядром ОС или гипервизором.
В результатах подобного проседания не видно, хотя есть мега-странности с latency (см далее).
Если смотреть на max-latency для MDBX, то значения практически не меняется с самого начала до конца теста, т.е. время выполнения запроса к БД примерно не меняется, даже когда БД перестает помещаться в память и случайное чтение или запись ведет к подкачке с диска. Очевидно, что такого не может быть, т.е. налицо какая-то ошибка.
Если посмотреть на сводные диаграммы latency ближе к концу первой части статьи, то результаты вызывают полное непонимание:
Для RockDB максимальное время выполнения запроса порядка 0,5 секунд при чтении и около 3 секунд при смешанной нагрузке.
Предположим, что получив неудачный запрос RockDB может глубоко и неудачно (из-за фильтра Блума) искать в LSM-дереве, но 3 секунды на NVMe-диске — это невероятно много! Особенно с с учетом того, что слияние LSM делается фоновым тредом и механизм многократно "допиливали", в том числе для стабилизации latency.
Для MDBX максимум порядка 100 секунд (10**5 миллисекунд) при чтении на NVE-диске — это явная чушь и/или ошибка.
MDBX не делает ничего лишнего, просто поиск по B+Tree. Поэтому, в худшем случае, MDBX прочитает кол-во страниц на 2 больше высоты B+Tree дерева. При не-длинных ключах (как в рассматриваемом случае), на одну branch-страницу поместиться 50-100-200 ключей (размер страницы 4К или 8К, примерно делим на размер ключа). Т.е. будет максимум 10 чтений с NVMe (модель указана), который имеет производительность более 500K IOPS при случайном чтении. Поэтому мы должны увидеть max-latency близкую к 10 / 500K = 0,2 миллисекунды. Откуда взялось 100 секунд?
Даже в начале прогонов, когда размер БД еще небольшой и полностью помещается в память, производительность MDBX почему-то меньше чем на моём ноуте с i7-4600U @ 2.1 GHz. Для сравнения см. мои скрипты и результаты тестирования производительности.
Поэтому, в сухом остатке — показанным цифрам, графика и выводам нельзя верить.
Roslyn, платформа компилятора .NET, помогает обнаруживать ошибки еще до запуска кода.
А можете привести пример с иным поведением, т.е. когда компилятор обнаруживает ошибки после запуска кода?
Могу предположить, что именно такой "компилятор" используется при создании Windows и MS Office, но хотелось-бы больше подробностей об этом know how от Microsoft.
Статья не идеальна, но ваш комментарий не более компетентен.
Следует различать физический уровень LoRa (модуляцию и т.п), от LoRaWAN (управление сетью включая выдачу адресов).
Статья не идеальна, но ваш комментарий не более компетентен.
Следует различать физический уровень LoRa (модуляцию и т.п), от LoRaWAN (управление сетью включая выдачу адресов).
Я бы не смешивал key-value и вторичные индексы. Понятно что через первое можно сделать второе, но именно поэтому это разные вещи.
Следующий важный момент это — вопрос встраиваемости, включая неизбежный компромисс между легковесностью движка (простой встраивания) и предлагаемыми возможностями. Например: хорошая производительность во write-сценариях потребует WAL и запуск rollback/redo при открытии БД, LSM потребует фоновых потоков для выполнения слияния, а репликация потребует event loop + поддержку сети + массу настроек и средств диагностики.
Если к обозначенным критериям добавить легкость встраивания, то начать можно с SQLite и libfpta, затем Firebird Embedded и MySQL Embedded. Уверен что есть что-то еще подходящее, но нужно смотреть по остальным критериями, начиная с лицензии (пошла мода на двойное лицензирования с бесплатностью для open-source проектов, т.е. все меняется и нужно смотреть по-факту). Другими словами, при встраивании full-featured движка хранения можно прийти к пропорции "один конь / один рябчик".
UPDATE: Еще стоит подумать над "встраиванием" тарантула.
Пардон, промазал тредом.
Безотносительно к самой статье, хочу раскритиковать как Berkeley DB, так и подход работы с БД как с stl-контейнером.
Berkeley DB (далее BDB) — очень старый продукт в области, которая активно развивалась в последнее время, перенесла несколько революций и родила массу альтернатив с учетом набитых шишек. Лучшее враг хорошего и сейчас при (пожалуй) любом наборе критериев можно выбрать альтернативу превосходящую BDB. К этому добавляется ряд проблем/недочетов BDB: плохая производительность и/или deadlock-и при конкурентной обработки транзакций, полу-ручное восстановление БД после падений, смена лицензии на AGPL (неприемлема для некоторых проектов).
BDB является встраиваемым движком хранения, который предлагает больше чем key-value. Но в результате получился комбайн, у которого что-то не так с каждой из features. Поэтому в последние годы (несмотря на усилия и деньги Oracle) разработчики предпочитают мигрировать с BDB, когда им нужна хотя-бы одна features (производительность, надежность, масштабируемость, репликация, шифрование и т.д.) на актуальном для индустрии уровне. Сомнительным, но всё-же аргументом, стало то, что при всей "чудесности" BDB (исходя из проспектов Oracle) удаленный из MySQL 5.1 бэкенд хранение так и не был возвращен (работы и багов много, а толку нет).
Поэтому рекомендую читателям десять раз подумать и посмотреть на альтернативы, прежде чем запрягать этого "старого мерина" в новые проекты.
Использование БД как stl-контейнера может порождать массу проблем, так как это разные абстракции. Основное отличие в том, что stl-контейнеры и их интерфейс предназначены для использования внутри одного процесса при монопольном доступе из одного потока выполнения.
В том время как у БД другое время жизни, (как правило) есть транзакции и доступ из нескольких процессов.
Тут можно резонно возразить, что достаточно вовремя открывать/закрывать БД и правильно расставить условные
begin_transacton()
иend_transaction(bool abort)
. Во многих случаях, особенно простых так и будет. Однако, дьявол в деталях:Поэтому не советую работать с БД как с stl-контейнером, кроме совсем тривиальных и прозрачных случаев.
Вы видимо сошли с ума.
Верна тут только ваша глупость.
Прогрессивная общественность (без кавычек) — это Сноуден и Ассанж, оба объявлены преступниками от лица американской
демократиидерьмократии с ее стабильными правовыми институтами.А "прогрессивная общественность" (в кавычках) наслаждается божьей росой из под своих любимых соросов и кидается на всех кто с ними плохо делится или пытается выгнать ;)
Что-то вы сегодня не в ударе.
1024 только у годичного сертификата для CN=*.facebook.com.
У тех-годичного выше уже 2048, а у 30-летнего CA 4096.
Может лучше RTFM?
Не вижу связи с "отечественной криптографией".
Но меня несколько забавляет другой набор фактов:
Вот правительство Казакстана предложило (предполагаю что в соответствии со своими законами) поставить свой сертификат. Решение сомнительное по многим критериям, но озвучено явно и открыто. "Прогрессивная общественность" возмутилась и даже назвала это "атакой".
Примерно та же общественность: Не хотела замечать публикации о backdoor-е в генераторе NIST примерно до публикаций Сноудена и мягко замяла скандал по самому факту скрытой преднамеренной установки backdoor-а и прочей информации о преднамеренном внесении ошибок во всяческие openssl-и.
Более 10 лет не замечала "Патриотического акта" и сейчас примерно не замечает "Investigatory Powers Act". Упрямо не замечает, что всяческие гуглы и фейсбуки читают и перепродают все их данные, а также обязаны выдать всю инфу без какой-либо реальной защиты для не-граждан США. Ну и т.д. и т.п.
Я, конечно, не хочу сказать, что всё это хорошо (хотя, может и неизбежно). Но смешно смотреть на вой и битье казахов за их открытые действия. При том, что с другой стороны "прогрессивной общественности" давно вставили по самые гланды, и дрючат в полную силу уже несколько десятилетий ;)
Никакого ограничения в 1024 операции в транзакции нет. Есть ограничения на "размер транзакции" по кол-ву грязных страниц, в MDBX это 4194302. Пока производимые изменения приводят к изменению/добавлению меньшего кол-ва страниц всё будет работать. При достижении лимита будет ошибка MDBX_TXN_FULL (Кстати, я ошибся написав что заполнение всей вашей БД поместится в одну транзакцию — потребуется порядка 30-50).
Так или иначе вставка по 500-600 записей — это очень мало. Тут нужно ворочить миллионами.
Потому-что БД состоит из страниц, размер которых по-умолчанию равен 4096.
LMDB не создает sparce-файлов и если это делает ядро ОС, то могут быть еще какие-то странности. Размер создаваемого файла задается через API (по умолчанию кажется 2 Mb), а затем он может увеличиваться пока есть место на диске. Но LMDB не умеет уменьшать файл и не выполняется компактификацию (только при копировании БД). Поэтому я рекомендую всё-таки перейти на MDBX и использовать
mdbx_env_set_geometry()
.В LMDB были подобные ошибки. Текущую ситуацию не знаю, но крайний коммит связан с подобными ошибками, а проблема перебалансировки похоже так и осталась… В MDBX всё подобное поправлено и перепроверено, в том числе есть mdbx_chk и развитый тест, включая стохастический.
Видимо вы не понимаете как работает B+Tree. При случайных вставках (т.е. несортированных данных) заполнение страниц может находиться в пределах от 25% до 100%. При вставке сортированных в порядке ключей с APPEND-флажком получаться ровно заполненные страницы.
Создавая тектовый дамп вы получаете отсортированные данные, а заливая базу из дампа получаете ровно заполненные страницы. При этом вы сначала заставляете LMDB выполнить сортировку вставками (с эффективностью O(N*2)), вместо того чтобы использовать сортировку слиянием (с эффективностью O(NLog(N)), как было предложено. Вы понимаете что на вашем объеме данных это примерно в миллиард раз медленнее?
На не-дремучих ядрах linux должен быть fdatasync, а не fsync (и ни в коем случае не sync).
O_DIRECT используется для записи мета-страниц (одна запись на транзакцию), а также включается при копировании БД без компактификации.
Поэтому сделайте как я написал (используйте MDBX вместо LMDB, используйте WRITEMAP + UTTERLY_NOSYNC при вливании данных).
В отличии от LMDB, в MDBX это работает корректно: движок не даст одновременно открыть БД в несовместимых режимах, движок поддерживает три мета-старицы вместо двух и поддерживает разные режимы фиксации (steady, weak, legacy).
Частичная сортировка даст очень мало эффекта, точнее даст для первого куска, но не для следующих.
Загружать все данные в память не нужно. Вам нужен алгоритм сортировки слиянием, который прекрасно умеет утилита sort. При этом затраты на такую сортировку много-много-кратно ниже затрат на сортировку вставками внутри B+Tree и кратно ниже стандартных эвристик LSM.
Для скорости используйте
--buffer-size=XYZ
.Я пока не видел LSM работающий быстрее sort. Теоретически RocksDB может отработать быстрее на сильно сжимаемых данных, но не видел и думаю какой-нибудь lz4 sort его обгонит.
Я уже все вам написал и более-менее объяснил. Просто следуйте советам или вникайте глубже.
Во-первых, если каждую запись коммитеть в отдельной транзакции, то конечно будет жутко медленно. Заливать данные нужно с разумным батчингом, где-то по 10К-1000К записей за одну транзакцию. При этом лучше открыть БД в режиме
MDBX_WRITEMAP
|
MDBX_UTTERLY_NOSYNC
.UPDATE: Наполение БД в 256 Гб с размером страницы в 4К должно поместиться в одну транзакцию, см
MDBX_DPL_TXNFULL
.Во-вторых, если данных существенно больше чем размер ОЗУ, то вливая не-сортированные данные вы неизбежно и безвыходно заставите движок выполнять сортировку вставками со сложностью O(N**2). Этим породите множественные случайные изменения в B+Tree, с многократным перекладыванием всей БД с диска в память и обратно.
Поэтому, при большом кол-ве записей, в "миллион раз" выгоднее предварительно отсортировать данные сортировкой слиянием (сложность O(N*Log(N)) в порядке возрастания ключей. Утилита sort реализует алгоритм сортировки сама. А затем влить отсортированные данные в MDBX (с ключом
MDBX_APPED
будет еще быстрее). Такая заливка займет время сравнимое с копированием данных на используемый диск.Такой трюк оправдан для всех БД, но движки на основе LSM более толерантны к массивной загрузке без сортировки — фактически БД будет выполнять сортировку слиянием внутри себя, т.е. какой-нибудь RocksDB будет еще достаточно долго жужжать диском после окончания загрузки (и все это время достаточно сильно тормозить со случайным чтением/обновлением).
Еще в 2017 году я обещал выдать критику — думаю лучше поздно чем никогда.
FYI: olegbunin, kaamos, kostja, leventov.
Некоторые результаты для меня выглядят странно и вызывают серьезные сомнения.
А отдельные цифры наводят на мысль о полной компрометации результатов.
Как разработчик libmdbx я хорошо представляю в каких сценариях и по каким причинам RocksDB будет "уделывать" MDBX / LMDB.
Собственно, это те сценарии где хорошо работает WAL и LSM:
Однако, это не совпадает с наблюдаемым, плюс есть масса нестыковок и странностей:
В результатах подобного проседания не видно, хотя есть мега-странности с latency (см далее).
Предположим, что получив неудачный запрос RockDB может глубоко и неудачно (из-за фильтра Блума) искать в LSM-дереве, но 3 секунды на NVMe-диске — это невероятно много! Особенно с с учетом того, что слияние LSM делается фоновым тредом и механизм многократно "допиливали", в том числе для стабилизации latency.
MDBX не делает ничего лишнего, просто поиск по B+Tree. Поэтому, в худшем случае, MDBX прочитает кол-во страниц на 2 больше высоты B+Tree дерева. При не-длинных ключах (как в рассматриваемом случае), на одну branch-страницу поместиться 50-100-200 ключей (размер страницы 4К или 8К, примерно делим на размер ключа). Т.е. будет максимум 10 чтений с NVMe (модель указана), который имеет производительность более 500K IOPS при случайном чтении. Поэтому мы должны увидеть max-latency близкую к 10 / 500K = 0,2 миллисекунды. Откуда взялось 100 секунд?
Поэтому, в сухом остатке — показанным цифрам, графика и выводам нельзя верить.
На всякий — аналогичный комментарий я добавил ко второй части статьи.
Что-то я не заметил вторую часть статьи вовремя. Только сейчас наткнулся посредством поиска.
Кроме этого, еще в 2017 году я обещал выдать критику — думаю лучше поздно чем никогда.
Некоторые результаты для меня выглядят странно и вызывают серьезные сомнения.
А отдельные цифры наводят на мысль о полной компрометации результатов.
Как разработчик libmdbx я хорошо представляю в каких сценариях и по каким причинам RocksDB будет "уделывать" MDBX/LMDB.
Собственно, это те сценарии где хорошо работает WAL и LSM:
Однако, это не совпадает с наблюдаемым, плюс есть масса нестыковок и странностей:
В результатах подобного проседания не видно, хотя есть мега-странности с latency (см далее).
Предположим, что получив неудачный запрос RockDB может глубоко и неудачно (из-за фильтра Блума) искать в LSM-дереве, но 3 секунды на NVMe-диске — это невероятно много! Особенно с с учетом того, что слияние LSM делается фоновым тредом и механизм многократно "допиливали", в том числе для стабилизации latency.
MDBX не делает ничего лишнего, просто поиск по B+Tree. Поэтому, в худшем случае, MDBX прочитает кол-во страниц на 2 больше высоты B+Tree дерева. При не-длинных ключах (как в рассматриваемом случае), на одну branch-страницу поместиться 50-100-200 ключей (размер страницы 4К или 8К, примерно делим на размер ключа). Т.е. будет максимум 10 чтений с NVMe (модель указана), который имеет производительность более 500K IOPS при случайном чтении. Поэтому мы должны увидеть max-latency близкую к 10 / 500K = 0,2 миллисекунды. Откуда взялось 100 секунд?
Поэтому, в сухом остатке — показанным цифрам, графика и выводам нельзя верить.
"Sophos XG Firewall — линейка фаирволов следующего поколения" — достойная формулировка, и всегда актуальная, что характерно )
А за "Everyone Else Has Claims. We Have Proof" можно и 0-days дивидендов дождаться, в виде побегов из sandstorm и включения bypass-ов на "фаирволах следующего поколения" )
Детский сад какой-то. Лучше бы начали с (неполного) описания ELF и соответствующих опций ld, потом механизма загрузки (включая ifunc) и затем dwarf3.
Отсылка к "библиотеке Oracle" тоже доставляет )
А можете привести пример с иным поведением, т.е. когда компилятор обнаруживает ошибки после запуска кода?
Могу предположить, что именно такой "компилятор" используется при создании Windows и MS Office, но хотелось-бы больше подробностей об этом know how от Microsoft.
Зачет сдан. 5+.
Я бы сказал не 2-3, а до 10 раз на мелких файловых операциях.
Плюс невменяемая стоимость exec и отсутствие fork/clone, из-за чего неприемлемо тормозит весь не-виндовый софт.
Статья не идеальна, но ваш комментарий не более компетентен.
Следует различать физический уровень LoRa (модуляцию и т.п), от LoRaWAN (управление сетью включая выдачу адресов).
Статья не идеальна, но ваш комментарий не более компетентен.
Следует различать физический уровень LoRa (модуляцию и т.п), от LoRaWAN (управление сетью включая выдачу адресов).
Речь о streambuf и string_view из С++, жаба-аналоги которых несложно реализовать поверх MappedByteBuffer.