Ну, это ожидалось от любого эффективного хранения данных: слова должны индексироваться в памяти в динамической структуре данных ячеек, связанных указателями. Размер метаданных структуры, указателей и внутренней фрагментации распределителя памяти является причиной того, что данные занимают гораздо больше памяти, чем соответствующий плоский файл.
Набор Redis выполнен в виде хеш-таблицы. Это включает в себя:
- массив указателей растет в геометрической прогрессии (степени двух)
- второй массив может потребоваться при инкрементный перепевы активен
- одинарного связанный список ячеек, представляющих записи в хэш-таблице (3 указатели, 24 байта на входе)
- Redis объект обертки (по одному на каждое значение) (16 байт на запись)
- фактические сами данные (каждый из них с приставкой 8 байт для размера и мощности)
Все приведенные выше размеры приведены для реализации 64 бит. Учет служебных данных распределителя памяти приводит к тому, что Redis занимает не менее 64 байт на каждый элемент (поверх данных) для последней версии Redis с использованием распределителя jemalloc (> = 2.4)
Redis предоставляет memory optimizations для некоторых типы данных, но они не охватывают множества строк. Если вам действительно нужно оптимизировать потребление памяти наборами, есть трюки, которые вы можете использовать. Я бы не сделал этого всего за 160 МБ ОЗУ, но если у вас есть большие данные, вот что вы можете сделать.
Если вам не нужны соединения, пересечения, разностные возможности множеств, вы можете хранить свои слова в хэш-объектах. Преимущество хэш-объектов может быть автоматически оптимизировано Redis с использованием zipmap, если они достаточно малы. Механизм zipmap был заменен на ziplist в Redis> = 2.6, но идея такая же: использование сериализованной структуры данных, которая может вписываться в кэши процессора, чтобы получить как производительность, так и компактную память.
Чтобы гарантировать, что хеш-объекты достаточно малы, данные могут быть распределены в соответствии с некоторым механизмом хэширования.Предполагая, что вы должны хранить 1M элементы, добавляя слово может быть реализована следующим образом:
- хэш, по модулю 10000 (сделано на стороне клиента)
- HMSET слова: [hashnum] [слово] 1
Вместо хранения:
words => set{ hi, hello, greetings, howdy, bonjour, salut, ... }
вы можете хранить:
words:H1 => map{ hi:1, greetings:1, bonjour:1, ... }
words:H2 => map{ hello:1, howdy:1, salut:1, ... }
...
Чтобы получить или проверить наличие слова, это то же самое (хеш его и использовать HGET или HEXISTS).
С этой стратегией, значительная экономия памяти может быть сделано при условии, что по модулю хэша будет выбран в соответствии с конфигурацией zipmap (или ZipList для Redis> = 2.6):
# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given number of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
Осторожно: имя эти параметры изменились с помощью Redis> = 2.6.
Здесь modulo 10000 для предметов 1M означает 100 предметов на хэш-объекты, что гарантирует, что все они будут сохранены в виде zipmaps/ziplists.
Увлекательный и подробный ответ; Я этого не знал. Спасибо @Didier! –
Хорошо, спасибо, я очень уверен, что это решит мои проблемы. И да, для 160mb это прекрасно, но я ожидаю работать с до 1gb простых данных слова и не хотел, чтобы это увеличилось до 10gb. Еще раз спасибо, оцените подробный ответ. – cwoebker
@ Didier - Отличный ответ! Пара исправлений, хотя a) Записи Hashtable представляют собой один связанный список, а не двойной, служебные данные 24 байта правильны, хотя b) Оболочка объекта Redis не применяется к каждой записи набора/хэша. Он применим только к парам ключ/значение верхнего уровня, так что накладные расходы постоянны. C) Вы можете указать, что zipmap устарел в 2.6/unstable, и этот ziplist делает эквивалентную вещь. –