# Key-value: ParticleDB and Redis

Key-value throughput of ParticleDB and Redis on the same machine, in asynchronous and fully durable modes, from 1 to 512 clients.

Source: https://particledb.ai/benchmarks/key-value/

ParticleDB serves Redis clients over the Redis protocol (RESP) and its own native key-value protocol. This page compares it with Redis in two durability modes, each against the Redis setting that gives the same guarantee.

| Mode | ParticleDB | Redis | Reply sent | Writes lost on power failure |
|---|---|---|---|---|
| Asynchronous | `--kv-durability async` (default) | `appendfsync everysec` | Before fsync | ParticleDB: writes since the last fsync, about 1.7 ms in our tests (fsync runs continuously). Redis: up to 1 second. |
| Durable | `--durability sync` | `appendfsync always` | After fsync | None: every acknowledged write is on disk. |

## Results at a glance

ParticleDB operations per second divided by Redis operations per second, one command per request, over RESP. Above 1.00x means ParticleDB is faster.

| Operation | Async, 8 clients | Async, 64 clients | Async, 512 clients | Durable, 8 clients | Durable, 64 clients | Durable, 512 clients |
|---|---|---|---|---|---|---|
| SET | 1.27x | 2.21x | 4.81x | 1.78x | 1.27x | 1.58x |
| GET | 1.60x | 3.13x | 7.11x | 1.56x | 3.08x | 7.04x |
| INCR | 1.46x | 3.12x | 6.88x | 1.70x | 1.08x | 1.88x |
| LPUSH | 1.49x | 3.19x | 6.45x | 1.74x | 1.12x | 1.99x |
| HSET | 1.51x | 3.05x | 5.06x | 1.75x | 1.16x | 1.91x |

ParticleDB scales with the server's cores: throughput keeps rising as clients are added. With a single client the result is decided by per-request latency rather than cores; see the full tables.

## Asynchronous mode

ParticleDB `--kv-durability async` against Redis `appendfsync everysec`.

- - - Redis 7.2.7 (appendfsync everysec) &nbsp; &#9473;&#9473; ParticleDB over RESP (--kv-durability async) &nbsp; &#9473;&#9473; ParticleDB native KV protocol (--kv-durability async)

The native key-value protocol, asynchronous mode, against Redis:

| Operation | 8 clients | 64 clients | 512 clients |
|---|---|---|---|
| SET | 1.64x | 2.59x | 2.97x |
| GET | 3.07x | 13.90x | 14.09x |
| INCR | 2.12x | 4.09x | 4.12x |

All asynchronous results

