Skip to content

Instantly share code, notes, and snippets.

@koron
Last active August 15, 2022 03:56
Show Gist options
  • Save koron/0917506b5d30d1f4488389c2d7666a76 to your computer and use it in GitHub Desktop.
Save koron/0917506b5d30d1f4488389c2d7666a76 to your computer and use it in GitHub Desktop.
Compare memory usage between Dragonfly and Redis

Compare memory usage between Dragonfly and Redis

  • redis:7.0.4-alpine3.16

    $ docker run --rm -it -p 6379:6379 --name mem-redis redis:7.0.4-alpine3.16
  • dragonfly

    $ docker run --rm -it -p 6380:6379 --name mem-dragon --ulimit memlock=-1 docker.dragonflydb.io/dragonflydb/dragonfly:v0.4.0

つまりほぼデフォルト設定ということ。

Comparison at startup

docker stats で数秒間隔で3回計測

$ docker stats --no-stream
CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT    MEM %     NET I/O     BLOCK I/O   PIDS
f46762c52191   mem-dragon   6.53%     4.062MiB / 11.7GiB   0.03%     656B / 0B   0B / 0B     7
768780b69d7c   mem-redis    0.05%     2.379MiB / 11.7GiB   0.02%     876B / 0B   0B / 0B     5

$ docker stats --no-stream
CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT    MEM %     NET I/O     BLOCK I/O   PIDS
f46762c52191   mem-dragon   6.46%     4.062MiB / 11.7GiB   0.03%     726B / 0B   0B / 0B     7
768780b69d7c   mem-redis    0.05%     2.379MiB / 11.7GiB   0.02%     946B / 0B   0B / 0B     5

$ docker stats --no-stream
CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT    MEM %     NET I/O     BLOCK I/O   PIDS
f46762c52191   mem-dragon   6.52%     4.062MiB / 11.7GiB   0.03%     726B / 0B   0B / 0B     7
768780b69d7c   mem-redis    0.06%     2.379MiB / 11.7GiB   0.02%     946B / 0B   0B / 0B     5

dragonflyのほうがCPU使用率が高く、使用メモリも多い

$ redis-cli -p 6379 info memory | grep human
used_memory_human:904.26K
used_memory_rss_human:6.48M
used_memory_peak_human:904.26K
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B

$ redis-cli -p 6380 info memory | grep human
used_memory_human:860.3KiB
used_memory_rss_human:9.98MiB
maxmemory_human:8.94GiB

dragonflyのほうが info で読める項目がかなり少ない。 比較可能な項目は3つ。

  • used_memory_human - サーバーが認識している、malloc等で割り当てたメモリ総量
  • used_memory_rss_human - OSから見たメモリ使用総量。仮想メモリを含む
  • maxmemory_human - maxmemory の設定値。比較する意味なし

なので容易に比較可能なのは前2項目 (ほかに比較できるものもあるがちゃんと見る意味はない)

まとめると起動時点では:

  • コンテナを通して見るとdragonflyのほうがメモリ使用量が多く、CPU使用率が大きい
  • サーバー自身が認識しているメモリ使用量はredisのほうが多い
  • OSが認識しているメモリ使用量はdragonflyのほうが多い

推測ではあるが、dragonflyはマルチスレッドで動いてるため、 スレッド間で何らかの調停が必要でアイドル時でもCPUを必要とするし、 スレッドのローカルメモリーというmalloc外で確保され OS等が認識しているメモリが表出していると考えられる。

Comparison at many contents

ベンチマークの流れは以下の通り:

  1. redis-benchmark -t set で大量のキーを作る

    ランダムに10万キーを作成する。値は3バイト。

  2. メモリ使用量を確認する

Redis

$ redis-benchmark -p 6379 -t set -r 100000 -n 1000000
====== SET ======
  1000000 requests completed in 19.96 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

50.79% <= 1 milliseconds
97.71% <= 2 milliseconds
99.90% <= 3 milliseconds
99.96% <= 4 milliseconds
99.98% <= 5 milliseconds
100.00% <= 6 milliseconds
100.00% <= 6 milliseconds
50092.67 requests per second

