Към съдържанието

Сегментиране

DocStore записва по един файл за всеки запис. Без сегментиране голяма колекция би струпала всички файлове в една директория, а операциите с директории се забавят с увеличаването на броя записи. Затова storh разпределя файловете със записи в групи според два знака от идентификатора:

Text
pages/data/2d/018bcfe5-6800-7000-8000-2d5dba6274da.jsonc

Групата се определя от началото на последната група в UUID (знаци 24 и 25), което е случайна ентропия. Два шестнадесетични знака дават 256 групи, така че колекция със 100k записа има средно под 400 файла във всяка директория.

Защо последните, а не първите знаци

Идентификаторите UUIDv7 започват с 48-битов времеви отпечатък в милисекунди, затова идентификаторите, създадени близо един до друг, споделят началните си знаци. Сегментирането по префикс би насочило всеки изблик на записи към една и съща натоварена директория и би сменяло групите едва с течение на времето. Последните байтове са случайни за всеки запис, така че записите се разпределят равномерно още от първия.

Сегментирането не се вижда при четене и заявки: get() изчислява групата от идентификатора, а stream() връща записите, сортирани по идентификатор във всички групи, така че страничното прелистване с курсор работи така, сякаш колекцията е един подреден списък.

При голям мащаб

Броят на групите никога не нараства: два шестнадесетични знака означават 256 директории при всякакъв размер на колекцията. Нараства броят на файловете във всяка група:

Записи Файлове във всяка група
10k ~40
100k ~390
1M ~3,900
10M ~39,000

Съвременните файлови системи индексират записите в директориите, така че няколко хиляди файла във всяка група поддържат бързо търсене на отделни записи; 1M записа е удобен обем за get() и индексирани заявки. Отварянето на хранилище отнема постоянно време независимо от размера на колекцията: почистването на осиротели временни файлове се изпълнява само когато маркер за прекъснал запис показва, че предишен процес се е сринал по време на запис. Операциите, които растат линейно при мащабиране, са операциите върху цялата колекция: неиндексираните сканирания, reindex() и verify() обхождат всеки файл със запис, затова ги планирайте като пакетни задачи. При над приблизително 10M записа в колекция започват да имат значение броят във всяка група и общото използване на inode: разделете колекциите или използвайте сегментирания журнал за данни, които се сканират, тъй като той поддържа малък брой файлове по замисъл.

Другите машини

SegmentedLog и Queue не използват сегментиране, защото не създават по един файл за всеки запис. Журналът добавя записи към сегментни файлове в segments/, ограничени от max_segment_bytes (по подразбиране 1 MiB), а опашката добавя събития към един queue.log. Броят на файловете остава нисък по замисъл.