Ответ 1
Спасибо Андре за его ответ. Вот мои выводы.
Сохранение ints напрямую
Ключи Redis должны быть строками. Если вы хотите передать целое число, это должна быть какая-то строка. Для небольших, четко определенных наборов значений, Redis будет анализировать строку в целое число, если оно одно. Я предполагаю, что он будет использовать этот int для адаптации своей хэш-функции (или даже статически измеряет хэш-таблицу на основе значения). Это работает для небольших значений (примерами являются значения по умолчанию для 64 записей значения до 512). Я буду испытывать большие значения во время моего расследования.
http://redis.io/topics/memory-optimization
Сохранение в виде строк
Альтернативой является раздавливание целого числа, чтобы оно выглядело как строка.
Похоже, что в качестве ключа можно использовать любую байтовую строку.
В случае с моим приложением на самом деле это не так сильно повлияло на сохранение строк или целых чисел. Я полагаю, что структура в Redis все равно подвергается некоторому выравниванию, так что в любом случае могут быть некоторые предварительно потраченные байты. Значение хэшируется в любом случае.
Используя Python для моего тестирования, я смог создать значения с помощью struct.pack
. long long
весит 8 байт, что довольно велико. Учитывая распределение целочисленных значений, я обнаружил, что на самом деле может быть полезно хранить строки, особенно когда они закодированы в шестнадцатеричном формате.
Поскольку строки перерисовывания являются "Pascal-style":
struct sdshdr {
long len;
long free;
char buf[];
};
и учитывая, что мы можем хранить что-нибудь там, я сделал немного дополнительного Python, чтобы закодировать тип в кратчайший возможный тип:
def do_pack(prefix, number):
"""
Pack the number into the best possible string. With a prefix char.
"""
# char
if number < (1 << 8*1):
return pack("!cB", prefix, number)
# ushort
elif number < (1 << 8*2):
return pack("!cH", prefix, number)
# uint
elif number < (1 << 8*4):
return pack("!cI", prefix, number)
# ulonglong
elif number < (1 << 8*8):
return pack("!cQ", prefix, number)
Это, по-видимому, делает незначительную экономию (или вообще ничего). Вероятно, из-за добавления структуры в Redis. Это также управляет процессором Python через крышу, что делает ее несколько непривлекательной.
Данные, с которыми я работал, были 200000 zsets consecutive integer => (weight, random integer) × 100
, плюс некоторый инвертированный индекс (основанный на случайных данных). dbsize
дает 1 200 001 ключей.
Конечная память сервера: 1,28 ГБ оперативной памяти, 1.32 виртуальная. Различные настройки имели значение не более 10 мегабайт в любом случае.
Итак, мой вывод:
Не докучайте кодировку в типы данных фиксированного размера. Просто сохраните целое число как строку, в шестнадцатеричном формате, если хотите. Это не будет иметь столь большой разницы.
Литература: