Из внутреннего устройства, например:
- компактное представление для hash и list есть, а для set - нет. Т.е. маленький хэш может в виде линейного блоба храниться, без оверхед в 56 байт на элемент, а set только в виде хэш-таблицы (которая отвратительна)
- ttl элемента хранится не в самом элементе, а в отдельной хэш-таблице. + 56 байт на каждый элемент. + поход в ещё одну хэш-таблицу, чтобы проверить expiration. (А в нашем случае использования, значений без TTL вообще нет)
- в кластере чтобы держать список ключей в слоте, используются ещё одна хэш-таблица (правда с другим устройством). И ее тоже нужно мантейнить.
- expiration сделан рандомом. В итоге, какие-то значения залипают очень надолго.
- все бы ни чего, но если он решает по-эвиктить, то все может начать резко тормозить. Потому что если вставляется большой кусок, то ему приходится много мелких эвиктить. Не знаю, правда, как это решать :-( В memcached вытесняются сразу такого же размера. Кому-то это не нравится, зато тупняков нет. Как это в общем случае реализовать, не знаю. ) Можно было бы не тупить сразу, а пытаться дочистить потом; типа кроме max_memory иметь ещё real_max_memory. По max_memory начинать eviction, а тупить по real_max_memory.
- кластер... делает вид, что работает. На практике год назад разваливался от любого неосторожного приседания. Заслал им тестов и корявых фиксов. Тесты не приняли, сказали «мы тут на Ruby хотели переписывать тесты, потому пока не возьмём». Что-то починили, но из четырёх тестов один все ещё падает. В итоге, у нас в проде редис с костылём в этом месте.