$ redis-cli -p 6379 dbsize
(integer) 99994

$ docker stats --no-stream mem-redis
CONTAINER ID   NAME        CPU %     MEM USAGE / LIMIT    MEM %     NET I/O        BLOCK I/O     PIDS
517aa55b283c   mem-redis   0.05%     10.68MiB / 11.7GiB   0.09%     116MB / 71MB   0B / 3.06MB   5

$ redis-cli -p 6379 info memory | grep human
used_memory_human:8.77M
used_memory_rss_human:14.72M
used_memory_peak_human:9.82M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B

Dragonfly

$ redis-benchmark -p 6380 -t set -r 100000 -n 1000000
====== SET ======
  1000000 requests completed in 20.71 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

47.37% <= 1 milliseconds
96.54% <= 2 milliseconds
99.82% <= 3 milliseconds
99.92% <= 4 milliseconds
99.96% <= 5 milliseconds
99.98% <= 6 milliseconds
99.99% <= 7 milliseconds
100.00% <= 8 milliseconds
100.00% <= 9 milliseconds
100.00% <= 10 milliseconds
100.00% <= 11 milliseconds
100.00% <= 11 milliseconds
48295.18 requests per second

$ redis-cli -p 6380 dbsize
(integer) 99998

$ docker stats --no-stream mem-dragon
CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT    MEM %     NET I/O        BLOCK I/O   PIDS
f46762c52191   mem-dragon   6.45%     10.39MiB / 11.7GiB   0.09%     116MB / 71MB   0B / 0B     7

$ redis-cli -p 6380 info memory | grep human
used_memory_human:6.74MiB
used_memory_rss_human:16.61MiB
maxmemory_human:8.94GiB

Consideration

  1. 純粋な set 速度は若干ではあるがDragonflyのほうが遅い

    おおよそ4%ほど(5万req/secに対して4.8万req/sec) ただしどちらも同一PCで動かしているのでその分の考慮は必要かもしれない。

  2. コンテナを通して見るとDragonflyのほうが若干メモリ使用量が少ない。

    10万キーでおおよそ3%

  3. malloc量はDragonflyが20%以上少ない

  4. RSSベースでみるとDragonflyのほうが13%近く多い

確かにDragonflyのほうが使用メモリが少なくなってる気配がある。

しかしRSSベースの比較ではそうでもない。スレッド分だろうか?

件数をさらに多くしてみたほうが良いかも。

今の設定は10万件、100万回だけど、メモリ使用量だけみるならもっと絞って良さそう。

Compare inceasing contents

Redis (1-redis.log)

Size Container Malloc RSS
100000 10.59M 8.77M 14.72M
200000 18.61M 16.62M 22.66M
300000 28.64M 25.47M 31.68M
400000 35.57M 32.32M 39.68M
500000 41.41M 39.15M 45.55M

Dragonfly (2-dragonfly.log)

Size Container Malloc RSS
100000 10.36M 6.74M 16.22M
200000 16.80M 13.27M 22.60M
300000 28.30M 24.79M 34.15M
400000 29.80M 26.31M 35.74M
500000 32.29M 28.74M 38.29M

40万件を超えたあたりからDragonflyが有意に少なくなっている。

