Согласно документации Redis хэштеги можно использовать для принудительного назначения ключей одному и тому же хеш-слоту. У меня есть вариант использования, когда мы храним {UUID}Integer как массив байтов в Redis, и я ожидаю, что для назначения хеш-слота будет использоваться только часть UUID.
Проблема, с которой мы сталкиваемся, заключается в том, что если UUID содержит символы 7b
или 7d
, он конфликтует с {
и }
, представленными значениями байтов ASCII 123 (0x7b) и 125 (0x7d) соответственно, что влияет на распределение этих ключей.
Например, 7d3e4567-e89b-12d3-a456-426614174000
печатается как {}>Eg\xe8\x9b\x12\xd3\xa4VBf\x14\x17@\x00}
при сохранении с хэштегами в Redis.
Есть ли способ экранировать символы в UUID, чтобы расчет хеш-слота работал правильно, или есть ли другой обходной путь?
Невозможно сообщить Redis, что байт 7b
или 7d
не является фигурной скобкой.
Единственный способ обойти эту проблему, который я вижу, — это по-другому закодировать UUID.
Я предполагаю, что вас волнует скорость кодирования и потребление памяти. В настоящее время вы используете 16 байт на UUID, что является оптимальным.
Вы можете использовать кодировку Base64, чтобы избежать этой проблемы. для этого потребуется один байт на 6 бит, следовательно, 22 байта на UUID.
Другой вариант — использовать собственную кодировку: каждые 7 бит преобразуются в символ 00
..81
, кроме 7b
и 7d
. Кодировка относительно проста — вам придется извлекать по 7 бит за раз и заменять 7b
на 80
и 7d
на 81
. Для этого потребуется один байт на 7 бит, следовательно, 19 байт на UUID.
Другая возможная кодировка — добавление 2 байтов к UUID. Теперь у вас есть 16 байт + 16 бит. Установите эти 16 бит четности на 0. Далее для каждого из 16 байтов: если это 7b
— замените его на 7a
и установите соответствующий бит четности. Если это 7d
— замените его на 7c
и установите соответствующий бит четности. Однако с этой кодировкой есть проблема: два добавленных байта могут стать 7b
или 7d
. Чтобы этого избежать — вместо этого добавьте 3 байта и разделите 16 бит четности между этими 3 байтами, избегая наиболее значимого бита каждого из этих байтов. Вы можете дополнительно оптимизировать: для каждого байта UUID: if (byte & 0x01 == 0) { byte |= 1; установить соответствующий бит четности }
Более сложные кодировки могут уменьшить это число до 17 байт на UUID, но вычисление будет медленнее.
Еще один вариант, который следует рассмотреть: если вы генерируете эти UUID, вы можете просто избежать создания UUID, содержащих 7b
и 7d
.
Если байты четности — это последние два байта ключа, то даже если дополнительные байты разрешаются в 7b
или 7d
, это не должно быть проблемой, верно, потому что Redis уже оценил бы хэштеги вокруг UUID? Redis использует первое вхождение согласно документации .
Нет, байты четности должны быть частью вашего закодированного UUID.
На самом деле да. Вы можете хешировать только закодированный UUID без байтов четности. Некоторые UUID будут хэшироваться в один и тот же слот, но что с того? это произойдет в любом случае. Это не добавило бы существенного смещения распределения.
Да, цель состоит в оптимизации памяти, что является причиной хранения UUID в двоичном виде. Изучение пользовательской кодировки для решения проблемы.