Skip to content
ParticleDB

Redis Compatibility

ParticleDB speaks the Redis protocol (RESP2). You can point redis-cli or a Redis client library (configured for RESP2) at it and use strings, lists, sets, sorted sets, hashes, streams, HyperLogLog, geo indexes, Pub/Sub and MULTI/EXEC transactions. Every write is logged to the same write-ahead log as SQL, so Redis keys survive a restart, and SQL can read and write the same key space.

For the per-command reference, see Redis Commands.

The Redis listener is on by default on port 6379. It listens on the same interface as the PostgreSQL listener (--pg-addr, all interfaces by default). To choose the interface and port explicitly, use --redis-addr:

Terminal window
particledb start --data-dir ~/.particledb/data --redis-addr 127.0.0.1:6379
Flag What it does
--redis-addr host:port Listen address for the Redis protocol. Default: the --pg-addr interface, port 6379.
--tls-cert, --tls-key Serve TLS on the Redis port (and the other listeners). Plain-text connections are then refused.
--connection-timeout seconds Close idle Redis connections after this many seconds. Default 300; 0 disables it.
--resp-commit-mode sync|async When a write is acknowledged; see Durability.
Terminal window
redis-cli -p 6379 PING
# PONG
# With TLS
redis-cli -p 6379 --tls --cacert ca.pem PING

Authentication is on by default. Until a client authenticates, every command except AUTH, HELLO, PING and QUIT fails with NOAUTH Authentication required.

Redis users are ParticleDB users: authenticate with a role created in SQL (or the initial superuser, postgres by default, whose password you set with --pg-password). Use the two-argument form of AUTH:

Terminal window
redis-cli -p 6379 --user postgres --pass your_password GET greeting
127.0.0.1:6379> AUTH postgres your_password
OK
127.0.0.1:6379> AUTH postgres wrong
(error) WRONGPASS invalid username-password pair or user is disabled.
  • The one-argument form AUTH password authenticates as a user named default, so it only works if you created such a role.
  • Commands that read or write keys require a superuser role. A non-superuser can authenticate and run PING, but its data commands fail with NOPERM permission denied: this command requires superuser privilege.
  • HELLO answers with server information but does not authenticate: its AUTH and SETNAME options are ignored. Configure your client to send AUTH (most clients do this when you give them a user name and password with RESP2).
  • --no-auth disables authentication on every listener; use it only for local development.
  • RESP2 only. HELLO 3 is accepted but the server answers in RESP2 (proto is 2 in the reply). Clients that require RESP3 must be configured for RESP2.
  • One database. SELECT 0 is accepted; any other index returns ERR DB index is out of range. MOVE and SWAPDB are refused. Use key prefixes to separate applications.
  • No cluster mode. The server reports cluster_enabled:0; connect with a standalone (non-cluster) client configuration.
  • Binary safe. Keys, values, members, hash fields, channels and messages can hold any bytes and are returned exactly as sent.
Family Commands
Strings SET (EX, PX, NX, XX), GET, GETSET, GETDEL, GETEX, SETNX, SETEX, MGET, MSET, MSETNX, INCR, INCRBY, DECR, DECRBY, APPEND, STRLEN, GETRANGE, SUBSTR, SETRANGE
Lists LPUSH, RPUSH, LPUSHX, RPUSHX, LPOP, RPOP, LLEN, LRANGE, LINDEX, LSET, LINSERT, LREM, LTRIM, LPOS, LMOVE, RPOPLPUSH, and the non-waiting forms of BLPOP, BRPOP, BLMOVE, BRPOPLPUSH
Sets SADD, SREM, SMEMBERS, SISMEMBER, SMISMEMBER, SCARD, SPOP, SRANDMEMBER, SMOVE, SUNION, SINTER, SDIFF, SUNIONSTORE, SINTERSTORE, SINTERCARD, SSCAN
Sorted sets ZADD (NX, XX, GT, LT, CH, INCR), ZINCRBY, ZSCORE, ZMSCORE, ZRANK, ZREVRANK, ZRANGE, ZREVRANGE, ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZCOUNT, ZLEXCOUNT, ZCARD, ZREM, ZREMRANGEBYSCORE, ZREMRANGEBYRANK, ZPOPMIN, ZPOPMAX, ZRANDMEMBER, ZUNIONSTORE, ZINTERSTORE, ZINTERCARD, ZSCAN
Hashes HSET, HGET, HMSET, HMGET, HSETNX, HGETALL, HDEL, HEXISTS, HKEYS, HVALS, HLEN, HSTRLEN, HINCRBY, HRANDFIELD, HSCAN
Streams XADD, XLEN, XRANGE, XREVRANGE, XREAD, XTRIM, XDEL, XINFO STREAM
HyperLogLog PFADD, PFCOUNT, PFMERGE (Redis-compatible counts)
Geo GEOADD, GEODIST, GEOPOS
Keys DEL, UNLINK, EXISTS, TYPE, KEYS, SCAN, RENAME, COPY, TOUCH, RANDOMKEY, EXPIRE, PEXPIRE, EXPIREAT, PEXPIREAT, TTL, PTTL, EXPIRETIME, PEXPIRETIME, PERSIST
Pub/Sub SUBSCRIBE, UNSUBSCRIBE, PUBLISH
Transactions MULTI, EXEC, DISCARD
Scripting EVAL, EVALSHA, SCRIPT LOAD, SCRIPT EXISTS for a fixed set of built-in scripts (see Differences from Redis)
Connection and server AUTH, HELLO, PING, ECHO, QUIT, RESET, SELECT 0, DBSIZE, FLUSHDB, FLUSHALL, INFO, CONFIG GET, CONFIG SET pdb-resp-commit-mode, TIME, WAIT

