gRPC key-value хранилище на Java 21 + Spring Boot 3.4. Ключи строки, значения произвольные байты, включая null. Под капотом Tarantool 3.2
docker compose up --buildСервис на localhost:9090. Нужен только Docker
| Метод | Описание |
|---|---|
Put(key, value?) |
Записать пару. value необязательный, можно хранить null |
Get(key) |
Прочитать. NOT_FOUND если ключа нет |
Delete(key) |
Удалить |
Range(key_since, key_to) |
Стриминг пар в диапазоне включительно |
Count() |
Количество записей |
Пустой или пробельный ключ возвращает INVALID_ARGUMENT. Всё остальное INTERNAL
# "d29ybGQ=" = "world" в base64
grpcurl -plaintext -d '{"key":"hello","value":{"value":"d29ybGQ="}}' localhost:9090 kv.KvService/Put
grpcurl -plaintext -d '{"key":"nullable-key"}' localhost:9090 kv.KvService/Put
grpcurl -plaintext -d '{"key":"hello"}' localhost:9090 kv.KvService/Get
grpcurl -plaintext -d '{"key":"hello"}' localhost:9090 kv.KvService/Delete
grpcurl -plaintext -d '{"key_since":"a","key_to":"z"}' localhost:9090 kv.KvService/Range
grpcurl -plaintext -d '{}' localhost:9090 kv.KvService/CountВ proto3 обычный bytes не отличает "не передан" от "пустой". Для null нужен google.protobuf.BytesValue: hasValue() == false это NULL в Tarantool, hasValue() == true с пустым payload это byte[0]. Разные вещи
Range читает батчами по 1000 через Lua eval() с итераторами GE/GT, курсор это последний ключ предыдущего батча. Для этого нужен TREE-индекс. Tarantool по дефолту создаёт HASH, который range-запросы не поддерживает, поэтому индекс создаётся явно при старте
Virtual threads включены в Spring и отдельно в Netty-конфиге gRPC-сервера. grpc-spring-boot-starter сам не переключается, нужен GrpcServerConfigurer с явным executor
Спейс инициализируется при старте с 15 попытками. В Docker Compose Tarantool поднимается параллельно с приложением
./gradlew testUnit + integration через Testcontainers. Load-тесты отдельно, они долгие:
./gradlew loadTest -Dkv.load.records=5000000test на каждый push и PR. deploy только на main, собирает образ, пушит в GHCR с тегами latest и <sha>, заливает конфиги на VPS, перезапускает только kv-service. Tarantool не трогает. В конце smoke-check: Count через grpcurl с VPS
Нужные секреты: VPS_HOST, VPS_USER, VPS_SSH_KEY, TARANTOOL_PASSWORD. Опциональные: VPS_SSH_PASSPHRASE, VPS_SSH_PORT, GHCR_PAT (только для приватного репо)
Откат по sha:
KV_SERVICE_IMAGE=ghcr.io/<owner>/<repo>:<old-sha> \
TARANTOOL_PASSWORD='...' \
docker compose -f docker-compose.prod.yml up -d --no-deps kv-service