Redis + Hybrid Benchmark Comparison
Redis + Hybrid backend performance (comparison)
This suite compares the backend cost of three Redis rate limiting approaches under the same client concurrency and runtime.
Environment + machine details for interpreting results: see Benchmarking & Load Testing (Results).
How to run:
make stress-redis-compare
Environment:
- Redis: Docker Compose (
compose.yaml) on Docker Desktop (serverlinux/arm64) - Client: 16 threads
- Duration: 30s per case
Backends compared:
trypemaRedis provider (Lua sliding-window)trypemaHybrid provider (local fast-path + periodic Redis sync)redis-cellmodule (CL.THROTTLE)- GCRA Lua script (equivalent to
go-redis/redis_rateallowN)
Caveat: semantics differ (sliding window vs GCRA), so results are backend-cost comparisons, not strict behavioral equivalence.
Hybrid note: the Hybrid provider uses a local fast-path and periodically syncs to Redis, so it is not a pure "Redis round-trip per op" backend. It is included here because it still depends on Redis and is a common deployment choice when you want higher throughput with bounded state lag.
In these results, Hybrid runs use sync_interval_ms = 10ms.
Command captured (for reference):
make stress-redis-compare
Module-based approaches (like redis-cell) tend to be faster because the logic runs as native Redis module code with less Lua interpreter overhead and fewer internal steps than multi-op Lua scripts.
Hot key (rate_limit_per_s=1000)
Workload: --key-dist hot — always uses a single key (user_0).
tokio runtime
| Backend | ops/s | p50 (us) | p95 (us) | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 64,369 | 243 | 323 | 367 | 490 | 814 | 30,016 | 1,901,152 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 52,211 | 303 | 391 | 438 | 610 | 816 | 30,015 | 1,536,405 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 47,620 | 332 | 433 | 502 | 703 | 1,160 | 30,603 | 1,398,032 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 41,032 | 386 | 521 | 599 | 906 | 1,122 | 33,115 | 0 | 1,306 | 1,196,617 | 0 |
trypema (Hybrid + Absolute) | 11,360,280 | 1 | 1 | 1 | 1 | 45 | 30,000 | 340,794,220 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 10,568,476 | 1 | 1 | 1 | 1 | 1,214,463 | 29,984 | 0 | 5,007 | 317,034,410 | 0 |
smol runtime
| Backend | ops/s | p50 (us) | p95 (us) | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 83,223 | 187 | 227 | 254 | 357 | 556 | 30,016 | 2,466,720 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 53,248 | 312 | 358 | 400 | 487 | 711 | 30,015 | 1,567,457 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 43,490 | 373 | 425 | 472 | 1,320 | 1,328 | 30,000 | 1,274,729 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 39,975 | 392 | 512 | 563 | 735 | 910 | 33,181 | 0 | 2,734 | 1,163,363 | 0 |
trypema (Hybrid + Absolute) | 10,995,323 | 1 | 1 | 1 | 1 | 3,211 | 30,000 | 329,834,016 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 10,629,543 | 1 | 1 | 1 | 1 | 1,524,735 | 64,987 | 0 | 5,004 | 318,828,204 | 0 |
Uniform keys (100k keys, rate_limit_per_s=1e9)
Workload: --key-dist uniform --key-space 100000 — random key per op, effectively unlimited rate.
tokio runtime
| Backend | ops/s | p50 (us) | p95 (us) | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 58,228 | 259 | 339 | 395 | 3,791 | 15,135 | 1,750,382 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 52,251 | 302 | 389 | 435 | 614 | 1,365 | 1,570,837 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 39,578 | 396 | 541 | 627 | 963 | 2,309 | 1,190,045 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 33,608 | 448 | 661 | 768 | 3,233 | 10,535 | 1,010,251 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 8,628,833 | 1 | 1 | 1 | 19 | 27,167 | 259,464,943 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,216,202 | 1 | 1 | 1 | 13 | 22,719 | 277,038,640 | 0 | 0 | 0 | 0 |
smol runtime
| Backend | ops/s | p50 (us) | p95 (us) | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 72,646 | 210 | 253 | 283 | 2,959 | 4,487 | 2,184,064 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 52,320 | 302 | 361 | 416 | 770 | 16,975 | 1,572,718 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 38,353 | 402 | 535 | 582 | 745 | 2,309 | 1,152,833 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 31,704 | 484 | 633 | 739 | 3,189 | 10,335 | 953,165 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 4,044,466 | 1 | 1 | 1 | 9 | 16,087 | 121,575,135 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 2,817,062 | 1 | 1 | 1 | 425 | 26,623 | 84,679,989 | 0 | 0 | 0 | 0 |
Notes:
redis-cellandgcrashow higher ops/s under smol for both workloads. For pure Redis round-trip backends, smol's cooperative executor reduces context-switch overhead, particularly under hot-key contention.- Trypema's Redis provider throughput is broadly comparable across runtimes (~5–10% variance).
- Hybrid ops/s in the uniform case is substantially lower under smol (~4M vs ~9M for absolute). Hybrid's local fast-path relies on many concurrent atomics; tokio's work-stealing scheduler distributes these more evenly, while smol's cooperative executor serialises more of that work.
- For pure Redis round-trip backends, runtime choice has a modest effect relative to the order-of-magnitude gap between Redis round-trip and Hybrid local fast-path.
Redis + Hybrid uniform keys (matrix)
These runs come from make stress-redis-uniform-matrix-tokio and make stress-redis-uniform-matrix-smol (stress harness) and vary key_space and rate_limit_per_s while keeping the rest fixed:
--threads 16 --duration-s 30 --window-s 10 --group-ms 10 --mode max --key-dist uniform
Hybrid note: Hybrid runs use sync_interval_ms = 10ms.
The harness prints results in run groups of six (two Redis module/script backends + Redis provider + Hybrid provider). To keep it readable, the matrix is split by (key_space, rate_limit_per_s).
key_space=10, rate_limit_per_s=1
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 55,822 | 450 | 740 | 1,285 | 1,674,751 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 50,614 | 447 | 605 | 1,119 | 1,518,500 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 46,008 | 505 | 710 | 923 | 300 | 1,380,002 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 38,184 | 668 | 931 | 4,619 | 1,196 | 0 | 40 | 1,144,292 | 0 |
trypema (Hybrid + Absolute) | 10,658,472 | 1 | 1 | 9,961,471 | 300 | 319,770,837 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 7,860,245 | 1 | 2 | 99,327 | 396 | 0 | 76 | 235,818,537 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 79,299 | 271 | 468 | 745 | 2,378,992 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 49,496 | 432 | 898 | 1,447 | 1,484,922 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 51,730 | 412 | 510 | 889 | 300 | 1,551,628 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 41,892 | 572 | 759 | 1,059 | 1,141 | 0 | 40 | 1,255,584 | 0 |
trypema (Hybrid + Absolute) | 11,025,754 | 1 | 1 | 9,551 | 300 | 330,777,133 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,716,526 | 1 | 1 | 196,607 | 512 | 0 | 111 | 291,508,192 | 0 |
key_space=10, rate_limit_per_s=10
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 61,310 | 383 | 539 | 854 | 1,839,392 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 49,610 | 459 | 680 | 1,710 | 1,488,385 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 45,067 | 523 | 748 | 1,031 | 3,002 | 1,349,077 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 38,977 | 640 | 1,005 | 1,257 | 5,553 | 0 | 490 | 1,163,325 | 0 |
trypema (Hybrid + Absolute) | 8,285,258 | 1 | 1 | 9,953,279 | 3,000 | 248,567,517 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 7,994,442 | 1 | 2 | 99,135 | 3,572 | 0 | 523 | 239,841,065 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 77,325 | 269 | 508 | 535 | 2,319,792 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,285 | 422 | 634 | 654 | 1,448,564 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 46,370 | 470 | 587 | 648 | 3,000 | 1,388,120 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 40,937 | 575 | 1,024 | 1,093 | 5,689 | 0 | 490 | 1,221,966 | 0 |
trypema (Hybrid + Absolute) | 11,024,339 | 1 | 1 | 8,783 | 3,000 | 330,731,808 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,699,245 | 1 | 1 | 192,127 | 4,619 | 0 | 568 | 290,981,034 | 0 |
key_space=10, rate_limit_per_s=100
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 61,369 | 383 | 503 | 898 | 1,841,170 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 49,433 | 458 | 631 | 2,571 | 1,483,072 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 44,462 | 528 | 713 | 1,125 | 30,013 | 1,303,928 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 37,995 | 687 | 1,314 | 5,543 | 33,956 | 0 | 2,164 | 1,103,744 | 0 |
trypema (Hybrid + Absolute) | 9,134,903 | 1 | 1 | 10,807 | 31,467 | 274,029,615 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 8,697,216 | 1 | 1 | 99,135 | 34,532 | 0 | 5,042 | 260,889,866 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 70,877 | 291 | 371 | 651 | 2,126,352 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,257 | 428 | 581 | 1,198 | 1,447,738 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 46,065 | 470 | 1,676 | 3,993 | 30,000 | 1,351,970 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 41,831 | 594 | 742 | 840 | 33,057 | 0 | 2,091 | 1,219,801 | 0 |
trypema (Hybrid + Absolute) | 11,001,527 | 1 | 1 | 10,047 | 30,000 | 330,021,664 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,589,111 | 1 | 1 | 192,639 | 42,210 | 0 | 5,600 | 287,629,059 | 0 |
key_space=10, rate_limit_per_s=10,000
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 61,762 | 382 | 477 | 675 | 1,852,947 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 49,548 | 461 | 686 | 1,428 | 1,486,516 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 42,977 | 568 | 821 | 1,768 | 1,289,375 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 38,816 | 656 | 978 | 1,861 | 1,164,556 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 8,684,796 | 1 | 5 | 13,567 | 2,443,095 | 258,115,621 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 7,115,638 | 1 | 3 | 99,711 | 3,226,990 | 0 | 54,298 | 210,198,331 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 70,534 | 298 | 411 | 864 | 2,116,062 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,466 | 442 | 1,401 | 1,402 | 1,454,010 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 42,661 | 557 | 1,205 | 1,371 | 1,279,846 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 42,316 | 572 | 1,014 | 1,272 | 1,269,517 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 11,063,173 | 1 | 1 | 9,247 | 3,000,000 | 328,900,198 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,741,507 | 1 | 1 | 195,711 | 4,430,158 | 0 | 5,105 | 287,813,918 | 0 |
key_space=10, rate_limit_per_s=100,000
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 61,210 | 378 | 473 | 1,023 | 1,836,389 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 49,664 | 461 | 731 | 1,428 | 1,489,994 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 42,274 | 576 | 715 | 1,198 | 1,268,302 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 38,553 | 649 | 883 | 2,069 | 1,156,664 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 8,053,277 | 1 | 5 | 19,471 | 24,245,359 | 217,364,752 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,142,906 | 1 | 1 | 161,919 | 30,113,442 | 0 | 596,474 | 243,590,108 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 68,211 | 352 | 476 | 556 | 2,046,362 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,643 | 453 | 820 | 1,310 | 1,459,330 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 41,238 | 673 | 1,606 | 1,891 | 1,237,188 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 40,048 | 625 | 773 | 985 | 1,201,444 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 11,387,286 | 1 | 1 | 9,994,239 | 30,000,000 | 311,624,114 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 10,085,005 | 1 | 1 | 193,023 | 35,133,613 | 0 | 1,688,088 | 265,734,378 | 1 |
key_space=1,000, rate_limit_per_s=1
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 60,618 | 388 | 512 | 1,144 | 1,818,772 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,719 | 468 | 695 | 1,464 | 1,461,799 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 41,874 | 583 | 920 | 2,119 | 30,000 | 1,226,352 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 27,744 | 945 | 1,346 | 3,999 | 59,261 | 0 | 1,230 | 771,884 | 0 |
trypema (Hybrid + Absolute) | 7,350,822 | 1 | 4 | 9,854,975 | 33,323 | 220,509,608 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 2,343,675 | 1 | 668 | 509,951 | 219,784 | 0 | 6,948 | 70,762,366 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 66,161 | 344 | 788 | 1,116 | 1,985,021 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,091 | 422 | 612 | 642 | 1,442,892 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 40,317 | 614 | 1,120 | 1,314 | 30,000 | 1,179,592 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 30,151 | 834 | 2,983 | 3,383 | 61,287 | 0 | 1,388 | 841,965 | 0 |
trypema (Hybrid + Absolute) | 9,643,241 | 1 | 1 | 954 | 30,460 | 289,287,347 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 2,809,619 | 1 | 620 | 373,247 | 251,100 | 0 | 7,282 | 84,036,035 | 0 |
key_space=1,000, rate_limit_per_s=10
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 53,992 | 464 | 636 | 1,559 | 1,619,850 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 44,076 | 545 | 813 | 1,583 | 1,322,349 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 37,450 | 677 | 952 | 1,746 | 300,000 | 823,607 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 28,353 | 941 | 1,246 | 2,061 | 311,600 | 0 | 18,935 | 520,145 | 0 |
trypema (Hybrid + Absolute) | 8,243,810 | 1 | 11 | 34,303 | 356,529 | 246,977,824 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 2,590,528 | 1 | 662 | 454,399 | 1,902,681 | 0 | 47,563 | 75,768,253 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 59,207 | 411 | 830 | 1,040 | 1,776,360 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 47,497 | 489 | 996 | 1,057 | 1,425,018 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 38,932 | 633 | 1,174 | 1,247 | 300,000 | 868,025 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 30,159 | 821 | 2,277 | 2,415 | 312,016 | 0 | 17,266 | 575,556 | 0 |
trypema (Hybrid + Absolute) | 9,515,914 | 1 | 1 | 64,767 | 205,380 | 285,299,319 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 3,118,709 | 1 | 599 | 384,511 | 1,660,887 | 0 | 33,649 | 91,873,494 | 0 |
key_space=1,000, rate_limit_per_s=100
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 53,991 | 471 | 679 | 1,290 | 1,619,896 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 44,357 | 544 | 743 | 3,253 | 1,330,776 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 33,770 | 823 | 1,303 | 3,767 | 1,013,215 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 29,844 | 899 | 1,527 | 2,965 | 895,378 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 8,191,257 | 1 | 1 | 10,279 | 3,359,642 | 242,424,453 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 3,145,538 | 1 | 639 | 338,943 | 13,237,748 | 0 | 295,475 | 81,227,967 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 59,892 | 398 | 931 | 1,196 | 1,796,855 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 47,584 | 454 | 1,499 | 4,711 | 1,427,684 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 35,677 | 798 | 1,424 | 2,347 | 1,070,389 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 32,818 | 792 | 1,263 | 4,057 | 984,600 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 9,521,866 | 1 | 1 | 80,831 | 3,572,333 | 282,109,505 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 3,626,560 | 1 | 579 | 377,855 | 14,795,671 | 0 | 118,031 | 93,892,950 | 0 |
key_space=1,000, rate_limit_per_s=10,000
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 54,046 | 471 | 754 | 3,579 | 1,621,469 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 44,142 | 545 | 803 | 2,305 | 1,324,384 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 34,226 | 768 | 1,319 | 3,121 | 1,026,845 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 29,605 | 902 | 1,312 | 2,027 | 888,248 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 9,008,798 | 1 | 9 | 4,411 | 270,637,483 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 8,487,169 | 1 | 2 | 1,991 | 254,627,326 | 0 | 0 | 0 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 62,460 | 359 | 702 | 1,032 | 1,873,949 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,213 | 447 | 776 | 1,137 | 1,446,500 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 35,585 | 719 | 983 | 1,420 | 1,067,649 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 33,839 | 781 | 1,867 | 1,869 | 1,015,205 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 11,530,183 | 1 | 1 | 1,612,799 | 212,220,227 | 133,697,111 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,728,075 | 1 | 1 | 4,997,119 | 258,062,617 | 0 | 27,349,341 | 6,445,919 | 2 |
key_space=1,000, rate_limit_per_s=100,000
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 53,807 | 475 | 747 | 3,865 | 1,614,363 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 44,339 | 539 | 755 | 1,204 | 1,330,254 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 34,103 | 784 | 1,454 | 2,635 | 1,023,193 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 29,428 | 920 | 1,491 | 2,523 | 882,934 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 7,358,353 | 1 | 6 | 3,647 | 220,779,709 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 7,216,898 | 1 | 8 | 1,297 | 216,521,918 | 0 | 0 | 0 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 71,704 | 300 | 672 | 722 | 2,151,244 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 49,621 | 412 | 530 | 1,170 | 1,488,738 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 39,925 | 575 | 1,325 | 1,476 | 1,197,838 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 34,666 | 738 | 1,364 | 1,426 | 1,040,039 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 14,560,182 | 1 | 1 | 589 | 436,829,976 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 13,351,371 | 1 | 1 | 668 | 400,556,035 | 0 | 0 | 0 | 0 |
key_space=10,000, rate_limit_per_s=1
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 53,367 | 472 | 697 | 2,705 | 1,601,356 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 43,677 | 560 | 807 | 3,661 | 1,310,644 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 36,326 | 718 | 1,286 | 2,631 | 300,000 | 790,020 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 29,249 | 947 | 1,961 | 12,455 | 418,521 | 0 | 14,643 | 444,494 | 0 |
trypema (Hybrid + Absolute) | 6,234,742 | 1 | 366 | 526,335 | 428,909 | 186,650,383 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 51,110 | 2,103 | 3,063 | 1,065,983 | 309,754 | 0 | 41,789 | 1,182,518 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 68,919 | 297 | 421 | 1,666 | 2,067,964 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 47,609 | 425 | 675 | 10,543 | 1,428,641 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 40,026 | 592 | 1,474 | 3,589 | 300,000 | 901,138 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 31,522 | 832 | 2,877 | 4,191 | 422,336 | 0 | 13,071 | 510,495 | 0 |
trypema (Hybrid + Absolute) | 5,650,618 | 1 | 392 | 192,383 | 443,519 | 169,136,267 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 58,723 | 2,607 | 3,769 | 555,519 | 299,297 | 0 | 66,433 | 1,410,444 | 0 |
key_space=10,000, rate_limit_per_s=10
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 53,748 | 480 | 1,251 | 3,209 | 1,612,799 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 43,898 | 552 | 853 | 2,153 | 1,317,217 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 33,690 | 779 | 1,363 | 2,841 | 1,010,942 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 30,091 | 914 | 1,791 | 9,247 | 902,940 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 8,275,750 | 1 | 46 | 251,647 | 4,127,161 | 244,238,026 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 213,605 | 1,057 | 2,081 | 539,647 | 3,734,286 | 0 | 91,994 | 2,649,423 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 69,760 | 302 | 531 | 998 | 2,093,306 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,327 | 414 | 684 | 1,145 | 1,450,165 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 37,626 | 661 | 991 | 1,701 | 1,129,106 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 31,374 | 832 | 1,622 | 2,967 | 941,398 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 4,817,229 | 1 | 589 | 6,737,919 | 4,277,692 | 140,264,903 | 0 | 0 | 5 |
trypema (Hybrid + Suppressed) | 123,785 | 2,083 | 2,927 | 635,391 | 2,685,018 | 0 | 592,420 | 436,776 | 0 |
key_space=10,000, rate_limit_per_s=100
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 59,491 | 390 | 2,209 | 4,959 | 1,785,160 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,508 | 476 | 620 | 1,150 | 1,455,706 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 35,655 | 747 | 3,203 | 38,815 | 1,069,952 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 33,470 | 778 | 1,371 | 3,115 | 1,004,350 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 5,683,238 | 1 | 85 | 52,063 | 31,297,611 | 139,243,571 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 1,096,356 | 1 | 1,610 | 492,543 | 30,084,036 | 0 | 2,120,136 | 693,408 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 54,883 | 400 | 2,737 | 5,103 | 1,646,800 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 44,047 | 475 | 1,006 | 2,053 | 1,321,642 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 34,512 | 681 | 876 | 1,523 | 1,035,553 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 31,754 | 813 | 1,273 | 1,549 | 952,784 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 5,619,250 | 1 | 485 | 106,751 | 30,910,552 | 137,696,051 | 0 | 0 | 9 |
trypema (Hybrid + Suppressed) | 730,461 | 1 | 2,351 | 600,575 | 21,225,719 | 0 | 667,839 | 24,103 | 0 |
key_space=10,000, rate_limit_per_s=10,000
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 59,707 | 394 | 1,984 | 4,495 | 1,791,927 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,515 | 469 | 651 | 1,484 | 1,455,813 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 37,454 | 663 | 899 | 1,402 | 1,123,948 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 31,533 | 836 | 1,794 | 2,393 | 946,262 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 10,069,860 | 1 | 2 | 1,291 | 302,213,556 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 6,293,406 | 1 | 11 | 13,119 | 188,865,545 | 0 | 0 | 0 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 59,170 | 407 | 2,691 | 4,871 | 1,775,400 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 44,435 | 481 | 1,188 | 1,451 | 1,333,307 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 33,689 | 686 | 1,010 | 1,136 | 1,010,859 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 30,765 | 867 | 1,879 | 2,667 | 923,129 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 10,270,907 | 1 | 1 | 2,665 | 308,181,918 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,500,654 | 1 | 1 | 2,401 | 285,069,535 | 0 | 0 | 0 | 0 |
key_space=10,000, rate_limit_per_s=100,000
tokio runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 59,048 | 402 | 2,383 | 3,965 | 1,772,022 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 48,577 | 472 | 637 | 2,419 | 1,457,675 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 38,260 | 654 | 968 | 2,069 | 1,148,188 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 33,729 | 805 | 1,354 | 2,381 | 1,012,179 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 9,690,774 | 1 | 9 | 11,175 | 290,829,099 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,469,741 | 1 | 1 | 2,695 | 284,162,478 | 0 | 0 | 0 | 0 |
smol runtime
| Backend | ops/s | p99 (us) | p99.9 (us) | max (us) | allowed | rejected | suppressed_allowed | suppressed_denied | errors |
|---|---|---|---|---|---|---|---|---|---|
redis-cell (CL.THROTTLE) | 56,624 | 399 | 2,695 | 11,519 | 1,699,018 | 0 | 0 | 0 | 0 |
gcra (Lua allowN-style) | 44,143 | 471 | 823 | 1,303 | 1,324,531 | 0 | 0 | 0 | 0 |
trypema (Redis + Absolute) | 33,799 | 696 | 1,260 | 4,747 | 1,014,164 | 0 | 0 | 0 | 0 |
trypema (Redis + Suppressed) | 31,080 | 803 | 1,441 | 2,207 | 932,572 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Absolute) | 10,865,742 | 1 | 1 | 3,577 | 326,026,813 | 0 | 0 | 0 | 0 |
trypema (Hybrid + Suppressed) | 9,423,345 | 1 | 1 | 3,085 | 282,749,003 | 0 | 0 | 0 | 0 |
Notes:
- All observed errors in these runs are Redis timeouts (
RedisError(timed out)) surfaced during Hybrid state reads. - Matrix results above were captured with both the tokio runtime (
make stress-redis-uniform-matrix-tokio) and the smol runtime (make stress-redis-uniform-matrix-smol).

