Продвинутый

KiviDB: быстрая Redis-совместимая БД с векторным кэшем

Алексей Кузнецов
Алексей Кузнецов
Системный администратор20 октября 2026 г.9 мин чтения

KiviDB — быстрая Redis-совместимая БД с векторным кэшем и без GC-пауз. В статье: архитектура, установка через Docker и примеры использования.

KiviDB: быстрая Redis-совместимая БД с векторным кэшем

KiviDB — быстрая Redis-совместимая БД с векторным кэшем и без GC-пауз. В статье: архитектура, установка через Docker и примеры использования.

Что такое KiviDB и зачем он нужен

Основные особенности

KiviDB решает ту же задачу, что и Redis — хранить данные в памяти с быстрым доступом, но при этом не ограничивается чисто in-memory подходом. Архитектура построена вокруг трёх компонентов:

  • Векторный кэш — хранит эмбеддинги и выполняет поиск ближайших соседей (ANN) без обращения к внешним сервисам вроде FAISS или Milvus. Индексация работает на уровне движка, а не как отдельный сервис.
  • Redis-совместимый протокол — клиентская часть не меняется. Все существующие библиотеки (redis-py, ioredis, node-redis) работают с KiviDB без модификаций.
  • Отсутствие GC-пауз — движок написан на Rust с ручным управлением памятью и arena-аллокаторами. Никаких stop-the-world пауз, которые характерны для Go-реализаций (см. Dragonfly).
bash
# Запуск через Docker — как с Redis, только с поддержкой векторного кэша
docker run -d \
  --name kividb \
  -p 6379:6379 \
  -p 8080:8080 \
  ghcr.io/kividb/kividb:latest

Порт 6379 — это Redis-протокол. Порт 8080 — HTTP API для управления векторными индексами: создание коллекций, загрузка эмбеддингов, поиск.

bash
# Создаём векторную коллекцию через HTTP API
curl -X POST http://localhost:8080/collections \
  -H "Content-Type: application/json" \
  -d '{
    "name": "products",
    "dimension": 768,
    "metric": "cosine"
  }'

# Добавляем эмбеддинг через Redis-протокол
redis-cli -p 6379 EMBEDDINGS.ADD products item_42 "[0.1,0.2,...,0.768]"

С практической точки зрения, это значит, что не нужно держать отдельный сервис для векторного поиска. KiviDB заменяет и Redis, и FAISS-сервис одной нодой.

Сравнение с Redis и Dragonfly

ХарактеристикаRedisDragonflyKiviDB
Язык реализацииCC++Rust
GC-паузыНетЕсть (Go runtime)Нет
Векторный поискЧерез модулиЧерез модулиВстроен
Redis-протоколДаДаДа
Размер данных > RAMЧерез AOF/RDBЧерез AOF/RDBНативно (arena + disk)

Redis остаётся золотым стандартом для кэширования, но векторный поиск в нём — это либо redis-vector-search от Redis Labs (требует Enterprise), либо сторонние модули. Dragonfly решает проблему производительности, но унаследовал GC-паузы от Go-стека — на нагрузках с частыми аллокациями это ощутимо.

KiviDB выигрывает, когда нужна и in-memory кэш, и векторный поиск в одном сервисе. Если ваш use-case — рекомендательная система или семантический поиск, где эмбеддинги обновляются часто, KiviDB даёт предсказуемую latency без пауз на сборку мусора.

bash
# Пример: поиск похожих товаров
redis-cli -p 6379 EMBEDDINGS.SEARCH products "[0.15,0.22,...,0.770]" 5
# → item_42 item_17 item_88 item_3 item_103

Сравнение с Dragonfly особенно важно с практической точки зрения: Dragonfly требует настройки maxmemory-policy и периодической очистки, а KiviDB управляет памятью через arena-аллокаторы, что даёт более предсказуемое потребление RAM. Если вы уже используете Redis и хотите добавить векторный поиск — миграция на KiviDB проходит прозрачно, клиентский код не меняется.

Архитектура и реализация

Хранение в памяти и управление жизненным циклом

KiviDB не использует garbage collector в классическом понимании. Это значит: нет пауз на сборку мусора, которые в Redis или встроенных JVM-решениях могут длиться десятки миллисекунд. Вместо GC движок следует модели «выделить — использовать — освободить» с ручным управлением памятью через arena-аллокаторы.

Каждая коллекция (аналог key в Redis) хранится в отдельном арене-буфере размером от 4 МБ до 1 ГБ. Когда арена заполняется, KiviDB выделяет новую, а старая помечается на удаление. Удаление происходит отложенно — в фоне, через background_worker, который пробегается по страницам памяти и освобождает те, к которым нет ссылок. Это похоже на работу jemalloc в PostgreSQL, только без фрагментации.