| Operation | Clients | Pipeline | Redis ops/s | ParticleDB RESP ops/s | ParticleDB native ops/s | p99 ms (Redis / RESP / native) |
|---|---|---|---|---|---|---|
| SET | 1 | 1 | 76,118 | 68,266 (0.90x) | 68,327 (0.90x) | 0.02 / 0.02 / 0.02 |
| SET | 8 | 1 | 184,215 | 233,152 (1.27x) | 302,244 (1.64x) | 0.08 / 0.05 / 0.03 |
| SET | 64 | 1 | 201,032 | 443,773 (2.21x) | 521,024 (2.59x) | 0.70 / 1.34 / 0.31 |
| SET | 512 | 1 | 186,393 | 897,390 (4.81x) | 553,506 (2.97x) | 5.30 / 49.43 / 58.37 |
| SET | 1 | 16 | 367,935 | 256,508 (0.70x) | 221,875 (0.60x) | 0.08 / 0.06 / 0.06 |
| SET | 8 | 16 | 704,422 | 1,011,502 (1.44x) | 884,271 (1.26x) | 0.43 / 0.20 / 0.17 |
| SET | 64 | 16 | 722,018 | 1,467,997 (2.03x) | 550,216 (0.76x) | 4.87 / 69.33 / 76.98 |
| SET | 512 | 16 | 640,440 | 1,470,331 (2.30x) | 549,610 (0.86x) | 34.05 / 182.32 / 191.79 |
| GET | 1 | 1 | 86,504 | 86,650 (1.00x) | 93,092 (1.08x) | 0.01 / 0.01 / 0.01 |
| GET | 8 | 1 | 231,070 | 368,629 (1.60x) | 708,725 (3.07x) | 0.09 / 0.08 / 0.01 |
| GET | 64 | 1 | 245,796 | 769,476 (3.13x) | 3,415,933 (13.90x) | 0.51 / 1.13 / 0.03 |
| GET | 512 | 1 | 228,156 | 1,623,240 (7.11x) | 3,214,184 (14.09x) | 2.39 / 0.89 / 0.32 |
| GET | 1 | 16 | 470,946 | 442,819 (0.94x) | 469,980 (1.00x) | 0.07 / 0.07 / 0.03 |
| GET | 8 | 16 | 1,188,489 | 1,576,930 (1.33x) | 3,439,170 (2.89x) | 0.20 / 0.18 / 0.03 |
| GET | 64 | 16 | 1,208,791 | 3,768,671 (3.12x) | 9,201,634 (7.61x) | 1.68 / 1.39 / 0.23 |
| GET | 512 | 16 | 1,086,199 | 4,474,941 (4.12x) | 9,105,514 (8.38x) | 15.17 / 8.09 / 1.93 |
| INCR | 1 | 1 | 85,211 | 75,109 (0.88x) | 76,536 (0.90x) | 0.01 / 0.01 / 0.01 |
| INCR | 8 | 1 | 232,492 | 339,363 (1.46x) | 492,904 (2.12x) | 0.04 / 0.04 / 0.02 |
| INCR | 64 | 1 | 252,751 | 788,769 (3.12x) | 1,034,431 (4.09x) | 0.49 / 1.20 / 0.26 |
| INCR | 512 | 1 | 234,974 | 1,617,664 (6.88x) | 967,861 (4.12x) | 2.29 / 0.79 / 2.92 |
| INCR | 1 | 16 | 537,361 | 436,964 (0.81x) | 346,485 (0.64x) | 0.03 / 0.04 / 0.04 |
| INCR | 8 | 16 | 1,166,854 | 2,158,263 (1.85x) | 1,690,443 (1.45x) | 0.15 / 0.13 / 0.08 |
| INCR | 64 | 16 | 1,196,083 | 4,511,391 (3.77x) | 999,519 (0.84x) | 1.56 / 0.93 / 1.79 |
| INCR | 512 | 16 | 1,140,930 | 4,523,900 (3.97x) | 1,020,847 (0.89x) | 13.37 / 5.14 / 14.75 |
| LPUSH | 1 | 1 | 82,799 | 71,288 (0.86x) | - | 0.01 / 0.02 |
| LPUSH | 8 | 1 | 211,634 | 315,153 (1.49x) | - | 0.05 / 0.04 |
| LPUSH | 64 | 1 | 224,012 | 714,908 (3.19x) | - | 0.55 / 1.29 |
| LPUSH | 512 | 1 | 207,346 | 1,337,532 (6.45x) | - | 3.49 / 0.77 |
| LPUSH | 1 | 16 | 404,925 | 309,297 (0.76x) | - | 0.06 / 0.05 |
| LPUSH | 8 | 16 | 674,187 | 1,164,057 (1.73x) | - | 0.48 / 0.16 |
| LPUSH | 64 | 16 | 670,544 | 1,451,012 (2.16x) | - | 4.14 / 1.68 |
| LPUSH | 512 | 16 | 653,771 | 1,464,682 (2.24x) | - | 31.33 / 54.53 |
| HSET | 1 | 1 | 79,416 | 70,142 (0.88x) | - | 0.01 / 0.02 |
| HSET | 8 | 1 | 199,626 | 301,992 (1.51x) | - | 0.06 / 0.04 |
| HSET | 64 | 1 | 209,798 | 639,061 (3.05x) | - | 0.59 / 1.28 |
| HSET | 512 | 1 | 195,810 | 990,884 (5.06x) | - | 3.80 / 0.92 |
| HSET | 1 | 16 | 335,565 | 257,979 (0.77x) | - | 0.08 / 0.06 |
| HSET | 8 | 16 | 522,275 | 806,361 (1.54x) | - | 0.57 / 0.28 |
| HSET | 64 | 16 | 523,017 | 873,462 (1.67x) | - | 5.34 / 4.00 |
| HSET | 512 | 16 | 512,038 | 922,858 (1.80x) | - | 38.54 / 47.45 |
| redis-benchmark mix | 1 | 1 | 81,392 | 70,718 (0.87x) | - | 0.01 / 0.01 |
| redis-benchmark mix | 8 | 1 | 176,792 | 173,568 (0.98x) | - | 0.04 / 0.04 |
| redis-benchmark mix | 64 | 1 | 174,774 | 173,086 (0.99x) | - | 0.21 / 0.22 |
| redis-benchmark mix | 512 | 1 | 164,499 | 160,419 (0.98x) | - | 1.67 / 1.93 |
| redis-benchmark mix | 1 | 16 | 672,856 | 429,642 (0.64x) | - | 0.03 / 0.04 |
| redis-benchmark mix | 64 | 16 | 1,144,916 | 870,862 (0.76x) | - | 1.07 / 3.06 |
| redis-benchmark mix | 512 | 16 | 1,136,084 | 873,683 (0.77x) | - | 11.72 / 23.86 |

