Redis и Nostr: кэширование событий

Redis и Nostr: кэширование событий

Redis и Nostr — это два мощных, но совершенно разных технологических решения. Redis — высокопроизводительная in-memory база данных, используемая для кэширования, очередей и хранения временных данных. Nostr («Notes and Other Stuff Transmitted by Relays») — децентрализованный протокол передачи событий, лежащий в основе социальных сетей нового поколения, таких как Damus или Amethyst. Связь между ними возникает на уровне ретрансляторов (relays), где Redis может эффективно кэшировать события Nostr, снижая нагрузку на диск и ускоряя доступ к часто запрашиваемым данным. Это особенно важно при масштабировании relays под высокую нагрузку.

Использование Redis для кэширования событий Nostr позволяет существенно повысить производительность ретранслятора за счёт быстрого доступа к горячим данным. Главная рекомендация — настроить TTL и стратегию eviction в Redis, чтобы избежать переполнения памяти.

Что такое Nostr и зачем ему кэширование

Nostr — это открытый, децентрализованный протокол, позволяющий пользователям публиковать и получать события без централизованного контроля. Каждое событие подписывается приватным ключом и передаётся через ретрансляторы (relays). Архитектура Nostr исключает необходимость доверия к серверам: пользователи сами проверяют подлинность событий по публичным ключам.
Однако, несмотря на свою простоту, Nostr сталкивается с проблемой производительности при увеличении числа запросов. Ретрансляторы должны отвечать на запросы фильтров (например, «покажи все события от публичного ключа X за последние 24 часа»), что требует частого обращения к хранилищу. При хранении всех событий в файловой системе или на медленном диске задержки могут достигать сотен миллисекунд.
Кэширование решает эту проблему. Часто запрашиваемые события (например, популярные публикации или активные профили) можно временно хранить в оперативной памяти. Это снижает время отклика с ~150 мс до ~2–5 мс. Учитывая, что пользовательские клиенты отправляют десятки запросов в секунду, выигрыш в скорости ощутим.

Полезно знать: В Nostr нет понятия «лайков» или «репостов» на уровне протокола — всё это реализуется через события с определёнными типами (kind). Самые частые — kind 1 (заметки), kind 3 (контакты), kind 7 (лайки).

Как работает ретранслятор в Nostr

Ретранслятор принимает события от клиентов, проверяет их подпись, сохраняет и рассылает подписчикам. Когда клиент запрашивает данные, relay ищет подходящие события по фильтрам. Без кэша каждый запрос требует сканирования файлов или SQL-запросов. При высокой нагрузке это быстро становится узким местом.

  • Клиент отправляет REQ с фильтром (например, по pubkey и времени)
  • Relay ищет события, соответствующие фильтру
  • Найденные события отправляются обратно по WebSocket
  • Новые события транслируются всем подписавшимся

Если один и тот же фильтр запрашивается многократно (например, главная лента клиента), логично закэшировать результат.

Роль Redis в обработке событий

Redis идеально подходит для кэширования событий Nostr благодаря своей скорости, гибкости и поддержке различных структур данных. Он работает полностью в памяти, обеспечивая микросекундные задержки при чтении и записи.
Основные преимущества Redis:

  • Поддержка TTL (времени жизни ключа) — автоматическое удаление устаревших событий
  • Структуры данных: строки, хэши, списки, множества — позволяют гибко организовать кэш
  • Atomic-операции — безопасны при одновременных запросах
  • Pub/Sub — можно использовать для внутренней синхронизации между процессами

Для Nostr чаще всего применяется модель кэширования по ключу события (event ID) и по фильтрам. Например:

  1. Событие с ID a1b2c3... сохраняется в Redis как строка: event:a1b2c3 → JSON
  2. Фильтр { "authors": ["pubkey_x"], "kinds": [1], "#d": ["thread_id"] } сериализуется в хэш и используется как ключ: filter:hash123 → массив event ID

Такой подход позволяет повторно использовать результаты запросов, если фильтр уже встречался.

«Кэшируйте не только полные события, но и агрегированные данные — например, количество лайков для заметки. Это снижает нагрузку при рендеринге интерфейса.» — Артем, инженер по распределённым системам

Пример структуры хранения в Redis

Тип данных
Ключ
Значение
TTL
Строка
event:
JSON события (kind, pubkey, created_at, tags, sig)
7 дней
Список
author_events:
Список ID событий автора (по убыванию времени)
24 часа
Множество
kind:1:hot
ID самых популярных заметок (по числу лайков)
1 час
Хэш
filter:
Массив ID событий, соответствующих фильтру
5 минут

Выбор TTL зависит от типа данных. Горячие фильтры могут жить короче (5–10 мин), а события — дольше (до нескольких дней).

Как настроить Redis для кэширования событий Nostr

