Redis в 10 раз больше использования памяти, чем данные - программирование
Подтвердить что ты не робот

Redis в 10 раз больше использования памяти, чем данные

У меня есть небольшой вопрос.

Я пытаюсь сохранить список слов в redis. Отличная производительность.

Мой подход состоит в создании набора под названием "слова" и добавлении каждого нового слова через "sadd".

Здесь проблема при добавлении файла размером 15.9mb и содержит около миллиона слов, процесс redis-server потребляет 160 МБ оперативной памяти. Почему я использую 10-кратную память, есть ли лучший способ приблизиться к этой проблеме?

Спасибо в Advance

4b9b3361

Ответ 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.

Ответ 2

Что касается моих экспериментов, лучше хранить данные внутри хэш-таблицы/словаря. самый лучший случай, который я достиг, после того, как много бенчмаркинга хранится внутри ваших записей данных хэш-таблицы, которые не превышают 500 ключей.

Я пробовал стандартную строку set/get, для 1 миллиона ключей/значений, размер был 79 МБ. Он очень большой, если у вас есть большие цифры, например, 100 миллионов, которые будут использовать около 8 ГБ.

Я попробовал хэши хранить одни и те же данные, для тех же миллионов ключей/значений размер был все меньше и меньше 16 МБ.

Попробуйте в случае, если кому-то нужен код бенчмаркинга, напишите мне письмо

Ответ 3

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

Также: Какая версия Redis для вас работает? Посмотрите этот пост в блоге - в нем говорится, что фрагментация частично решена с версии 2.4.