Откуда берется сравнение с Redis и почему HurriCache — это не «еще один аналог»

Redis — это безусловный индустриальный стандарт и великолепный инструмент, доказавший свою надежность годами эксплуатации. Задача HurriCache — решить те задачи с которыми Redis, с однопоточной архитектурой классических in-memory решений, изначально не справлялся, и в некоторой степени не предназначен для них.

На экстремально высоких нагрузках ключевые особенности Redis иногда превращаются в узкие места:

  • Непредсказуемые задержки (Latency Spikes): Выбросы p99/p99.9 из-за фонового рехешинга или исполнения длительных Lua-скриптов;

  • Просадки на записи и удалении: Падение пропускной способности при интенсивной смешанной CRUD-нагрузке;

  • Ограничение одного ядра: Необходимость администрирования десятков мелких инстансов Redis для утилизации мощностей современных многоядерных серверов.

HurriCache создан как узкоспециализированный, ultra-high-load «горячий» слой для предельно быстрых и регулярных операций над данными в оперативной памяти (без встроенной персистентности на диск). Это не прямая замена Redis — системы преследуют разные архитектурные цели, но в своем целевом профиле нагрузки HurriCache позволяет выжать максимум из современного железа.

Архитектура HurriCache

В основе HurriCache лежит кастомная, сильно оптимизированная Partitioned Hash Map.

Если не уходить в глубокие детали реализации, главное её свойство — полное отсутствие глобального рехешинга (Stop-the-World rehashing). При проектировании структуры использовались отдельные концептуальные идеи из absl::flat_hash_map, однако под узкоспециализированные задачи HurriCache собственная Partitioned Hash Map демонстрирует ощутимо более высокую производительность.

Оптимизация достигается за счет нескольких ключевых решений:

  • Шардирование структуры в памяти: данные разбиваются на независимые партиции, что избавляет от просадок p99/p99.9 latency, неизбежно возникающих при расширении обычных словарей;

  • Аппаратное ускорение: активное применение SIMD-инструкций (SSE, AVX, CRC32) для параллельного вычисления хэшей;

  • Cache-friendly подходы: упаковка данных под размер кеш-линий процессора (64 bytes) и использование аппаратных prefetch, сводящее к минимуму CPU stalls при обращении к бакетам.

Остальные внутренние детали реализации структуры данных являются коммерческой тайной.

Архитектурная схема узлов и взаимодействия

Упрощенно структура кластера и потоки данных выглядят так:

Упрощенная архитектура HurriCache
Упрощенная архитектура HurriCache

Разбор компонентов схемы:

  1. SmartClient: Служит единой точкой входа для приложения. Он разделяет служебный и дата-трафик:

    • Routing-запросы: периодически запрашивает актуальные данные о топологии кластера у HurriCache Coordinator Server.

    • Data-запросы: отправляет CRUD-операции и работы с контейнерами напрямую в HurriCache Server конкретной ноды-владельца ключа.

  2. Анатомия узла (Node 1 / Node 2): Каждый узел представляет собой изолированный процессинг со своим набором компонентов, связываемых через gRPC Layer:

    • HurriCache Server: основной модуль обработки CRUD-запросов и выполнения атомиков прямо над Partitioned HashMap.

    • HurriCache Coordinator Server: многофункциональный управляющий модуль — отдаёт актуальную карту маршрутизации (Routing Data) клиентам, отвечает за глобальное управление распределением шардов, процесс миграции данных между нодами и непрерывно проверяет жизнеспособность (health check) соседних узлов.

    • Replication Server: модуль фоновой репликации, обменивающийся данными напрямую с Replication Server соседних нод кластера для обеспечения отказоустойчивости.

    • Routing Data & Partitioned HashMap: локальное хранилище состояния топологии и непосредственная in-memory структура данных.

Что такое SmartClient

SmartClient — это умный клиентский слой (SDK), реализующий клиентскую маршрутизацию (client-side sharding). Вместо использования прокси-серверов или тяжелой перемаршрутизации на стороне хранилища, SmartClient полностью берет на себя логику выбора целевого узла, обеспечивая минимальный RTT и предсказуемую задержку.