$ redis-benchmark -p 6379 -t set -r 100000000 -n 100000 -q
SET: 48732.94 requests per second
$ redis-cli -p 6379 dbsize
(integer) 99939
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
af7aeb11c1ea mem-redis 0.05% 10.59MiB / 11.7GiB 0.09% 11.6MB / 7.12MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:8.77M
used_memory_rss_human:14.72M
used_memory_peak_human:9.79M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 200000 -q
SET: 50012.50 requests per second
$ redis-cli -p 6379 dbsize
(integer) 199782
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
a26f4bbfd3a6 mem-redis 0.05% 18.61MiB / 11.7GiB 0.16% 23.2MB / 14.2MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:16.62M
used_memory_rss_human:22.66M
used_memory_peak_human:17.65M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 300000 -q
SET: 49925.11 requests per second
$ redis-cli -p 6379 dbsize
(integer) 299540
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
8336171c47a8 mem-redis 0.05% 28.64MiB / 11.7GiB 0.24% 34.9MB / 21.3MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:25.47M
used_memory_rss_human:31.68M
used_memory_peak_human:28.25M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 400000 -q
SET: 50314.46 requests per second
$ redis-cli -p 6379 dbsize
(integer) 399196
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
facd6f398956 mem-redis 0.06% 35.57MiB / 11.7GiB 0.30% 46.5MB / 28.4MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:32.32M
used_memory_rss_human:39.68M
used_memory_peak_human:33.34M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 500000 -q
SET: 50449.00 requests per second
$ redis-cli -p 6379 dbsize
(integer) 498764
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
53eda828b6b9 mem-redis 0.06% 41.41MiB / 11.7GiB 0.35% 58MB / 35.5MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:39.15M
used_memory_rss_human:45.55M
used_memory_peak_human:40.18M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 100000 -q
SET: 48732.94 requests per second
$ redis-cli -p 6379 dbsize
(integer) 99939
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
af7aeb11c1ea mem-redis 0.05% 10.59MiB / 11.7GiB 0.09% 11.6MB / 7.12MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:8.77M
used_memory_rss_human:14.72M
used_memory_peak_human:9.79M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 200000 -q
SET: 50012.50 requests per second
$ redis-cli -p 6379 dbsize
(integer) 199782
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
a26f4bbfd3a6 mem-redis 0.05% 18.61MiB / 11.7GiB 0.16% 23.2MB / 14.2MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:16.62M
used_memory_rss_human:22.66M
used_memory_peak_human:17.65M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 300000 -q
SET: 49925.11 requests per second
$ redis-cli -p 6379 dbsize
(integer) 299540
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
8336171c47a8 mem-redis 0.05% 28.64MiB / 11.7GiB 0.24% 34.9MB / 21.3MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:25.47M
used_memory_rss_human:31.68M
used_memory_peak_human:28.25M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 400000 -q
SET: 50314.46 requests per second
$ redis-cli -p 6379 dbsize
(integer) 399196
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
facd6f398956 mem-redis 0.06% 35.57MiB / 11.7GiB 0.30% 46.5MB / 28.4MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:32.32M
used_memory_rss_human:39.68M
used_memory_peak_human:33.34M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B
$ redis-benchmark -p 6379 -t set -r 100000000 -n 500000 -q
SET: 50449.00 requests per second
$ redis-cli -p 6379 dbsize
(integer) 498764
$ docker stats --no-stream mem-redis
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
53eda828b6b9 mem-redis 0.06% 41.41MiB / 11.7GiB 0.35% 58MB / 35.5MB 0B / 0B 5
$ redis-cli -p 6379 info memory | grep human
used_memory_human:39.15M
used_memory_rss_human:45.55M
used_memory_peak_human:40.18M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B

Set large number of keys

  • redis:7.0.4-alpine3.16

    $ docker run --rm -it -p 6379:6379 --name mem-redis redis:7.0.4-alpine3.16 --save "" --appendonly no

    ディスクに書かないようにした。

  • dragonfly

    $ docker run --rm -it -p 6380:6379 --name mem-dragon --ulimit memlock=-1 docker.dragonflydb.io/dragonflydb/dragonfly:v0.4.0

    もともと暗黙的にディスクに書くことはないらしい。

Summary

概ねDragonflyのほうが小さくなる。100M個のkeyでは約1.2GB(20%相当)も異なる。

Dragonfly

Size Container Malloc RSS
1M 61.54MiB 57.74MiB 67.03MiB
10M 798.7MiB 792.64MiB 802.90MiB
100M 6.484GiB 6.46GiB 6.48GiB

Redis

Size Container Malloc RSS
1M 80.39MiB 77.56MiB 83.97MiB
10M 826.2MiB 814.00MiB 855.21MiB
100M 7.652GiB 7.55GiB 7.64GiB