Настройка Redis начинается с выбора конфигурации, соответствующей нагрузке ретранслятора. Для среднего relay (10–50 тыс. событий в день) достаточно одного экземпляра Redis с 2 ГБ RAM.

Шаг 1: Базовая конфигурация Redis

Откройте redis.conf и установите:

  • maxmemory 2gb — ограничение памяти
  • maxmemory-policy allkeys-lru — политика удаления: удалять наименее используемые ключи
  • timeout 300 — отключение неактивных клиентов
  • save "" — отключить RDB-сохранение, если кэш временный
  • appendonly yes — включить AOF для восстановления после сбоя (опционально)
Полезно знать: Если кэш используется только для ускорения чтения, а основное хранилище — надёжная СУБД или файлы, можно отключить постоянное хранение (RDB/AOF).

Шаг 2: Интеграция с Nostr relay

Большинство реализаций Nostr relay (например, nostr-rs-relay, iris, snort) позволяют подключать внешние хранилища. Ниже — пример псевдокода для интеграции:


// При получении нового события
onEventReceived(event) {
 const eventId = event.id;
 const key = `event:${eventId}`;
 redis.setex(key, 86400 * 7, JSON.stringify(event)); // 7 дней
 // Обновить списки авторов
 const authorKey = `author_events:${event.pubkey}`;
 redis.lpush(authorKey, eventId);
 redis.expire(authorKey, 86400); // 1 день
}
// При обработке REQ
onReq(filter) {
 const filterHash = hashFilter(filter);
 const cacheKey = `filter:${filterHash}`;
 const cached = redis.get(cacheKey);
 if (cached) {
 return JSON.parse(cached); // Вернуть из кэша
 }
 const results = db.queryEvents(filter); // Поиск в БД
 redis.setex(cacheKey, 300, JSON.stringify(results)); // 5 мин
 return results;
}

Шаг 3: Мониторинг и тюнинг

Используйте команды Redis CLI для анализа состояния:

  • INFO memory — объём используемой памяти, количество ключей
  • INFO stats — hit rate, количество запросов
  • KEYS * — не использовать на проде! Только для диагностики
  • MEMORY USAGE key — размер конкретного ключа

Ключевой метрикой является cache hit ratio — отношение успешных чтений из кэша к общему числу запросов. Целевой показатель — выше 70%. Ниже — сигнал к оптимизации TTL или структуры ключей.

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

Кэширование в Nostr особенно эффективно в следующих случаях:

  • Популярные события: когда заметка становится вирусной, сотни клиентов одновременно запрашивают её и связанные лайки. Кэш предотвращает «лавину» запросов к диску.
  • Активные профили: если пользователь имеет много подписчиков, его события часто запрашиваются. Хранение списка его заметок в Redis ускоряет загрузку профиля.
  • Общие фильтры: клиенты часто используют стандартные фильтры («последние 20 заметок», «лента друзей»). Их можно кэшировать по хэшу.

Кейс: масштабирование relay под 100K+ пользователей

Команда разработчиков одного из крупных relays столкнулась с ростом задержек до 800 мс при пиковой нагрузке. После внедрения Redis с кэшированием по фильтрам и event ID:

  • Среднее время ответа снизилось до 12 мс
  • Нагрузка на CPU упала на 40%
  • Hit ratio кэша составил 82%
Важно: они использовали шардирование Redis (несколько экземпляров) и маршрутизацию по типу данных — события в один шард, фильтры — в другой.
Полезно знать: Для высоконагруженных систем используйте Redis Cluster или хотя бы master-replica с Sentinel для отказоустойчивости.

Ошибки и как их избежать

Несмотря на простоту, кэширование в Nostr с Redis сопряжено с типичными ошибками.

Ошибка 1: Отсутствие TTL

Если ключи не имеют времени жизни, память будет расти бесконечно. При большом потоке событий это приведёт к OOM (out of memory) и падению Redis.
Решение: Всегда устанавливайте TTL, даже если событие «вечное». Например, 30 дней — разумный компромисс между свежестью и производительностью.

Ошибка 2: Кэширование слишком больших наборов

Фильтр вроде «все события kind=1 за последний год» может вернуть десятки тысяч ID. Сохранение такого массива в Redis займёт много памяти и замедлит запись.
Решение: Ограничьте размер кэшируемых результатов (например, первые 1000 событий) или не кэшируйте такие «тяжёлые» запросы вообще.

Ошибка 3: Несогласованность кэша

Если событие было удалено (через kind=5 — deletion) или обновлено (replaceable events), старая версия может остаться в кэше.
Решение: При получении события удаления — очистить из кэша все связанные ключи:


if (event.kind === 5) {
 event.tags.filter(t => t[0] === 'e').forEach(ref => {
 redis.del(`event:${ref[1]}`);
 });
}

Экспертное мнение

