nostr-relay is designed to be performant and scalable "out of the box". The default configuration can support hundreds of connections, serving about 100 requests per second. But the default sqlite storage backend offers the worst performance (because the aiosqlite driver is not optimized for async access). With a few configuration changes, you can greatly increase throughput.
Here are some tips for squeezing the most performance out of nostr-relay:
Use pypy
The easiest improvement is to install pypy version 3.9 or higher. The only limitation to using pypy is that the PostgreSQL driver (asyncpg) is not compatible. Sqlite and LMDB work well, however.
If you can't use pypy, be sure to use cPython 3.11 or higher.
Use LMDB
Configure LMDB as your storage backend. See the python LMDB docs for more tuning tips.
Use Purple
Version 1.12 introduces the "purple" server: a minimal websockets server that is intended to be the fastest method of serving nostr-relay. The implementation is subject to change, but currently it is limited to serving only the websockets (not /e/<id> or the other endpoints defined in web.py).
To use purple simply run it like so:
nostr-relay serve --use-purple
Turn off noisy logging
Disabling logging can improve performance. Add this to your config file:
logging:
version: 1
handlers:
empty:
class: logging.NullHandler
level: WARNING
console:
class: logging.StreamHandler
level: ERROR
stream: ext://sys.stdout
root:
level: WARNING
handlers: [empty]
Logging is extremely configurable. See the python logging docs for more.
Complete Configuration Example
Here's a complete high-performance configuration file, using LMDB:
DEBUG: false
storage:
class: nostr_relay.storage.kv.LMDBStorage
path: ./data/nostr-fast.db
map_size: 209715200
metasync: false
pool_size: 8
purple:
host: 127.0.0.1
port: 6969
# compression is great for saving bandwidth, but it kills performance
disable_compression: true
workers: 4
relay_name: fast python relay
relay_description: a super fast implementation
sysop_pubkey:
sysop_contact:
nip05_verification: disabled
garbage_collector:
collect_interval: 600
logging:
version: 1
handlers:
empty:
class: logging.NullHandler
level: WARNING
console:
class: logging.StreamHandler
level: ERROR
stream: ext://sys.stdout
root:
level: WARNING
handlers: [empty]
To use PostgreSQL, switch the storage section with this:
storage:
sqlalchemy.url: 'postgresql+asyncpg://user:pass@localhost/nostr'
sqlalchemy.max_overflow: 80
sqlalchemy.pool_size: 4
num_concurrent_reqs: 10
num_concurrent_adds: 10
Then, be sure to run with the purple server:
nostr-relay -c config.yaml serve --use-purple
Benchmarks
Use aionostr to benchmark your relay:
aionostr bench -r ws://127.0.0.1:6969 -f req_per_second
This will execute a request for 50 events, in a tight loop. Use -c to increase the concurrency.
aionostr bench -r ws://127.0.0.1:6969 -f events_per_second
This will execute a request for 500 events, measuring the number of events sent to the client.