Ответ 1
Ну, это ожидалось от любого эффективного хранения данных: слова должны индексироваться в памяти в динамической структуре данных ячеек, связанных указателями. Размер метаданных структуры, указателей и внутренней фрагментации распределителя памяти является причиной того, что данные занимают гораздо больше памяти, чем соответствующий плоский файл.
Набор Redis реализован как хэш-таблица. Это включает в себя:
- массив указателей, растущих геометрически (степени двух)
- может потребоваться второй массив, если активна инкрементная перезагрузка
- односвязные ячейки списка, представляющие записи в хеш-таблице (3 указателя, 24 байта на запись)
- Оболочки объектов Redis (по одному на каждое значение) (16 байт на запись)
- сами фактические данные (каждый из них имеет префикс 8 байтов для размера и емкости)
Все приведенные выше размеры приведены для реализации 64 бит. Учет служебных данных распределителя памяти приводит к тому, что Redis принимает не менее 64 байт на каждый элемент (поверх данных) для последней версии Redis с использованием распределителя jemalloc ( >= 2.4)
Redis обеспечивает оптимизацию памяти для некоторых типов данных, но они не охватывают множество строк. Если вам действительно нужно оптимизировать потребление памяти наборами, есть трюки, которые вы можете использовать. Я бы не сделал этого всего за 160 МБ ОЗУ, но если у вас есть большие данные, вот что вы можете сделать.
Если вам не нужны объединения, пересечения, разностные возможности наборов, вы можете хранить свои слова в хэш-объектах. Преимущество хэш-объектов может быть автоматически оптимизировано Redis с использованием zipmap, если они достаточно малы. Механизм zipmap был заменен на ziplist в Redis >= 2.6, но идея одинаков: использование сериализованной структуры данных, которая может вписываться в кэши процессора, чтобы получить как производительность, так и компактную память.
Чтобы гарантировать, что хэш-объекты достаточно малы, данные могут быть распределены в соответствии с некоторым механизмом хэширования. Предполагая, что вам нужно хранить элементы 1M, добавление слова может быть реализовано следующим образом:
- hash it modulo 10000 (выполняется на стороне клиента)
- Слова HMSET: [hashnum] [word] 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.