Кэширование — не панацея, а инструмент. Его стоит применять осознанно, с учётом специфики нагрузки. В случае с Nostr, где данные публичные и часто повторяются, Redis даёт максимальный эффект.
Главный принцип: кэшируйте то, что часто читается и редко меняется. Заметки, профили, лайки — идеальные кандидаты. Временные фильтры или единичные запросы — нет.
Также важно не игнорировать долгосрочную стратегию. Кэш должен дополнять, а не заменять основное хранилище. Даже самый быстрый Redis не спасёт от плохой индексации в базе данных.
При проектировании relay всегда тестируйте производительность с нагрузкой, близкой к реальной. Используйте инструменты вроде nostr-bench для симуляции тысяч клиентов.

Вопросы и ответы

Можно ли использовать Memcached вместо Redis?
Да, но с потерями. Memcached проще и быстрее для простых ключ-значение операций, но не поддерживает списки, TTL на уровне операций и Pub/Sub. Для сложной логики Nostr Redis предпочтительнее.
Как часто нужно обновлять кэш?
Кэш обновляется автоматически при изменении данных. При получении нового события — оно добавляется в кэш. При удалении — удаляется. Не нужно ручного обновления.
Безопасно ли хранить события в Redis?
Да. Все события в Nostr публичны и проверяются по подписи. Даже если Redis скомпрометирован, злоумышленник не может подделать данные — клиенты это обнаружат.
Нужен ли Redis для маленького relay?
Не обязательно. Если у вас до 1K событий в день и мало клиентов, встроенное кэширование (например, в памяти процесса) может быть достаточным. Redis нужен при масштабировании.

Заключение

Кэширование событий Nostr с помощью Redis — это мощный способ повысить отзывчивость ретранслятора и снизить нагрузку на систему. Правильно настроенный Redis может уменьшить задержки в 10–50 раз, особенно при работе с популярным контентом.
Важно понимать, что кэш — это дополнение к архитектуре, а не замена. Он эффективен только при грамотной стратегии хранения, контроле памяти и синхронизации с основным хранилищем.

Интеграция Redis в Nostr relay требует внимания к деталям: выбор TTL, структура ключей, политика eviction. Но при правильной реализации вы получаете высокопроизводительный, масштабируемый сервис, способный выдерживать серьёзные нагрузки.
  • Redis идеально подходит для кэширования событий Nostr благодаря скорости и гибкости
  • Кэшируйте события, фильтры и агрегированные данные с разумным TTL
  • Следите за hit ratio — целевой показатель выше 70%
  • Очищайте кэш при удалении или обновлении событий
  • Тестируйте производительность под реальной нагрузкой
⚠️ Дисклеймер — нажмите, чтобы развернуть

Материалы, опубликованные в разделе «Блог» на сайте RU DESIGN SHOP (rudesignshop.ru), носят исключительно информационный и ознакомительный характер и не являются руководством к действию, финансовой рекомендацией, медицинской услугой, ветеринарным назначением либо рекламой товаров и услуг, включая азартные игры. Публикации не содержат призывов к участию в азартных играх и не направлены на продвижение соответствующих операторов.

Безопасность применения товаров и веществ: при использовании строительных материалов, бытовой химии, пестицидов и агрохимикатов необходимо строго следовать инструкциям производителя и действующему законодательству Российской Федерации, включая Федеральный закон РФ от 19.07.1997 № 109-ФЗ «О безопасном обращении с пестицидами и агрохимикатами».

Упоминание товарных знаков, брендов и организаций носит исключительно информационный характер и не означает наличие партнёрских отношений или одобрения со стороны правообладателей.

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

Возрастные ограничения: материалы, содержащие сведения о продукции категории 18+, включая алкоголь или азартные игры, предназначены исключительно для совершеннолетней аудитории и публикуются в информационных целях.

Правовая ответственность: решения, принятые на основе опубликованной информации, пользователь принимает самостоятельно и на свой риск; редакция и авторы несут ответственность в пределах, установленных законодательством Российской Федерации.

Редакция не допускает публикаций, содержащих пропаганду экстремизма, терроризма, наркотических средств или суицида; подобные материалы подлежат немедленному удалению.

Упоминание организаций с ограниченным статусом: компания Meta Platforms Inc. (социальные сети Facebook и Instagram) признана экстремистской организацией решением суда РФ, её деятельность запрещена на территории Российской Федерации; любые упоминания приводятся исключительно в информационных целях.

Авторские права и источники: информация собирается из открытых источников; её актуальность указывается на дату публикации и может изменяться.

Изображения и иллюстрации используются на условиях, разрешённых правообладателями. При возникновении претензий редакция готова оперативно рассмотреть обращение и внести необходимые изменения.

Персональные данные и cookies: сайт использует cookies и обрабатывает персональные данные пользователей в соответствии с Федеральным законом № 152-ФЗ «О персональных данных» и Политикой конфиденциальности RU DESIGN SHOP.

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