Ключевые подходы к работе

  • Локальная карта топологии: SmartClient фоново запрашивает у координатора состояние кластера и держит в памяти актуальную таблицу маршрутизации (Master / Backup ноды для каждого шарда). Это позволяет отправлять gRPC-запрос сразу на целевой сервер без промежуточных хопов.

  • Гибкий расчет KeyHint: До отправки сетевого вызова клиент может вычислить детерминированный KeyHint (включающий хэш ключа, например WeekHash или StrongHash). Если клиент этого не делает, KeyHint генерируется сервером (например, при вызовах createKeyValue). По значению KeyHint SmartClient мгновенно определяет нужный ShardID и обращается напрямую к целевому узлу.

  • Автоматический Fallback и Reroute: В случае неактуальности локальной карты топологии или переезда шарда, узел HurriCache возвращает ошибку перемаршрутизации (со статусом FAILED_PRECONDITION и новыми метаданными роутинга в gRPC Trailers). SmartClient прозрачно для приложения обновляет локальную таблицу роутинга и делает бесшовный retry на правильную ноду.

Почему маршрутизация вынесена на сторону клиента (Client-Side Routing)

В классических прокси-схемах или при реализации рероутинга внутри узлов хранилища сервер, получивший запрос «не по адресу», вынужден самостоятельно пересылать его на правильную ноду. В HurriCache от этой схемы осознанно отказались:

  • Исключение двойного RTT и процессорных оверхедов: Внутренний пересыл — это синхронная межнодовая сетевая операция. На обработку одного такого запроса блокируются ресурсы минимум двух узлов (потока-прокси на первой ноде и потока-исполнителя на целевой).

  • Сохранение линейной пропускной способности: Внутренний роутинг превращает узлы кластера в транзитные прокси, из-за чего пропускная способность падала бы кратно росту объема данных и количества шардов.

  • Дешевая коррекция на клиенте: Если SmartClient ошибается с выбором ноды (например, при рассинхронизации топологии), сервер не пересылает тело запроса, а возвращает легкий gRPC-заголовок с корректными метаданными роутинга. Повторная отправка происходит прямо с клиента, что не нагружает межнодовую сеть и позволяет кластеру масштабироваться линейно под высокой нагрузкой.

Поддерживаемые операции в HurriCache

HurriCache предоставляет богатый набор примитивов, разработанных с акцентом на строгость типов, нативную атомарность и безопасность в распределенной среде.

  • 1. Базовые Key-Value операции (Скаляры)

    • createKeyValue: Создание новой пары «ключ-значение». Главное отличие от Redis — отсутствие lazy create (upsert): если ключ уже существует, система вернет ошибку. Это предохраняет данные от случайного перезаписывания.

    • getValue: Чтение значения по ключу.

    • getAndDeleteValue: Атомарное чтение и последующее удаление объекта за один запрос (Get-and-Delete).

    • updateValue: Явное обновление только существующего значения.

    • remove: Универсальное удаление объекта любого типа или контейнера из памяти.

    2. Контейнеры и коллективные типы HurriCache поддерживает привычные по функциональности Redis структуры данных, но добавляет к ним нативные атомарные операции вроде GetAndDelete для внутренних элементов:

    • Set: Упорядоченные (OrderedSet) и неупорядоченные (HashSet).

    • Map: Упорядоченные (OrderedMap) и неупорядоченные (HashMap).

    • List: Двусвязный список (Linked List).

    • Vector: Динамический массив (Array List).

    • Queue: Строгая очередь FIFO.

  • Встроенная система распределенных блокировок Благодаря нативной поддержке Multi-tenancy, HurriCache позволяет любому клиенту изолированно заблокировать целевой объект. Блокировка регулируется на уровне движка с помощью типов:

enum LockType : uint8_t {
    NO_LOCK = 0,
    WRITE_LOCK = 1,
    READ_LOCK = 2,
    GLOBAL = 3
};
  • Lock-Free Атомики (Out-of-the-Box) Если в Redis для реализации атомарных цепочек (например, CAS) приходится писать Lua-скрипты, блокирующие исполняющий поток, то HurriCache поддерживает безблокировочные атомики «из коробки» прямо в кластерном режиме:

    • Создание: atomicCreate.

    • Чтение и запись: atomicLoad, atomicStore, atomicLoadAndDelete.

    • Модификация и обмен: atomicExchange, atomicAdd, atomicSub.

    • Побитовые операции: atomicOr, atomicAnd, atomicXor.

    • CAS операции: atomicCompareAndSet (CAS) для построения высоконагруженных lock-free алгоритмов поверх кэша.

Сравнение архитектур Redis и HurriCache

Главное архитектурное различие между системами кроется в подходе к параллелизму и организации данных в памяти. Redis исторически опирается на однопоточную исполняющую модель (Single-Threaded Event Loop) и единый глобальный словарь — это исключает состояния гонки, но упирается в производительность одного ядра CPU и приводит к просадкам p99 latency при фоновом рехешинге.