Data: run of 2026-10-31 with the ParticleDB 1.1.19-rc.17 release candidate (commit 14813b4d9).

## Durable mode

ParticleDB `--durability sync` against Redis `appendfsync always`. Each write waits for an fsync of about 1.7 ms on this volume, which sets the single-client rate for both systems. Every ParticleDB configuration is also killed with `kill -9` and every acknowledged write is verified after restart.

The native key-value protocol, durable mode, against Redis:

| Operation | 8 clients | 64 clients | 512 clients |
|---|---|---|---|
| SET | 2.23x | 1.53x | 1.73x |
| GET | 3.03x | 13.58x | 14.55x |
| INCR | 2.07x | 1.49x | 2.28x |

All durable results

| Operation | Clients | Pipeline | Redis ops/s | ParticleDB RESP ops/s | ParticleDB native ops/s | p99 ms (Redis / RESP / native) |
|---|---|---|---|---|---|---|
| SET | 1 | 1 | 572 | 1,041 (1.82x) | 1,051 (1.84x) | 2.23 / 1.83 / 1.80 |
| SET | 8 | 1 | 2,441 | 4,342 (1.78x) | 5,431 (2.23x) | 3.87 / 2.79 / 2.75 |
| SET | 64 | 1 | 27,215 | 34,605 (1.27x) | 41,727 (1.53x) | 4.68 / 4.12 / 4.02 |
| SET | 512 | 1 | 98,831 | 155,820 (1.58x) | 171,468 (1.73x) | 10.57 / 32.88 / 33.11 |
| SET | 1 | 16 | 8,704 | 16,007 (1.84x) | 15,919 (1.83x) | 2.08 / 2.30 / 1.92 |
| SET | 8 | 16 | 30,768 | 63,222 (2.05x) | 66,252 (2.15x) | 5.80 / 4.84 / 4.38 |
| SET | 64 | 16 | 224,498 | 272,784 (1.22x) | 214,271 (0.95x) | 10.90 / 60.90 / 54.18 |
| SET | 512 | 16 | 465,591 | 1,063,772 (2.28x) | 518,057 (1.11x) | 41.09 / 305.76 / 250.51 |
| GET | 1 | 1 | 87,048 | 86,873 (1.00x) | 91,153 (1.05x) | 0.01 / 0.01 / 0.01 |
| GET | 8 | 1 | 234,559 | 365,324 (1.56x) | 709,947 (3.03x) | 0.09 / 0.08 / 0.01 |
| GET | 64 | 1 | 247,115 | 762,339 (3.08x) | 3,354,919 (13.58x) | 0.50 / 1.16 / 0.03 |
| GET | 512 | 1 | 230,320 | 1,622,391 (7.04x) | 3,351,659 (14.55x) | 2.39 / 0.89 / 0.31 |
| GET | 1 | 16 | 471,989 | 441,914 (0.94x) | 462,057 (0.98x) | 0.07 / 0.07 / 0.03 |
| GET | 8 | 16 | 1,189,800 | 1,597,774 (1.34x) | 3,396,994 (2.86x) | 0.21 / 0.18 / 0.03 |
| GET | 64 | 16 | 1,207,474 | 5,453,360 (4.52x) | 9,871,788 (8.18x) | 1.66 / 1.52 / 0.21 |
| GET | 512 | 16 | 1,091,555 | 6,877,056 (6.30x) | 9,808,988 (8.99x) | 15.56 / 8.09 / 1.74 |
| INCR | 1 | 1 | 573 | 1,045 (1.82x) | 1,053 (1.84x) | 1.92 / 1.79 / 1.83 |
| INCR | 8 | 1 | 2,554 | 4,340 (1.70x) | 5,288 (2.07x) | 3.72 / 2.74 / 2.70 |
| INCR | 64 | 1 | 31,037 | 33,646 (1.08x) | 46,127 (1.49x) | 4.01 / 2.80 / 2.83 |
| INCR | 512 | 1 | 126,064 | 236,917 (1.88x) | 286,797 (2.28x) | 4.29 / 3.65 / 4.08 |
| INCR | 1 | 16 | 9,060 | 16,154 (1.78x) | 15,978 (1.76x) | 1.91 / 1.83 / 1.83 |
| INCR | 8 | 16 | 35,488 | 68,490 (1.93x) | 71,610 (2.02x) | 3.83 / 2.77 / 2.87 |
| INCR | 64 | 16 | 342,567 | 465,894 (1.36x) | 377,026 (1.10x) | 5.57 / 3.19 / 4.69 |
| INCR | 512 | 16 | 820,416 | 2,163,346 (2.64x) | 962,392 (1.17x) | 16.91 / 8.09 / 14.22 |
| LPUSH | 1 | 1 | 573 | 1,044 (1.82x) | - | 1.89 / 1.79 |
| LPUSH | 8 | 1 | 2,498 | 4,335 (1.74x) | - | 3.69 / 2.70 |
| LPUSH | 64 | 1 | 30,469 | 34,002 (1.12x) | - | 4.08 / 2.80 |
| LPUSH | 512 | 1 | 113,668 | 225,717 (1.99x) | - | 5.80 / 4.18 |
| LPUSH | 1 | 16 | 9,010 | 15,892 (1.76x) | - | 1.94 / 1.83 |
| LPUSH | 8 | 16 | 34,868 | 69,244 (1.99x) | - | 3.95 / 2.80 |
| LPUSH | 64 | 16 | 269,552 | 413,172 (1.53x) | - | 7.05 / 4.88 |
| LPUSH | 512 | 16 | 543,981 | 1,047,227 (1.93x) | - | 32.90 / 65.27 |
| HSET | 1 | 1 | 573 | 1,044 (1.82x) | - | 1.89 / 1.81 |
| HSET | 8 | 1 | 2,479 | 4,334 (1.75x) | - | 3.69 / 2.74 |
| HSET | 64 | 1 | 30,272 | 35,065 (1.16x) | - | 4.11 / 2.80 |
| HSET | 512 | 1 | 109,608 | 208,905 (1.91x) | - | 6.26 / 5.14 |
| HSET | 1 | 16 | 8,992 | 15,864 (1.76x) | - | 1.91 / 1.83 |
| HSET | 8 | 16 | 34,640 | 70,698 (2.04x) | - | 3.95 / 2.80 |
| HSET | 64 | 16 | 239,502 | 413,766 (1.73x) | - | 8.09 / 5.28 |
| HSET | 512 | 16 | 439,584 | 949,804 (2.16x) | - | 41.68 / 38.01 |
| redis-benchmark mix | 1 | 1 | 573 | 1,044 (1.82x) | - | 1.96 / 1.80 |
| redis-benchmark mix | 8 | 1 | 2,473 | 4,337 (1.75x) | - | 3.68 / 2.70 |
| redis-benchmark mix | 64 | 1 | 19,472 | 34,317 (1.76x) | - | 3.98 / 2.75 |
| redis-benchmark mix | 512 | 1 | 96,598 | 149,422 (1.55x) | - | 6.65 / 4.19 |
| redis-benchmark mix | 1 | 16 | 9,074 | 16,132 (1.78x) | - | 1.98 / 1.81 |
| redis-benchmark mix | 8 | 16 | 35,234 | - | - | |
| redis-benchmark mix | 64 | 16 | 227,207 | 373,834 (1.65x) | - | 5.33 / 5.00 |
| redis-benchmark mix | 512 | 16 | 665,599 | 779,971 (1.17x) | - | 17.61 / 25.49 |