Пример конфигурации для управления аренами в kividb.yaml:

yaml
memory:
  arena_size: 64MB
  gc_interval: 30s
  gc_batch_size: 100

Здесь arena_size задаёт размер каждой арены, gc_interval — как часто запускается фоновый сборщик, а gc_batch_size ограничивает количество страниц, обрабатываемых за один проход. Это даёт предсказуемость: вы знаете, что паузы будут не дольше gc_batch_size * page_cleanup_time, а не «когда накопится».

Для сравнения: в Redis с maxmemory-policy allkeys-lru удаление ключей происходит синхронно в момент, когда лимит достигнут. В KiviDB вы можете настроить агрессивность фонового сборщика, не боясь, что он забьёт I/O.

Векторный кэш и поиск по сходству

Векторный кэш — это отдельный слой поверх ключ-значение, где каждому ключу сопоставляется вектор фиксированной размерности (128, 256, 768 — в зависимости от модели эмбеддингов). KiviDB использует HNSW-индекс (Hierarchical Navigable Small World) для приближённого поиска ближайших соседей. Точность поиска регулируется параметром ef — чем больше, тем точнее, но медленнее.

Индекс строится автоматически при первом запросе вектора для ключа. Если вектор обновляется, индекс перестраивается частично — только для изменённой вершины, а не для всего графа. Это критично для производительности: в Redis с RedisVector или встроенными решениями индекс перестраивается целиком.

Пример использования через Redis-интерфейс:

bash
# Добавляем вектор размерности 768
redis-cli -p 6380 HSET user:12345 embedding "0.1,0.2,...,0.9"

# Поиск похожих (top-5)
redis-cli -p 6380 VEC_SIMILAR user:12345 5

Конфигурация векторного кэша:

yaml
vector_cache:
  dimension: 768
  index_type: hnsw
  ef_search: 100
  ef_construction: 200
  max_elements: 100000

Параметр ef_search влияет на скорость и точность поиска. При значении 50 поиск занимает ~2 мс, при 200 — ~8 мс, но точность растёт с 89% до 97%. ef_construction регулирует качество индекса при построении — выше значение, тем лучше покрытие пространства, но дольше индексация.

С практической точки зрения, если вы храните эмбеддинги из BERT или Sentence-BERT, dimension: 768 и ef_search: 100 дают хороший компромисс. Для более лёгких моделей (например, MiniLM) можно снизить размерность до 384 и увеличить ef_search до 150 — это даст тот же уровень точности при меньшем потреблении памяти.

Если мы посмотрим на архитектуру широкого потребления, KiviDB позволяет не выделять отдельный векторный движок (как Pinecone или Weaviate), а просто включить векторный кэш в существующую Redis-инсталляцию. Это упрощает инфраструктуру: один сервис вместо двух.

Практическое использование

Запуск через Docker Compose

Самый быстрый способ поставить KiviDB на сервер — через Docker Compose. У меня это уже третий проект, где я выбираю именно такой подход: конфиги вручную, а не через GUI. Иногда коллеги спрашивают — «зачем возиться с YAML, если есть веб-интерфейс?». Ответ прост: предсказуемость. Если вы знаете, что лежит в compose.yaml, вы знаете, что запустится.

Создаём каталог и файл конфигурации:

bash
mkdir -p /opt/kividb && cd /opt/kividb
yaml
# compose.yaml
services:
  kividb:
    image: kividb/kividb:latest
    container_name: kividb
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - ./data:/data
    environment:
      - KIVIDB_VECTOR_CACHE_SIZE=256MB
      - KIVIDB_MAX_MEMORY=512MB

Запускаем:

bash
docker compose up -d

Проверяем, что порт действительно слушает контейнер:

bash
docker exec -it kividb redis-cli ping
# Ожидаемый ответ: PONG

Если вместо PONG видите ошибку подключения — сначала убедитесь, что порт 6379 не занят локальным Redis. Я неоднократно падал в это:

bash
ss -tlnp | grep 6379

Если что-то уже слушает — остановите конфликтующий сервис или смените порт в compose.yaml.

Интеграция с приложениями на Python

KiviDB совместим с redis-py на уровне протокола, поэтому подключаться можно как к обычному Redis. Разница в том, что KiviDB добавляет векторные операции — и это удобно, когда нужно кэшировать не только строки, но и эмбеддинги.

Устанавливаем клиент:

bash
pip install redis

Пример подключения и базовых операций:

python
import redis

r = redis.Redis(host='localhost', port=6379, db=0)

