リレーの運用

nostrfy リレーの運用:起動と停止、ログと統計、設定のホットリロード、複数インスタンス、大規模チューニング。

起動と停止

リレーをバックグラウンドのデーモンとして起動します:

sh
nostrfy --config nostrfy.toml start

=> nostrfy started (pid 12345)

またはターミナルでフォアグラウンド実行:

sh
nostrfy --config nostrfy.toml start --foreground

停止:

sh
nostrfy --config nostrfy.toml stop

起動を確認:

sh
curl http://127.0.0.1:8080/health

=> {"status":"ok"}

ログと統計

デーモンは次のファイルに書き込みます: daemon.log_file。ファイルが max_log_size_bytes を超えると自動的にローテーションします(nostrfy.log.1、.2……最大 max_log_files 世代):

sh
tail -f nostrfy.log

ログレベルは RUST_LOG 環境変数で制御します(例: RUST_LOG=debug)。

統計

CLI からライブ統計を取得:

sh
nostrfy stats

または HTTP 経由:

sh
curl http://127.0.0.1:8080/relay/stats

接続数、承認/拒否されたイベント、DB サイズなどが表示されます。

Prometheus メトリクス

sh
curl http://127.0.0.1:8080/metrics

ホットリロード(SIGHUP)

設定ファイルを編集したら、再起動せずにリロードできます:

sh
kill -HUP $(cat nostrfy.pid)
リロード時に有効再起動が必要
リレー ID、public_urlprivate_key
大部分の [limits]、reject_ephemeral、enabled_git、enabled_nip78_authapi_host、metrics_enabled、LiveKit 設定
—enabled_nips / disabled_nips、server.host / port / ws_paths
—database.*(search_index を含む)、blossom.*

再起動が必要な設定が変更されると、ログが警告します。

複数インスタンスの実行

nostrfy は 1 台のサーバーで複数の独立したリレー(異なるポート)を実行できます。各インスタンスには独自の server.port、[daemon] の pid_file/log_file/stats_file (共有すると 2 番目のインスタンスが already running で拒否されます)、 database.path、および(使用する場合)独自の api_host / blossom.host:

toml
[server]
port = 8080

[database]
path = "/var/lib/nostrfy-a"

[daemon]
pid_file = "/var/run/nostrfy-a.pid"
log_file = "/var/log/nostrfy-a.log"
stats_file = "/var/lib/nostrfy-a/stats.json"

[server]
port = 8081

[database]
path = "/var/lib/nostrfy-b"

[daemon]
pid_file = "/var/run/nostrfy-b.pid"
log_file = "/var/log/nostrfy-b.log"
stats_file = "/var/lib/nostrfy-b/stats.json"

各インスタンスは独自の設定で管理します:nostrfy --config /etc/nostrfy/a.toml start など。

大規模デプロイ

このリレーは単一ホストで数十万接続まで拡張できるよう設計されています — ライブ配信はイベントに一致し得る購読者だけを起こし、接続あたりのメモリは小さく保たれます。数百万規模にはホストレベルのチューニングが必要です:

設定値理由
ulimit -n / systemd LimitNOFILE目標接続数の 2 倍以上(+1000)接続ごとに fd を 1 つ消費します
net.core.somaxconn≥ 1024接続バースト時の保留 accept キュー
net.ipv4.tcp_fin_timeout低くする(例:10)TIME_WAIT ソケットをより早く回収
vm.overcommit_memory1 または 2LMDB マップは大きなスパース仮想予約です

FreeBSD では、対応するパラメータは kern.maxfiles / kern.maxfilesperproc と ulimit -n で、kern.ipc.somaxconn が net.core.somaxconn に対応します。1 接続あたりのカーネルメモリは約 80 KiB、ユーザー空間は約 10 KiB なので、100 万接続ではデータベースとは別に約 90 GiB のカーネル + ユーザーメモリが必要です。

スループット(毎秒イベント数)

イベントの書き込みは 2 つのコストに制約されます:Schnorr 署名検証(1 イベントあたり約 30〜50 µs)と、LMDB ライターが各コミットバッチ後に実行する同期ディスクフラッシュです。どちらも nostrfy.toml で調整できます:

設定理由
database.disabled_fsync = trueOS ページキャッシュへコミット(マイクロ秒);電源断で失われるのは最後のフラッシュ以降の書き込みのみ — ここから始めましょう
CPU コア ≥ 8 vCPUバッチ EVENT パスがコアをまたいで並列に署名検証
database.search_index = false書き込み重視のインスタンス向けに、イベントごとの NIP-50 語インデックス書き込みを省きます

並列署名検証は、保留中のバッチ内のすべての署名を一度にワーカースレッドプールで検証します(上限 8。16 イベント未満のバッチはインラインで検証)。各イベントの軽量チェックは先に実行されるため、拒否理由の文言は逐次処理と同一です — Schnorr の処理だけが各コアに分散されます。シングルスレッドビルドは逐次のままです。

固定の不正対策リミット

リレーが濫用下でも応答し続けるよう、いくつかのハードリミットは固定されています(設定不可):

  • 1 つのフィルターが持つのは最大 512 個 ids、authors または kinds エントリ;#... タグ値はフィルターごとに別の 512 値の予算。より大きなフィルターは拒否されます(CLOSED invalid: ...)。
  • max_connections_per_sec_per_ip は最大 10,000 個のソース IP を追跡します。満杯になると、未見の IP は拒否されます(フェイルクローズ)。
  • ids フィルター内のイベント id はプレフィックスでも構いませんが、完全な 32 バイト id と偶数長のプレフィックスのみ一致します(奇数長/空のエントリは履歴とライブ配信の両方で無視されます)。
  • 過長なインデックスキー(タグ値、内容の単語、LMDB のキーサイズ制限を超える d タグ)は索引時にスキップされます;イベント自体は保存されます。