Parallel processing

スレッド数が少ないうちはRedisのほうがパフォーマンスが良い。 スレッド数が増えると(本計測では128スレッドから)逆転する。

Dragonfly

$ redis-benchmark -p 6380 -c 1 -t set -r 100000000000 -n 1000000
SET: 2217.32

$ redis-benchmark -p 6380 -c 2 -t set -r 100000000000 -n 1000000
SET: 4021.99

$ redis-benchmark -p 6380 -c 4 -t set -r 100000000000 -n 1000000
SET: 8207.76

$ redis-benchmark -p 6380 -c 8 -t set -r 100000000000 -n 1000000
SET: 15476.01

$ redis-benchmark -p 6380 -c 16 -t set -r 100000000000 -n 1000000
SET: 26968.31

$ redis-benchmark -p 6380 -c 32 -t set -r 100000000000 -n 1000000
SET: 39939.89

$ redis-benchmark -p 6380 -c 64 -t set -r 100000000000 -n 1000000
SET: 52767.00

$ redis-benchmark -p 6380 -c 128 -t set -r 100000000000 -n 1000000
SET: 57385.52

Redis

$ redis-benchmark -p 6379 -c 1 -t set -r 100000000000 -n 1000000
SET: 2437.10

$ redis-benchmark -p 6379 -c 2 -t set -r 100000000000 -n 1000000
SET: 4721.11

$ redis-benchmark -p 6379 -c 4 -t set -r 100000000000 -n 1000000
SET: 9020.48

$ redis-benchmark -p 6379 -c 8 -t set -r 100000000000 -n 1000000
SET: 17048.82

$ redis-benchmark -p 6379 -c 16 -t set -r 100000000000 -n 1000000
SET: 29695.61

$ redis-benchmark -p 6379 -c 32 -t set -r 100000000000 -n 1000000
SET: 44350.43

$ redis-benchmark -p 6379 -c 64 -t set -r 100000000000 -n 1000000
SET: 53059.89

$ redis-benchmark -p 6379 -c 128 -t set -r 100000000000 -n 1000000
SET: 55254.50

どちらもQPSが安定したあたりで計測を止めた。

Lage number of keys

Dragonfly

1M keys

$ redis-benchmark -p 6380 -t set -r 100000000000 -n 1000000
====== SET ======
  1000000 requests completed in 20.83 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

47.25% <= 1 milliseconds
96.05% <= 2 milliseconds
99.85% <= 3 milliseconds
99.97% <= 4 milliseconds
99.98% <= 5 milliseconds
99.99% <= 6 milliseconds
99.99% <= 7 milliseconds
100.00% <= 8 milliseconds
100.00% <= 9 milliseconds
100.00% <= 10 milliseconds
100.00% <= 11 milliseconds
100.00% <= 12 milliseconds
100.00% <= 13 milliseconds
100.00% <= 14 milliseconds
100.00% <= 14 milliseconds
48014.60 requests per second

$ redis-cli -p 6380 dbsize
(integer) 999767

$ redis-cli -p 6380 info memory | grep human
used_memory_human:57.74MiB
used_memory_rss_human:67.03MiB
maxmemory_human:8.96GiB

$ docker stats --no-stream
CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT    MEM %     NET I/O        BLOCK I/O   PIDS
e2b7857c0cdb   mem-dragon   6.67%     61.54MiB / 11.7GiB   0.51%     116MB / 71MB   0B / 0B     7

10M keys

$ redis-benchmark -p 6380 -t set -r 100000000000 -n 9000000
====== SET ======
  9000000 requests completed in 195.36 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

46.05% <= 1 milliseconds
95.19% <= 2 milliseconds
99.74% <= 3 milliseconds
99.93% <= 4 milliseconds
99.97% <= 5 milliseconds
99.99% <= 6 milliseconds
100.00% <= 7 milliseconds
100.00% <= 8 milliseconds
100.00% <= 9 milliseconds
100.00% <= 10 milliseconds
100.00% <= 10 milliseconds
46069.50 requests per second

