# Valkey: кеш PHP и Node.js

Восемь опытов с настоящим Valkey 9.0.7: cache-aside, общий JSON-контракт, TTL, инвалидация, negative cache, конкурентный промах, eviction и fallback. На странице мастерской показана запись выполнения. В архиве команды исполняются заново. Основной источник — небольшая вымышленная модель товара; настоящая база данных не подключена.

## Требования

Node.js 24 LTS не ниже24.15; PHP8.2+ с JSON; Composer2; Docker Engine/Desktop с Compose и Linux containers. Зафиксированы redis npm6.3.1, Predis3.7.1, Bootstrap5.3.9. Lock-файлы входят в архив. Valkey использует BSD-3-Clause, авторский код MIT; лицензии зависимостей сохраняются.

## Посмотреть мастерскую без Valkey

Из корня распакованного проекта:

```text
node tools/serve.mjs
```

Откройте http://127.0.0.1:8523. Для просмотра готовой public не нужны npm install, PHP и Docker. Это только просмотр ранее записанных результатов.

## Windows / PowerShell

Установите Node.js LTS, PHP и Composer из официальных источников, включите Linux containers в Docker Desktop. Затем:

```powershell
npm ci --ignore-scripts
composer install --no-interaction --no-plugins --prefer-dist
node tools/prepare.mjs
docker compose up -d --wait valkey
php php/capture.php
npm test
npm run capture
npm run verify
npm run build
node tools/serve.mjs
```

Каждая команда должна завершиться успешно до следующей. `prepare` генерирует уникальный пароль и ACL в `.runtime`, не выводя секрет в консоль. Повтор сохраняет существующий пароль. Не публикуйте `.runtime`, vendor, node_modules и локальные env-файлы. Упакованный пример не содержит сгенерированного пароля.

`capture` разрешает только этот отдельный стенд на loopback8540 или внутреннем имени valkey. База должна быть пустой. Опыт памяти временно меняет maxmemory/policy и восстанавливает их в finally, поэтому его нельзя направлять на рабочий или общий сервер. Команды не используют FLUSHALL/FLUSHDB. Очистка удаляет только созданные ключи случайного префикса. Если запуск был прерван, безопаснее пересоздать именно свой одноразовый контейнер без сохранения данных: `docker compose down`, затем `docker compose up -d --wait valkey`.

## Полезный одиночный пример

После запуска стенда выполните:

```powershell
node examples/product.mjs 42
php examples/product.php 42
node examples/product.mjs 999
```

Node сохраняет JSON для `demo:v1:service-a:product:42`, PHP читает тот же ключ. Цена хранится в копейках. Неизвестный ID получает короткий negative cache. `source` показывает origin/hit/negative-hit. Замените callback основного источника своим repository, а не HTML-строкой интерфейса. Ошибки источника не превращаются в «товар не найден».

После одиночного примера дождитесь TTL60секунд или удалите только его ключи через свой ACL-клиент, прежде чем повторять capture: проверка пустоты намеренно защищает от запуска эксперимента памяти на чужих данных.

## Linux

На Debian/Ubuntu установите Docker Engine с Compose по инструкции Docker и PHP CLI/Composer подходящей версии. Node.js установите из официальной поставки или принятого менеджера версий. Проверка:

```bash
node --version
php --version
composer --version
docker compose version
npm ci --ignore-scripts
composer install --no-interaction --no-plugins --prefer-dist
node tools/prepare.mjs
docker compose up -d --wait valkey
php php/capture.php
npm test
npm run capture
npm run verify
npm run build
node tools/serve.mjs
```

Без локального PHP/Node runtime после подготовки зависимостей можно повторить вычисления в фиксированных Linux-контейнерах:

```bash
docker compose run --rm linux-php
docker compose run --rm linux-node
```

Первый сохраняет `public/php-result-linux.json`, второй — `public/recording-linux.json`. На Linux PHP можно установить зависимости отдельно Composer до запуска контейнера. Composer vendor в этом проекте — обычный переносимый PHP-код; версии проверяются lock. Linux node runner использует тот же каталог и выполняет npm ci, поэтому не запускайте одновременно другие npm-команды в нём. Публичная мастерская читает `recording.json`; отдельный Linux-файл служит подтверждением повторяемости.

## Что проверяется

8 сетевых опытов и28 проверок в capture; PHP отдельно подтверждает5 условий; node:test проверяет разделение ключей, валидацию JSON и сохранение ошибки источника. Конкурентный опыт —12 одновременных вызовов одного Node-процесса: без координации12 чтений источника, с SET NX и проверкой владельца1. Это не доказательство отказоустойчивой распределённой блокировки. Опыт fallback устанавливает настоящее неудачное подключение к закрытому временному порту собственного loopback.

Число вытесненных ключей и PTTL могут немного различаться между ОС и запусками. Проверяются свойства, не одинаковые миллисекунды: ключ истёк, новая ревизия видна, источник не вызван лишний раз, eviction произошёл, OOM обработан. Шесть файлов реализации связываются с записью по SHA-256; после их изменения повторите capture и verify.

## Остановка и сервер

```text
docker compose down
```

Останавливается только aen-valkey-b19. Данные здесь одноразовые, persistence отключена, отдельного тома нет. Не выполняйте глобальный Docker prune для остановки примера. Для реального Linux/VPS прочитайте `docs/LINUX-VPS.md`: сеть, отдельный ACL приложения, systemd, память, мониторинг и восстановление после холодного старта.

Источники: https://valkey.io/download/ · https://valkey.io/topics/lru-cache/ · https://valkey.io/topics/security/ · https://github.com/redis/node-redis · https://github.com/predis/predis