HurriCache, напротив, изначально спроектирован под многопоточную асинхронную архитектуру. В его основе лежит кастомная Partitioned Hash Map, которая устраняет задержки Stop-the-World за счет шардирования структуры данных прямо в памяти и агрессивного использования возможностей железа:

  • SIMD-ускорение: инструкций SSE, AVX и аппаратного CRC32 для мгновенного параллельного вычисления хэшей;

  • Cache-friendly: структуры данных оптимизированы под размер кеш-линий процессора (64 bytes);

  • Аппаратный Prefetch: инструкция явного предвыборки данных в кеш L1/L2 процессора до обращения к памяти, что сводит к минимуму CPU stalls при перемещении по цепочкам бакетов.

Для работы с сетью HurriCache использует глубоко кастомизированный gRPC Engine. За счет прямого управления асинхронными Completion Queues, оптимизированного сборкой под LTO и выравниванием thread_local переменных, система линейно масштабирует пропускную способность по всем доступным ядрам CPU там, где Redis упирается в потолок одного треда. (Это далеко не все изменения в gRPC Engine)

Сравнение API Redis vs HurriCache

Сравнение интерфейсов отражает кардинальное различие в идеологии двух систем: универсальный текстовый/RESP-протокол Redis с динамической типизацией против строго детерминированного, высокопроизводительного Protobuf-контракта в HurriCache.

  • Протокольная основа и строгость типов: Redis использует собственные текстовые/RESP-команды (SET, HSET, LPUSH), где аргументы передаются как массивы строк, а тип контейнера определяется динамически в момент создания. В HurriCache контракт задан строго через gRPC-сервис HurriCacheGrpcService. Каждая операция имеет четко типизированную RPC-сигнатуру, что дает высокую производительность на сериализации (благодаря Protobuf-аренам) и автогенерацию типобезопасных клиентов под любые языки без написания парсеров.

  • Семантика создания объектов (Explicit vs Lazy): В Redis создание ключей происходит по схеме lazy create/upsert: команда SET или LPUSH создаст объект, если его не существовало, или перезапишет/допишет в него. HurriCache разделяет создание и модификацию:

    • Создание скаляров и контейнеров строго явное (createKeyValue, createContainer), возвращающее KeyHintResponse для будущей мгновенной маршрутизации.

    • Попытка пересоздать существующий ключ вернет ошибку. Это исключает случайные перезаписи данных на сетевом уровне.

  • Атомарность и работы с контейнерами: В Redis составные операции (например, «прочитать и сразу удалить элемент контейнера» или CAS-сравнение) требуют написания Lua-скриптов или сложных цепочек WATCH/MULTI/EXEC. В API HurriCache такие паттерны извлечения внедрены на уровне нативных RPC-вызовов:

    • getAndDeleteValue (для скаляров), getAndRemoveFront / getAndRemoveTail (для списков и очередей).

    • getAndRemoveElementAtPosition и getAndDeleteValueInContainer (для карт и множеств). Операции выполняются за один RTT на уровне ядра хранилища без накладных расходов на интерпретатор Lua.

  • Полноценные Lock-Free Атомики (out-of-the-box): У Redis для работы со счетчиками есть только базовые INCR / DECRBY, а для сложной атомарной логики снова нужен Lua. HurriCache предоставляет полноценный набор атомарных примитивов для безблокировочной разработки:

    • Низкоуровневые битовые операции: atomicOr, atomicAnd, atomicXor.

    • Обмен и сравнение: atomicExchange и нативный atomicCompareAndSet (CAS), что позволяет строить распределенные lock-free алгоритмы прямо поверх кэша.

  • Явное управление блокировками и TTL: В Redis блокировки строятся поверх сторонних алгоритмов (вроде Redlock через SET NX EX). В HurriCache явное управление блокировками объектов встроенное: методы lockObject и unlockObject поддерживают различные уровни гранулярности (READ_LOCK, WRITE_LOCK, GLOBAL), интегрированные с системой Multi-tenancy. Настройки TTL (setTtl, getTtl) при этом едины и применимы ко всем типам данных (включая сложные контейнеры и атомики).

Результаты тестов

Чтобы проверить реальную производительность HurriCache под нагрузкой, была проведена серия стресс-тестов.