$ redis-cli -p 6380 dbsize
(integer) 9976674

$ redis-cli -p 6380 info memory | grep human
used_memory_human:792.64MiB
used_memory_rss_human:802.90MiB
maxmemory_human:8.96GiB

$ docker stats --no-stream
CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT    MEM %     NET I/O          BLOCK I/O   PIDS
e2b7857c0cdb   mem-dragon   6.75%     798.7MiB / 11.7GiB   6.67%     1.16GB / 710MB   0B / 0B     7

100M

$ redis-benchmark -p 6380 -t set -r 100000000000 -n 90000000
====== SET ======
  90000000 requests completed in 2051.72 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

37.50% <= 0 milliseconds
...
100.00% <= 36 milliseconds
43865.72 requests per second

$ redis-cli -p 6380 dbsize
(integer) 97707113

$ redis-cli -p 6380 info memory | grep human
used_memory_human:6.46GiB
used_memory_rss_human:6.48GiB
maxmemory_human:8.95GiB

$ docker stats --no-stream
CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT    MEM %     NET I/O          BLOCK I/O   PIDS
e2b7857c0cdb   mem-dragon   6.99%     6.484GiB / 11.7GiB   55.43%    11.6GB / 7.1GB   0B / 0B     7

Redis

1M keys

$ redis-benchmark -p 6379 -t set -r 100000000000 -n 1000000
====== SET ======
  1000000 requests completed in 20.60 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

48.52% <= 1 milliseconds
96.80% <= 2 milliseconds
99.80% <= 3 milliseconds
99.97% <= 4 milliseconds
99.99% <= 5 milliseconds
99.99% <= 6 milliseconds
100.00% <= 7 milliseconds
100.00% <= 8 milliseconds
48548.40 requests per second

$ redis-cli -p 6379 dbsize
(integer) 999766

$ redis-cli -p 6379 info memory | grep human
used_memory_human:77.56M
used_memory_rss_human:83.97M
used_memory_peak_human:78.58M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B

$ docker stats --no-stream
CONTAINER ID   NAME        CPU %     MEM USAGE / LIMIT    MEM %     NET I/O        BLOCK I/O   PIDS
743bd9125e83   mem-redis   0.10%     80.39MiB / 11.7GiB   0.67%     116MB / 71MB   0B / 0B     5

10M keys

$ redis-benchmark -p 6379 -t set -r 100000000000 -n 9000000
====== SET ======
  9000000 requests completed in 199.65 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

45.14% <= 1 milliseconds
95.30% <= 2 milliseconds
99.72% <= 3 milliseconds
99.95% <= 4 milliseconds
99.98% <= 5 milliseconds
99.99% <= 6 milliseconds
100.00% <= 7 milliseconds
100.00% <= 8 milliseconds
100.00% <= 9 milliseconds
100.00% <= 10 milliseconds
100.00% <= 11 milliseconds
100.00% <= 11 milliseconds
45078.66 requests per second

$ redis-cli -p 6379 dbsize
(integer) 9977069

$ redis-cli -p 6379 info memory | grep human
used_memory_human:814.00M
used_memory_rss_human:828.15M
used_memory_peak_human:855.21M
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B

$ docker stats --no-stream
CONTAINER ID   NAME        CPU %     MEM USAGE / LIMIT    MEM %     NET I/O          BLOCK I/O   PIDS
743bd9125e83   mem-redis   0.09%     826.2MiB / 11.7GiB   6.90%     1.16GB / 710MB   0B / 0B     5

100M keys

$ redis-benchmark -p 6379 -t set -r 100000000000 -n 90000000
====== SET ======
  90000000 requests completed in 1920.08 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

48.12% <= 1 milliseconds
96.51% <= 2 milliseconds
99.81% <= 3 milliseconds
99.97% <= 4 milliseconds
99.99% <= 5 milliseconds
100.00% <= 6 milliseconds
...
100.00% <= 62 milliseconds
46872.95 requests per second

$ redis-cli -p 6379 dbsize
(integer) 97706566

