29 сентября 2026 года Percona выложила замер памяти Valkey. Короткий SET в сборке 9.1.1 занимает 64,02 байта на ключ. В 7.2.14 тот же ключ стоил 102,48 байта. Разница 37,5%.
Цифры из поста Percona Team от 29 сентября. Это не USN и не пакет в репозитории дистрибутива. Сравнивали пять сборок из исходников: 7.2.14, 8.0.10, 8.1.9, 9.0.5 и 9.1.1. Аллокатор везде jemalloc 5.3.0, чтобы версия была единственной переменной. Режим standalone, не кластер. У процесса maxmemory 0, пустой save и appendonly no: ни вытеснения, ни снимка, ни AOF.
Нагрузка описана так: valkey-benchmark, тип set, миллион запросов, -r тоже миллион, значение 16 байт. Из-за коллизий ключей уникальными остаются около 63,2%. В таблице это примерно 632 тысячи. Память пустого процесса вычитают и считают маржинальные байты на ключ. В посте сказано, что так устроен официальный метод бенчмарка Valkey. Ссылок на release notes в статье нет.
37,5% они относят к средам, где много коротких строковых ключей: кэш, сессии, авторизация, мелкие realtime-ключи. Крупное значение этот процент само по себе не обещает. Самый большой шаг в ряду, по их же таблице, не 9.1, а переход 7.2 к 8.1: минус 29,8%.
В начале поста есть набросок «было 1 ТБ на 7.2»: 1000 ГБ, потом около 800 ГБ на 8.0, 640 ГБ на 8.1 и 630 ГБ на 9.1. Таблица с ним не сходится. 800 ГБ от 1000 это минус 20%, а 8.0.10 в замере минус 7,8%. 640 ГБ ближе к минус 36%, у 8.1 к базе минус 29,8%. К 9.1 набросок ближе к таблице: 630 ГБ почти те 37%. RAM под апгрейд лучше считать по байтам на ключ, не по верхней плашке.
7.2.14, 8.0.10, 8.1.9, 9.0.5, 9.1.1
Одинаковые условия, разное число уникальных ключей из-за случайных коллизий. Ниже строки их таблицы, не округление.
- 7.2.14: 632 181 ключ, 61,78 МБ, 102,48 байта. База.
- 8.0.10: 632 565 ключей, 57,00 МБ, 94,49 байта. Минус 7,8% к 7.2.14.
- 8.1.9: 632 573 ключа, 43,43 МБ, 71,98 байта. Минус 23,8% к предыдущей сборке и минус 29,8% к 7.2.14.
- 9.0.5: 631 672 ключа, 43,36 МБ, 71,99 байта. К 8.1 ноль. К 7.2.14 те же минус 29,8%.
- 9.1.1: 631 985 ключей, 38,58 МБ, 64,02 байта. Минус 11,1% к 9.0.5 и минус 37,5% к 7.2.14.
На том же железе таких мелких ключей влезает примерно на 60% больше: 102,48 разделить на 64,02. Формулировка из поста, арифметика сходится. Почти весь путь сделала 8.1. Ветка 9.0 в этой гонке стоит: 71,98 и 71,99 байта. Percona пишет, что тот релиз память не целил.
dictEntry в 8.0 и кэш-линия в 8.1
С 7.2 на 8.0 ключ перестали хранить отдельным куском. В 7.2 dictEntry это три указателя, 24 байта: key, val, next. Сам ключ лежит в другом выделении, SDS, и чтение прыгает туда отдельно. В 8.0 появляется embeddedDictEntry: байты ключа лежат сразу за структурой. Остаются указатели val и next плюс ключ на месте. 16 байт плюс длина ключа, одно выделение вместо двух. Итог в посте: минус 8 байт на ключ, на один прыжок по памяти меньше, конфиг менять не нужно. 102,48 минус 94,49 как раз около восьми байт.
С 8.0 на 8.1 переписали словарь. В 8.0 обычная цепочка: бакет, запись, ключ, значение. Четыре прыжка, и ещё по два на коллизию. В 8.1 один бакет ровно 64 байта, длина кэш-линии. Ключ и значение сидят внутри. Восьмибайтовая шапка бакета пакует бит «есть дочерний бакет», семь бит занятости и семь байт вторичного хеша. Чужой кандидат часто отсекается без лишнего чтения. dictEntry как структура пропадает. Путь короче: бакет и serverObject. Коллизия чаще остаётся в той же линии.
Оценка Percona для этого шага: около минус 20 байт на пару ключ-значение и около минус 30 байт, если у ключа есть TTL. В таблице 94,49 к 71,98, это 22,5 байта. Порядок тот же. Это и есть минус 23,8% к предыдущей сборке, самый крупный одиночный скачок 7.2-9.1.
Дальше 9.0 пустая по памяти. С 9.0 на 9.1 разобрали короткую строку. Раньше embstr всё равно держал восьмибайтовый указатель на данные, которые лежали следом за заголовком объекта. В 9.1 для короткой строки эти же восемь байт заняты самими байтами строки. Отдельного указателя нет, отдельного выделения под значение тоже. Потолок в посте: до 20% на строках короче 128 байт. Значения бенчмарка по 16 байт в этом диапазоне. Весь ключ при этом с 71,99 до 64,02, минус 11,1%, не минус 20. Двадцать процентов про укладку короткой строки. Не про весь used_memory процесса.
Три правки, не один тумблер. 8.0 вшила ключ в запись. 8.1 убрала цепочку в кэш-линию и выкинула dictEntry. 9.1 забрала указатель у строки короче 128 байт. В конфиге под это отдельной директивы пост не показывает.
220 МБ четырьмя SET и 100 МБ одним HSET
В том же посте второй замер. Миллион записей, две укладки одних и тех же полей. Версию этой прогонки текст не называет. К 9.1.1 её привязать нельзя.
Первый способ: четыре строковых ключа на пользователя. SET user:1:name и ещё три ключа на возраст, город и счёт. В примере значения Alice, 30, Toronto, 100. Второй способ: один хеш, HSET user:1 с теми же четырьмя полями.
Четыре строки заняли 220 МБ. Один хеш занял 100 МБ. Минус 54%. Фиксированная цена ключа платится четыре раза или один раз. Для кэша, где на одну сущность наросли имя, мета и флаг, эта укладка часто заметнее, чем шаг с 9.0.5 на 9.1.1.
Хеш не объявлен победителем на все случаи. Память на объёме за хешем. TTL на отдельное поле за строкой: у строки родной EXPIRE, у хеша полевого TTL до 7.4 не было. Несколько полей за один заход за хешем, HSET или HMGET. Строкам на то же нужны отдельные круги. Слот в кластере: хеш и так один ключ и один слот, строки надо вручную склеивать хештегом. На одном VPS без кластера последний пункт unit-файл не меняет.
used_memory на VPS и чужие 16 байт
На обычном сервере с сайтом рядом с nginx, php-fpm и MariaDB часто крутится отдельный процесс кэша. Объектный кэш WordPress и сессии PHP живут в нём. Файловый fastcgi_cache и proxy_cache nginx к этой таблице не относятся: они не станут легче на 37,5% от нового Valkey.
64,02 байта сняты с пустого инстанса, куда бенчмарк записал короткие SET по 16 байт, минус память пустого процесса. Объектный кэш сайта держит сериализованные куски, часто гораздо длиннее. Доля фиксированной цены ключа там меньше, и 37,5% к своему RSS прикладывать нельзя. Если ключей много, а значения короткие, профиль ближе к таблице. Сессия одним ключом ближе к схеме «одна сущность, один ключ», а не к четырём SET на пользователя.
Замер сделан на своих сборках с одним jemalloc. Пакет из репозитория, старый пакет с именем redis и контейнер со своим тегом могут быть другой сборкой. Пока процесс не 9.1.1, нижняя строка таблицы не ваш расход. Пока он 7.2, вы на верхней. Сборка 9.0 относительно 8.1 память не отдаёт: в замере у них ноль.
Про укладку ключа в 8.0 пост пишет, что правка конфига не нужна и смена приезжает вместе с версией. Про то, что обновление пакета в ту же секунду переложит уже лежащий дамп и RSS упадёт до лабораторной цифры, там ничего нет. Байты считали на ключах, которые бенчмарк записал в этот процесс.
Флаги лаборатории в unit боевого кэша копировать не надо. maxmemory 0, пустой save и appendonly no выключили вытеснение, снимок и AOF, чтобы в цифру не попала персистентность. На кэше с сессиями это уже другой режим, не «как в статье, чтобы было меньше RAM».
Смотреть версию и объём можно без записи. Если клиент называется redis-cli, тот же INFO читается им. В server строка версии, в memory поле used_memory. Это не их маржинальные 64 байта: в цифре сидят пустой процесс, фрагментация, клиенты и сами значения. Имеет смысл порядок и динамика, не совпадение с таблицей до сотой. Если клиент просит пароль, это requirepass вашего конфига. В посте пароля нет.
valkey-cli INFO server valkey-cli INFO memory
Копию конфига имеет смысл снять тогда, когда после замера вы реально правите unit или конфиг кэша. Сам INFO файлы не трогает. nginx -t здесь ни при чём, пока вы не меняете прокси к этому процессу. Репозиторий, из которого ставили бинарник, и имя пакета (valkey или ещё redis) путают чаще, чем флаги бенчмарка: в INFO server будет та версия, которая реально слушает порт, а не та, что в заголовке поста.
Для коротких строк лаборатория показывает заметный зазор между 7.2.14 и 9.1.1, и почти весь он сидит в 8.1. Ветка 9.0 память не уменьшила. Укладка «четыре ключа вместо одного хеша» во втором примере дала 54%, и версию той прогонки пост не назвал. На VPS сначала версия процесса и то, из чего собран ключ. Потом уже разговор, хватит ли RAM.