Data: run of 2026-10-31 with the ParticleDB 1.1.19-rc.17 release candidate (commit 14813b4d9).

## Test setup

| | |
|---|---|
| Machine | AWS c8g.metal-48xl, 192 Graviton4 vCPUs, 500 GB EBS data volume (4 KiB fsync median 1.73 ms) |
| CPU placement | Server pinned to 48 cores (0-47), load generator to 48 other cores (48-95) |
| Redis | 7.2.7, default `io-threads` (single-threaded command execution) |
| Load generators | memtier_benchmark 2.1.4, redis-benchmark 7.2.7, and the suite's own RESP and native drivers; the same driver runs against both servers in each cell |
| Data | 100,000 keys, 32-byte values; list and hash operations spread across keys |
| Clients and pipelining | 1, 8, 64 and 512 connections; 1 and 16 commands per request |
| Statistic | Median over alternating rounds in one session; p99 latency per cell |

## How to run it

Run each server alone on the machine, pinned to the same cores, and drive it from other cores.

### 1. Start Redis

`redis.conf` used for both modes (change the last line to `appendfsync always` for durable mode):

```text
bind 127.0.0.1
protected-mode no
tcp-backlog 4096
maxclients 20000
timeout 0
tcp-keepalive 0
save ""
aof-use-rdb-preamble yes
appendonly yes
appendfsync everysec
```