$ redis-cli -p 6379 info memory | grep human
used_memory_human:7.55G
used_memory_rss_human:7.64G
used_memory_peak_human:7.55G
total_system_memory_human:11.70G
used_memory_lua_human:31.00K
used_memory_vm_total_human:63.00K
used_memory_scripts_human:184B
maxmemory_human:0B

$ docker stats --no-stream
CONTAINER ID   NAME        CPU %     MEM USAGE / LIMIT    MEM %     NET I/O          BLOCK I/O   PIDS
743bd9125e83   mem-redis   0.07%     7.652GiB / 11.7GiB   65.42%    11.6GB / 7.1GB   0B / 0B     5

Benchmark with memtier_benchmark

  • redis:7.0.4-alpine3.16

    $ docker run --rm -it -p 6379:6379 --name mem-redis redis:7.0.4-alpine3.16 --save "" --appendonly no

    ディスクに書かないようにした。

  • dragonfly

    $ docker run --rm -it -p 6380:6379 --name mem-dragon --ulimit memlock=-1 docker.dragonflydb.io/dragonflydb/dragonfly:v0.4.0

レイテンシーについて memtier_benchmark を使って深堀した。

Try

Setup

$ docker run --rm -it redislabs/memtier_benchmark:1.4.0 --thread 1 -n 200000 -c 20 --ratio 1:0 -d 256 --distinct-client-seed --hide-histogram -s 172.17.0.2

{thead} x {client} x {number} のリクエストを投げる。

--ratio 1:0 でSETだけを実行している。

-d 256 データの長さは256バイトに設定しているが特に意味はなく、サンプルに合わせた。

レイテンシーではなくスループットを観測する。 thread, client, numberの組み合わせで、 ops/sec がもっとも大きくなるところを探る

Redis

パラメーター変えて実行:

  • 1スレッドの時にもっとも ops/sec が最も大きくなるっぽい 参考: 113704 ops/sec
  • クライアントを増やしても変わらない (c:2、n:1/2) 参考: 114852 ops/sec
  • スレッドを増やす (t:4, n:1/4) と遅くなる 参考: 57877 ops/sec

Redis自身が1スレッドなのでスレッド増えてもスケールしないっぽい。 サーバーもクライアントも1スレッドでブン回せる最大で止まる。

Dragonfly

パラメーター変えて実行:

  • 1スレッド時はRedisよりかなり遅い 参考: 48867 ops/sec

  • クライアントを増やしてもあまり変わらない (c:2、n:1/2) 参考: 50263 ops/sec

  • スレッドを増やす (t:4, n:1/4) と速くなる 参考: 227567 ops/sec

    t:5 n:1/5 のとき 262118 ops/sec

Dockerで割り当ててるCPUリソースが6/16であるためか 5スレッドくらいでサチり気味になる。 リクエスト処理に5コア、各種調停用に1コア使っちゃうからだと推定

Docker で動いてる memtier_benchmark もコアの取り合い戦に参加するから 話はシンプルではないかも

Summary

シングルスレッド性能はDragonflyのほうが悪い。約半分をちょっと欠けるといったところ。

Dragonflyはホストのスレッド(CPUコア数)に応じてスケールするっぽい。 3コア以上でRedisをしのぐ。

3クライアント以上が同時接続して初めて意味がある。

コネクション数はネットワーク帯域の影響を受けるはずだが、 サチュレーションを観測できてないので評価できない。

前回までの結果の再解釈

redis-benchmarkがどうやらシングルスレッドであることから、 最終的にクライアント(redis-benchmark)側の限界にあたっていた。

前回の結果に従えば、 Dragonflyでは1スレッドでもコネクション数が増えれば相対的に ops/sec が増えていたので、 最大性能はもうちょい詰められるかもしれない。

TL;DR

  • (SETの)Dragonflyのシングルコア性能はRedis比で半分以下
  • Dragonflyはコアにスケールするのに対し、Redisは一切しない
    • スケール限界はあるとおもうが現時点で不明
  • コアを増やせばRedis比で狙った性能を出しやすい
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment