Redis и Nostr: кэширование событий
Redis и Nostr — это два мощных, но совершенно разных технологических решения. Redis — высокопроизводительная in-memory база данных, используемая для кэширования, очередей и хранения временных данных. Nostr («Notes and Other Stuff Transmitted by Relays») — децентрализованный протокол передачи событий, лежащий в основе социальных сетей нового поколения, таких как Damus или Amethyst. Связь между ними возникает на уровне ретрансляторов (relays), где Redis может эффективно кэшировать события Nostr, снижая нагрузку на диск и ускоряя доступ к часто запрашиваемым данным. Это особенно важно при масштабировании relays под высокую нагрузку.
- Что такое Nostr и зачем ему кэширование
- Как работает ретранслятор в Nostr
- Роль Redis в обработке событий
- Пример структуры хранения в Redis
- Как настроить Redis для кэширования событий Nostr
- Шаг 1: Базовая конфигурация Redis
- Шаг 2: Интеграция с Nostr relay
- Шаг 3: Мониторинг и тюнинг
- Практические сценарии использования
- Кейс: масштабирование relay под 100K+ пользователей
- Ошибки и как их избежать
- Ошибка 1: Отсутствие TTL
- Ошибка 2: Кэширование слишком больших наборов
- Ошибка 3: Несогласованность кэша
- Экспертное мнение
- Вопросы и ответы
- Заключение
Что такое Nostr и зачем ему кэширование
Nostr — это открытый, децентрализованный протокол, позволяющий пользователям публиковать и получать события без централизованного контроля. Каждое событие подписывается приватным ключом и передаётся через ретрансляторы (relays). Архитектура Nostr исключает необходимость доверия к серверам: пользователи сами проверяют подлинность событий по публичным ключам.
Однако, несмотря на свою простоту, Nostr сталкивается с проблемой производительности при увеличении числа запросов. Ретрансляторы должны отвечать на запросы фильтров (например, «покажи все события от публичного ключа X за последние 24 часа»), что требует частого обращения к хранилищу. При хранении всех событий в файловой системе или на медленном диске задержки могут достигать сотен миллисекунд.
Кэширование решает эту проблему. Часто запрашиваемые события (например, популярные публикации или активные профили) можно временно хранить в оперативной памяти. Это снижает время отклика с ~150 мс до ~2–5 мс. Учитывая, что пользовательские клиенты отправляют десятки запросов в секунду, выигрыш в скорости ощутим.
Как работает ретранслятор в Nostr
Ретранслятор принимает события от клиентов, проверяет их подпись, сохраняет и рассылает подписчикам. Когда клиент запрашивает данные, relay ищет подходящие события по фильтрам. Без кэша каждый запрос требует сканирования файлов или SQL-запросов. При высокой нагрузке это быстро становится узким местом.
- Клиент отправляет
REQс фильтром (например, по pubkey и времени) - Relay ищет события, соответствующие фильтру
- Найденные события отправляются обратно по WebSocket
- Новые события транслируются всем подписавшимся
Если один и тот же фильтр запрашивается многократно (например, главная лента клиента), логично закэшировать результат.
Роль Redis в обработке событий
Redis идеально подходит для кэширования событий Nostr благодаря своей скорости, гибкости и поддержке различных структур данных. Он работает полностью в памяти, обеспечивая микросекундные задержки при чтении и записи.
Основные преимущества Redis:
- Поддержка TTL (времени жизни ключа) — автоматическое удаление устаревших событий
- Структуры данных: строки, хэши, списки, множества — позволяют гибко организовать кэш
- Atomic-операции — безопасны при одновременных запросах
- Pub/Sub — можно использовать для внутренней синхронизации между процессами
Для Nostr чаще всего применяется модель кэширования по ключу события (event ID) и по фильтрам. Например:
- Событие с ID
a1b2c3...сохраняется в Redis как строка:event:a1b2c3→ JSON - Фильтр
{ "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 для восстановления после сбоя (опционально)
Шаг 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%
Ошибки и как их избежать
Несмотря на простоту, кэширование в 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 для симуляции тысяч клиентов.
Вопросы и ответы
Заключение
Кэширование событий Nostr с помощью Redis — это мощный способ повысить отзывчивость ретранслятора и снизить нагрузку на систему. Правильно настроенный Redis может уменьшить задержки в 10–50 раз, особенно при работе с популярным контентом.
Важно понимать, что кэш — это дополнение к архитектуре, а не замена. Он эффективен только при грамотной стратегии хранения, контроле памяти и синхронизации с основным хранилищем.
- 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.
Мнения авторов могут не совпадать с позицией государственных органов или коммерческих организаций, упомянутых в материалах.