Конфигурация тестового стенда:

  • Топология: 1-нодовая конфигурация (Single Node)

  • CPU: Intel Core i9-11900K (11th Gen) @ 3.50GHz (8 ядер / 16 потоков)

  • RAM: 128 GB DDR4 (двухканальный режим)

  • Сеть: loopback (127.0.0.1) — тест измеряет чистую производительность движка и gRPC-стека без ограничений физической сети

  • Параметры нагрузки: 32 параллельных клиентских потока по 100 000 операций на поток (всего 3,2 млн операций на тест)

  • Размер данных: Ключ — 150 байт, Значение — 500 байт

Тип операции

HurriCache (Без пайплайнинга)

Redis (Без пайплайнинга)

Redis (С пайплайном)

Чтение (Read)

85000 RPS

~5000 RPS

~60000 RPS

Запись (Write)

77000 RPS

~3000 RPS

~20000 RPS

Атомики (создание, чтение, инкремент, CAS)

~100000 RPS

Н/Д (требует Lua)

Н/Д

Смешанный тест (20% Create / 60% Read / 20% Update)

80 000 – 100 000 RPS (доп. порог ошибок до 15%) Заложена самим тестом

Примечание по кластеру: При тестировании кластерной конфигурации HurriCache показал практически линейный рост производительности по мере добавления новых нод благодаря маршрутизации на стороне SmartClient и отсутствию межнодовых пересылок запросов.

Примечание по контейнерам: В данном тестировании проверялись только базовые скалярные операции и атомики. Контейнерная часть (Lists, Sets, Maps) на текущий момент реализована функционально, но пока не проходила этап точечных низкоуровневых оптимизаций, поэтому ее бенчмарки будут опубликованы в следующих материалах.

Разбор результатов

  • Преимущество на записи: HurriCache показывает 77K RPS на запись против 3K RPS у Redis без пайплайна (и 20K RPS с пайплайном). Это следствие отсутствия глобального блокирующего словаря и эффективного применения prefetch вместе с lock-free структурами.

  • Стабильность на смешанной нагрузке: В профиле 20% Create / 60% Read / 20% Update HurriCache держит планку в 80K–100K RPS даже при жестком ограничении на допустимый порог ошибок (до 15%). Отсутствие глобального рехешинга сохраняет предсказуемую задержку при постоянной перезаписи и создании новых ключей.

  • Запас по атомикам: Нативные lock-free атомики выдерживают около 100K RPS за счет выполнения операций прямо на уровне процессора без накладных расходов на интерпретацию скриптов.

  • Пайплайнинг не требуется: HurriCache выдает производительность, превышающую пакетный Redis-пайплайнинг, работая при этом в честном синхронном режиме «запрос-ответ» благодаря асинхронным Completion Queues в gRPC.

Потенциальные потребители функционала

Изначально HurriCache разрабатывался под жесткие требования телеком-отрасли — систем онлайн-чарджинга (OCS) и биллинга, где от задержки списания средств зависит пропуск трафика в реальном времени. Впоследствии фокус проекта расширился на более широкий спектр high-load систем, сталкивающихся с ограничениями традиционных in-memory хранилищ на многоядерных серверах.

Основная целевая аудитория системы — инженеры и архитекторы с экстремальными требованиями к пропускной способности (RPS) и строгому соблюдению SLA по задержкам (p99/p99.9 latency).

1. Телеком, Системы Чарджинга и Биллинга (Real-Time OCS)

  • Проблема: Необходимость атомарно проверять и списывать баланс абонента за миллисекунды во время звонков или сессий передачи данных. Задержка или сбой приводит к некорректной тарификации либо обрыву связи.

  • Решение HurriCache: Нативные lock-free атомики и предсказуемая задержка без просадок на рехешинг позволяют обрабатывать высококонкурентные транзакции биллинга прямо в памяти с нулевым риском блокировки потоков.

2. High-Load и AdTech сервисы (Рекламные движки и Real-Time Bidding)

  • Проблема: Обработка миллионов аукционов в секунду требует миллисекундных ответов. Выбросы задержек (p99 latency spikes), вызванные фоновым рехешингом Redis или блокировками single-thread потока, приводят к пропуску ставок и прямой потере выручки.

  • Решение HurriCache: Lock-free структура Partitioned HashMap с предсказуемым профилем задержек и аппаратным ускорением SIMD/prefetch обеспечивает стабильный RPS без Stop-the-World просадок.

3. Финансовый сектор, Финтех и Торговые платформы

  • Проблема: Потребность в атомарных операциях без накладных расходов. В Redis реализация условной логики (CAS, списание/начисление лимитов, балансы) требует Lua-скриптов, которые выполняются блокирующим образом и режут общий throughput.

  • Решение HurriCache: Нативные аппаратные атомики (atomicCompareAndSet, atomicAdd, atomicExchange) позволяют строить распределенные безблокировочные алгоритмы (Lock-Free Data Structures) с производительностью порядка ~100K RPS на ноду.

