MappedByteBuffer с отображением в память или DirectBuffer для реализации БД? - PullRequest
21 голосов
/ 13 февраля 2012

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

Положение

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

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

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

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

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

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

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

Дизайн

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

Пока все хорошо ...

Проблемы

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

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

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

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

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

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

Вопрос № 1 из 2

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

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

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

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

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

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

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

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

Вопрос № 2 из 2

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

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

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

Ответы [ 2 ]

15 голосов
/ 14 февраля 2012

Возможно, вас заинтересует https://github.com/peter-lawrey/Java-Chronicle

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

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

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

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

Я считаю, что он хорошо работает даже при объемах данных, примерно в 10 раз превышающих объем вашей основной памяти (я использовал быстрый SSD-накопитель, поэтому YMMV) * ​​1012 *

2 голосов
/ 13 февраля 2012

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

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

...