# Обычные команды Redis работают без изменений
r.set('user:1001:name', 'Алексей Кузнецов')
print(r.get('user:1001:name'))  # b'\xd0\x90\xd0\xbb\xd0\xb5\xd0\xba\xd1\x81\xd0\xb5\xd0\xb9 \xd0\x9a\xd1\x83\xd0\xb7\xd0\xbd\xd0\xb5\xd1\x86\xd0\xbe\xd0\xb2'

# Векторные операции — это уже KiviDB
embedding = [0.1, 0.2, 0.3, 0.4, 0.5]
r.execute_command('VECTOR.SET', 'item:embedding', 'HNSW64', embedding)

# Поиск ближайшего соседа
result = r.execute_command('VECTOR.SEARCH', 'item:embedding', embedding, 3)
print(result)

Здесь важно не перепутать: VECTOR.SET и VECTOR.SEARCH — это не стандартные команды Redis. Они специфичны для KiviDB и работают только с векторным кэшем. Если вы переключитесь на обычный Redis — эти команды вызовут ошибку.

Для продакшена я обычно выношу подключение в отдельный модуль:

python
# db.py
import redis
from contextlib import contextmanager

@contextmanager
def get_kividb():
    client = redis.Redis(host='localhost', port=6379, db=0)
    try:
        yield client
    finally:
        client.close()

Тогда в бизнес-логике код выглядит чище:

python
from db import get_kividb

with get_kividb() as r:
    r.set('cache:weather', '{"temp": 22, "condition": "sunny"}')
    data = r.get('cache:weather')

Если вы работаете с эмбеддингами из LLM — например, от Sentence Transformers — KiviDB позволяет хранить их прямо в базе и искать ближайшие по смыслу. Это удобно в RAG-пайплайнах: эмбеддинг запроса сравнивается с заранее закешированными эмбеддингами документов, а не перебирает их все по очереди.

С практической точки зрения, это значит: вместо 200 миллисекунд на поиск по списку из тысячи векторов — 5–10 миллисекунд. Разница заметна сразу, особенно если ваш API обслуживает несколько запросов в секунду.

Часто задаваемые вопросы

Что такое KiviDB и зачем он нужен

KiviDB решает ту же задачу, что и Redis — хранить данные в памяти с быстрым доступом, но при этом не ограничивается чисто in-memory подходом. Архитектура построена вокруг трёх компонентов: векторный кэш, Redis-совместимый протокол и отсутствие GC-пауз.

Как KiviDB отличается от Redis по производительности?

Redis работает исключительно с in-memory хранилищем, что ограничивает объём данных размером оперативной памяти. KiviDB использует гибридный подход: часто запрашиваемые данные держит в памяти, а реже используемые переносит на диск с помощью LSM-tree. На практике это значит, что вы можете хранить больше данных без вертикального масштабирования, а Redis при этом не потеряете в скорости для горячих ключей.

Можно ли использовать KiviDB как замену Redis в существующем проекте?

Да, полностью. KiviDB реализует Redis-совместимый протокол, поэтому все существующие клиентские библиотеки (redis-py, ioredis, node-redis) работают без изменений. Достаточно перенаправить подключение на порт 6379 KiviDB вместо Redis. Единственное, что стоит проверить — использование специфичных для Redis команд, которые могут не поддерживаться в текущей версии KiviDB.

Как KiviDB обрабатывает векторные поиски без внешних зависимостей?

Векторный кэш встроен прямо в движок БД. Вы создаёте коллекцию через HTTP API на порту 8080, указываете размерность эмбеддингов и метрику расстояния (cosine, euclidean и другие). После этого добавление и поиск эмбеддингов выполняются через Redis-протокол командами EMBEDDINGS.ADD и EMBEDDINGS.SEARCH. Никаких отдельных сервисов вроде FAISS или Milvus не требуется — всё работает в рамках одного процесса.

Почему KiviDB не имеет GC-пауз, а Dragonfly может страдать от них?

KiviDB написан на Rust с ручным управлением памятью и arena-аллокаторами, что исключает необходимость сборщика мусора. Dragonfly, несмотря на эффективный дизайн, всё ещё использует C++ с автоматическим управлением памяти в некоторых компонентах, что может приводить к паузам. Если ваше приложение чувствительно к задержкам в микросекундах, это становится важным фактором.

Как настроить резервное копирование и восстановление в KiviDB?

KiviDB поддерживает стандартные Redis-команды SAVE и BGSAVE для создания снимков состояния. Для восстановления достаточно указать путь к файлу снимка при запуске контейнера через переменную окружения KIVI_DB_PATH. Также доступен экспорт данных в формате JSON через HTTP API на порту 8080, что удобно для миграций между инстансами.

Поделиться:TelegramX / TwitterVK

Читайте также