4. Игровые бэкенды (Gamedev & Real-time Multiplayer)

  • Проблема: Высокая конкуренция за изменение состояния персонажей, игровых комнат, сессий и матчмейкинга в реальном времени.

  • Решение HurriCache: Встроенная поддержка гранулярных блокировок (READ_LOCK, WRITE_LOCK) на уровне отдельных объектов вместе с нативной Multi-tenancy позволяет безопасно и изолированно управлять состоянием игроков из сотен параллельных потоков.

5. Распределенные микросервисные архитектуры

  • Проблема: Перегрузка прокси-слоев (Envoy, HAProxy) и узлов базы данных из-за постоянной перемаршрутизации (rerouting) некорректно отправленных запросов.

  • Решение HurriCache: Использование SmartClient и KeyHint позволяет перенести всю тяжелую логику шардирования на сторону клиентского приложения, снижая сетевой оверхед (RTT) и утилизируя 100% ресурсов серверного железа исключительно на обработку данных.

6. Проекты, вертикально масштабирующие In-Memory инфраструктуру

  • Проблема: Современные серверы оснащаются 64+ ядрами CPU, однако однопоточные решения утилизируют только одно ядро, заставляя инженеров разворачивать десятки мелких инстансов Redis и усложнять эксплуатацию.

  • Решение HurriCache: Полноценная многопоточная архитектура на базе асинхронных gRPC Completion Queues масштабируется вертикально по ядрам CPU на одном узле, заменяя целый кластер традиционных single-threaded кэшей.

Модель распространения, лицензирование и поддержка

Модель дистрибуции HurriCache строится по принципу Open-Core / Commercial, строго разделяя ядро системы и экосистему клиентских библиотек.

1. Модель исходного кода и Open Source контрибьютинг

  • Код движка (Core): Исходный код самого сервера HurriCache на текущем этапе закрыт (Proprietary) для защиты проприетарных алгоритмов in-memory структуры данных.

  • Клиентские SDK (SmartClient): Код всех клиентских библиотек и коннекторов полностью открыт (Open Source). Сообщество приветствуется в качестве контрибьюторов — можно разрабатывать интеграции для новых языков программирования, улучшать алгоритмы роутинга и оптимизировать сетевой стек.

2. Редакции и варианты лицензий

  • Single-Node редакция (Community / Developer Edition):

    • Формат: Готовый, преднастроенный Docker-образ

    • Лицензия: Бесплатный контракт / EULA на коммерческое и некоммерческое использование.

    • Условия: Полнофункциональный single-node движок без искусственных ограничений по RPS, количеству тредов или памяти. Запрещен реверс-инжиниринг и перепродажа в виде управляемого SaaS-сервиса.

  • Cluster / Enterprise редакция (Distributed Edition):

    • Формат: Helm-чарты, приватный Docker Registry, нативные пакеты для корпоративных Linux-дистрибутивов. Возможны узкоспециализированные билды

    • Лицензия: Коммерческая Enterprise-лицензия (Per-Node / Per-Core).

    • Условия: Включает модули автоматической репликации (Replication Server), динамическую перемаршрутизацию, балансировку шардов и миграцию данных (Coordinator Server).

3. Модель технической поддержки

  • Community Support (для Single-Node и Open Source SDK):

    • Поддержка осуществляется через GitHub Issues.

    • Обработка багрепортов и предложений функционала происходят в порядке очереди без гарантированного SLA по времени ответа и исправления.

  • Enterprise Support (для кластерных пользователей):

    • Персональный выделенный канал связи и фиксированный SLA на реагирование и выкатку хотфиксов.

    • Прямые консультации по архитектуре, профилированию задержек и оптимизации клиентского кода.

Где попробовать и потестировать

Для тех, кому интересно покрутить HurriCache на собственных стендах, посмотреть исходный код клиентского SDK или провести самостоятельные нагрузочные тесты:

  • Java Client (SmartClient SDK): github.com/hurricache/hurricache-java-client

  • Single-Node Docker Image:

    docker pull docker.io/alexaborisov/fastcache-standalone:26.34
    docker pull docker.io/alexaborisov/fastcache-standalone:latest

Docker-образ буду обновлять по мере возможности и выхода свежих оптимизаций.

Буду рад любому фидбеку, issues и контрибьютам в репозиторий клиента на разных языках программирования!

Комментарии (0)