```bash
taskset -c 0-47 redis-server ./redis.conf --port 6379 --dir /data/redis
```

### 2. Start ParticleDB

Asynchronous mode:

```bash
taskset -c 0-47 particledb start --no-auth \
  --durability groupsync --kv-durability async \
  --data-dir /data/pdb --redis-addr 127.0.0.1:6379
```

Durable mode: replace the second line with `--durability sync --kv-durability sync`.

### 3. Run the load

Each cell runs a 2-second warm-up and an 8-second timed run with the client pinned to the other cores. For example, SET with 64 clients and no pipelining:

```bash
taskset -c 48-95 memtier_benchmark -s 127.0.0.1 -p 6379 --protocol=redis \
  -t 8 -c 8 --ratio=1:0 --key-pattern=R:R --key-minimum=1 --key-maximum=100000 \
  -d 32 --pipeline=1 --test-time=8 --hide-histogram
```

For GET use `--ratio=0:1` after loading the keys; for pipelining use `--pipeline=16`; for other client counts change `-t` (threads) and `-c` (connections per thread) so that `t x c` is 1, 8, 64 or 512. The classic mix uses the stock tool:

```bash
taskset -c 48-95 redis-benchmark -h 127.0.0.1 -p 6379 -c 64 -P 1 -d 32 -r 100000 -n 1000000 \
  -t set,get,incr,lpush,hset --csv
```

The results on this page were produced by our benchmark suite, which runs the same cells with a verifying load driver: it checks every reply and the final state of the keys, alternates Redis and ParticleDB rounds in one session, and kills each ParticleDB configuration with `kill -9` to confirm that acknowledged writes survive. The native-protocol rows use the same driver over the ParticleDB native key-value protocol.

### 4. Report

Use the median of the timed rounds per cell, with p99 latency, and publish the server versions, configuration and machine details listed under [Test setup](#test-setup).

See [Benchmarks and methodology](/benchmarks/overview/) for the reporting rules.
