Подтвердить что ты не робот

Memory-Mapped MappedByteBuffer или Direct ByteBuffer для реализации БД?

Это выглядит длинным вопросом из-за всего контекста. В романе есть два вопроса. Спасибо, что нашли время, чтобы прочитать это и оказать помощь.

Ситуация

Я работаю над масштабируемой реализацией хранилища данных, которая может поддерживать работу с файлами данных с нескольких КБ до ТБ или больше по размеру в 32-разрядной или 64-разрядной системе.

В хранилище данных используется проект "Копировать-на-запись"; всегда добавляя новые или измененные данные в конец файла данных и никогда не делая на месте редактирования существующих данных.

Система может содержать 1 или более баз данных; каждый из которых представлен файлом на диске.

Детали реализации не важны; единственной важной деталью является то, что мне нужно постоянно добавлять файл и расширять его с КБ, до МБ, до ГБ до ТБ и в то же время случайным образом пропускать файл для операций чтения для ответа на запросы клиентов.

Первоклассники Мысли

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

Тогда весь мой код, о котором нужно беспокоиться, - это сериализовать операции добавления к файлу on-write и позволять любому числу одновременных читателей искать в файле ответы на запросы.

Дизайн

Поскольку отдельные файлы данных могут вырасти за пределы 2 Гбайт MappedByteBuffer, я ожидаю, что мой проект должен будет включать слой абстракции, который принимает смещение записи и преобразует его в смещение внутри определенного сегмента 2 ГБ.

До сих пор так хорошо...

Проблемы

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

Отчитывая здесь примерно 20 "связанных с памятью" вопросов, связанных с SO, кажется, что вызовы mmap чувствительны к желанию непрерывных прогонов памяти при распределении. Так, например, на 32-битной ОС хоста, если я попытался создать файл размером 2 ГБ, из-за фрагментации памяти, мои шансы тонкие, что сопоставление будет успешным, и вместо этого я должен использовать что-то вроде серии из 128 МБ-сопоставлений, чтобы вытащить целую файл.

Когда я думаю об этом дизайне, даже скажу, используя размеры 1024 мегабайта mmap, для СУБД, размещающей несколько огромных баз данных, все из которых представлены, например, 1TB файлами, теперь у меня есть тысячи областей памяти с памятью и в моем собственном тестировании Windows 7, пытаясь создать несколько сотен mmaps в файле с несколькими GB, я не просто столкнулся с исключениями, я фактически получил JVM для segfault каждый раз, когда я пытался выделить слишком много, и в одном случае получил видео в моей Windows 7 для вырезания и повторной инициализации с помощью всплывающего окна OS-error, которое я никогда раньше не видел.

Независимо от аргумента "вы никогда не будете обрабатывать файлы, которые являются большими" или "это надуманный пример", тот факт, что я мог бы что-то кодировать с таким типом побочных эффектов, поставил мою внутреннюю тревогу на высокий уровень -alert и рассмотрел альтернативный имп (ниже).

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

Я могу в какой-то мере бороться с этим расширением файла в кусках (скажем, 8 Мбайт за раз) и только заново создавать сопоставление каждые 8 ​​МБ, но необходимость постоянно воссоздавать эти сопоставления вызывает у меня нервную реакцию, особенно без явно функция unmap, поддерживаемая в Java.

Вопрос № 1 из 2

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

Но затем я оглядываюсь вокруг ландшафта вокруг меня с такими решениями, как MongoDB, охватывающий все файлы, помеченные памятью, и мне кажется, что здесь отсутствует какой-то основной компонент (я знаю, что он выделяет что-то вроде 2 ГБ экстентов на время, так что я думаю, что они работают над стоимостью повторной карты с этой логикой и помогают поддерживать последовательные прогоны на диске).

В этот момент я не знаю, является ли проблема Java отсутствием операции unmap, которая делает это намного более опасным и непригодным для моего использования, или если мое понимание неверно, и кто-то может указать мне на север.

Альтернативный дизайн

Альтернативный дизайн для карты памяти, предложенной выше, которую я буду использовать, если мое понимание mmap правильное:

Определите прямой ByteBuffer разумного настраиваемого размера (примерно 2, 4, 8, 16, 32, 64, 128 КБ), что делает его легко совместимы с любой платформой хоста (не нужно беспокоиться о том, что сама СУБД вызывает сценарии переполнения) и используя исходный FileChannel, выполните чтение с определенным смещением файла объемом 1 бит-емкость, одновременно полностью переносящим файлы с отображением памяти.

Недостатком является то, что теперь мой код должен беспокоиться о таких вещах, как "Я достаточно читал из файла, чтобы загрузить полную запись?"

Другая сторона заключается в том, что я не могу использовать логику виртуальной памяти ОС, позволяя ей автоматически сохранять "горячие" данные в памяти; вместо этого мне просто нужно надеяться, что логика кэша файлов, используемая ОС, достаточно велика, чтобы сделать что-то полезное для меня здесь.

Вопрос № 2 из 2

Я надеялся получить подтверждение моего понимания всего этого.

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

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

4b9b3361

Ответ 1

Вам может быть интересно https://github.com/peter-lawrey/Java-Chronicle

В этом я создаю несколько сопоставлений памяти в один и тот же файл (размер от 2 до 1 ГБ). Файл может быть любого размера (размером до вашего жесткого диска).

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

Он может делиться между процессами и использоваться для событий с низкой задержкой между процессами.

Я полагаю, что вы используете 64-битную ОС, если хотите использовать большие объемы данных. В этом случае вам будет нужен список MappedByteBuffer. Имеет смысл использовать правильные инструменты для работы.;)

Я нашел его производительность даже с размерами данных около 10x вашего размера основной памяти (я использовал быстрый SSD-накопитель, поэтому YMMV)

Ответ 2

Думаю, вам не стоит беспокоиться о файлах mmap'ping размером до 2 ГБ.

Рассматривая источники MongoDB в качестве примера БД, использующие файлы с отображением памяти, вы найдете, что он всегда отображает полный файл данных в MemoryMappedFile:: mapWithOptions() (который вызывает MemoryMappedFile:: map()). Данные БД охватывают несколько файлов размером до 2 ГБ. Также он предопределяет файлы данных, поэтому нет необходимости переназначать по мере роста данных, что предотвращает фрагментацию файлов. Как правило, вы можете вдохновить себя на исходный код этой БД.