Commands not in this table either return ERR unknown command or are accepted for client compatibility without doing anything useful (for example CLIENT, ACL, COMMAND, SAVE, BGSAVE, SLOWLOG). Do not rely on their replies.

Every Redis write is appended to ParticleDB’s write-ahead log before it is acknowledged, and keys, values, expirations and streams are restored on restart. SAVE, BGSAVE and BGREWRITEAOF are not needed and do nothing.

--resp-commit-mode decides how long a Redis write waits:

Mode A reply is sent after Acknowledged writes can be lost by
sync (default) the persistence flush completes (--wal-sync-mode sync or groupsync, the default) storage or hardware failures outside the persistence guarantee
async the WAL record is written to the operating system an operating-system crash or power loss (not a ParticleDB process crash)

If you know Redis persistence: sync corresponds to appendfsync always, and async is close to appendfsync everysec, except that the flush starts as soon as the previous one finishes rather than once a second. CONFIG GET appendfsync reports always or everysec to match; CONFIG SET appendfsync is refused. See Transaction and Durability Modes.

With --wal-sync-mode nosync the server writes no WAL, so Redis writes are not durable at all.

You can switch the mode at runtime; it returns to the startup value after a restart:

127.0.0.1:6379> CONFIG SET pdb-resp-commit-mode async
OK
127.0.0.1:6379> CONFIG GET pdb-resp-commit-mode
1) "pdb-resp-commit-mode"
2) "async"

async is refused when the server runs with --wal-sync-mode nosync, with --num-wal-stripes above 1, or with replication.

The Redis memory commands do not report real memory use in this release:

  • MEMORY USAGE key returns the same fixed value (64) for every existing key, whatever its size, and nil for a missing key.
  • MEMORY STATS returns an empty array.
  • INFO has no Memory section; INFO memory returns the same output as INFO (Server, Persistence and Keyspace sections).

Use ParticleDB’s server metrics and memory settings (--max-server-memory) to monitor and bound memory instead.

SQL functions read and write the same key space, over any protocol that runs SQL (PostgreSQL wire, native wire, HTTP, gRPC):

Terminal window
redis-cli SET greeting hello
redis-cli RPUSH tasks a b c
redis-cli HSET user:1 name Alice
SELECT KV_GET('greeting'); -- hello
SELECT LIST_RANGE('tasks', 0, -1); -- [a,b,c]
SELECT HASH_GET('user:1', 'name'); -- Alice
SELECT KV_SET('from_sql', '42'); -- OK; redis-cli GET from_sql returns "42"
SELECT KV_TTL('session:abc'); -- remaining seconds, as TTL

Other functions follow the same naming: KV_* for strings and keys, LIST_*, SET_*, HASH_*, ZSET_*, STREAM_*. SQL functions return text: reading a value that is not valid UTF-8 fails with SQLSTATE 22021 instead of altering it.

  • No Lua. EVAL, EVALSHA, SCRIPT LOAD and SCRIPT EXISTS accept only a fixed set of built-in scripts, matched by their exact text or SHA1 and run natively and atomically: the Orkes Conductor Redis queue’s pop_batch.lua (orkes-redis-queues 1.0.9) and the Redisson 3.13.3 RLock scripts (lock, renew, unlock, force-unlock). Any other script returns ERR unknown script; EVALSHA of an unknown SHA returns NOSCRIPT. EVAL_RO, EVALSHA_RO, SCRIPT FLUSH and FUNCTION are not supported.
  • Blocking commands do not wait. BLPOP, BRPOP, BLMOVE, BRPOPLPUSH, and XREAD with BLOCK return at once (nil when there is nothing to return). Poll instead.
  • No WATCH. MULTI/EXEC run the queued commands atomically, but optimistic locking with WATCH/UNWATCH is not available.
  • Pub/Sub supports channels only: PSUBSCRIBE, PUNSUBSCRIBE, SSUBSCRIBE and PUBSUB are not supported. A subscriber that falls more than 32 MB behind is disconnected (like Redis’s client-output-buffer-limit pubsub).
  • Streams: Consumer groups (XGROUP, XREADGROUP, XACK, XPENDING, XCLAIM, XAUTOCLAIM), XINFO GROUPS and XINFO CONSUMERS are not supported. XTRIM ... ~ trims exactly to the threshold.
  • Expiry options: EXPIRE and related commands do not accept NX, XX, GT or LT.
  • Not supported in this release: INCRBYFLOAT, HINCRBYFLOAT, RENAMENX, SDIFFSTORE, ZRANGEBYLEX, ZUNION, ZDIFF, GEOSEARCH, GEORADIUS, GEOHASH, SORT, DUMP/RESTORE, MONITOR; ZRANGE supports only start stop [WITHSCORES] (use ZREVRANGE and ZRANGEBYSCORE for the other forms); LPOP/RPOP pop one element (no count argument). Bitmap commands (SETBIT, GETBIT, BITCOUNT, BITPOS, BITOP, BITFIELD) are not compatible with Redis: they do not operate on the string value that GET returns.
  • Server information. CONFIG GET reports fixed values for most parameters and CONFIG SET changes only pdb-resp-commit-mode; configure the server with particledb start flags.

Documentation home · Troubleshooting