地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Redis】memtier_benchmarkでredisのベンチマークを取る

github.com

memtier_benchmarkを使うとredisやmemcachedベンチマークを取得できるらしく使ってみました。

dockerを使ってさくっとやってみます。-tでスレッド数-cでコネクション数-nでそれぞれのコネクションでどの程度のリクエストを投げるかを調整できます。

docker run --rm redislabs/memtier_benchmark:latest -s ${SERVER_IP} -p 6379 -a test12345 -t 4 -c 30 -n 10000
[RUN #1] Preparing benchmark client...
[RUN #1] Launching threads now...
[RUN #1 100%, 285 secs]  0 threads:     1200000 ops,    5476 (avg:    4208) ops/sec, 233.43KB/sec (avg: 178.51KB/sec), 22.04 (avg: 1746.48) msec latencyncy

4         Threads
30        Connections per thread
10000     Requests per client


ALL STATS
=========================================================================
Type         Ops/sec     Hits/sec   Misses/sec      Latency       KB/sec
-------------------------------------------------------------------------
Sets          383.16          ---          ---   1955.85700        29.51
Gets         3827.39         0.00      3827.39   1725.52400       149.09
Waits           0.00          ---          ---      0.00000          ---
Totals       4210.55         0.00      3827.39   1746.48400       178.60

見るべきなのはOps/SecでしょうかGetとSetがそれぞれどの程度でているかを確認できます。

pmapをみてみる

特に面白いものは見れなかった。arm特有の何かしらを期待したけど特にはなさそう。anonになってるあたりが恐らくredisのデータ領域でしょうか。read onlyなanonの用途はさっぱりわからず。

Address           Kbytes     RSS   Dirty Mode   Mapping
0000000000400000    1276     672       0 r-x--  redis-server
000000000073f000      24      24      24 rw---  redis-server
0000000000745000      92      92      92 rw---    [ anon ]
00000000011a3000     132      56      56 rw---    [ anon ]
00000039fa800000     128      40       0 r-x--  ld-2.12.so
00000039faa20000       4       4       4 r----  ld-2.12.so
00000039faa21000       4       4       4 rw---  ld-2.12.so
00000039faa22000       4       4       4 rw---    [ anon ]
00000039fac00000       8       4       0 r-x--  libdl-2.12.so
00000039fac02000    2048       0       0 -----  libdl-2.12.so
00000039fae02000       4       4       4 r----  libdl-2.12.so
00000039fae03000       4       4       4 rw---  libdl-2.12.so
00000039fb000000    1576     508       0 r-x--  libc-2.12.so
00000039fb18a000    2048       0       0 -----  libc-2.12.so
00000039fb38a000      16      16       8 r----  libc-2.12.so
00000039fb38e000       8       8       8 rw---  libc-2.12.so
00000039fb390000      16      12      12 rw---    [ anon ]
00000039fb400000      92      72       0 r-x--  libpthread-2.12.so
00000039fb417000    2048       0       0 -----  libpthread-2.12.so
00000039fb617000       4       4       4 r----  libpthread-2.12.so
00000039fb618000       4       4       4 rw---  libpthread-2.12.so
00000039fb619000      16       4       4 rw---    [ anon ]
00000039fc000000     524       4       0 r-x--  libm-2.12.so
00000039fc083000    2044       0       0 -----  libm-2.12.so
00000039fc282000       4       4       4 r----  libm-2.12.so
00000039fc283000       4       4       4 rw---  libm-2.12.so
00007fa14b600000  370688  331656  331656 rw---    [ anon ]
00007fa1621fd000       4       0       0 -----    [ anon ]
00007fa1621fe000   10240       8       8 rw---    [ anon ]
00007fa162bfe000       4       0       0 -----    [ anon ]
00007fa162bff000   10240       8       8 rw---    [ anon ]
00007fa1635ff000       4       0       0 -----    [ anon ]
00007fa163600000   10240    2048    2048 rw---    [ anon ]
00007fa164000000    2048    2048    2048 rw---    [ anon ]
00007fa16436b000   96852       0       0 r----  locale-archive
00007fa16a200000    2048    2048    2048 rw---    [ anon ]
00007fa16a5f9000      16      16      16 rw---    [ anon ]
00007fa16a60f000       4       4       4 rw---    [ anon ]
00007fff55af5000      84      20      20 rw---    [ stack ]
00007fff55b8f000       4       4       0 r-x--    [ anon ]
ffffffffff600000       4       0       0 r-x--    [ anon ]

armだけではないけどlibpthread.soを読んでるのは若干不思議だったけどredisはシングルスレッド動作というのはメモリの管理のみでバックグラウンドで行うAOFとかメモリのevictは別スレッドでやるらしい。6.0以外でもスレッドが複数いるのはこれが原因。AOF書きながらクライアント応答もすると思いったけどそんなわけはなかった。(計算量の多い処理があると処理がブロックされるのは変わらないので注意が必要)

blog.orz.at

エラーはどういう時に出るのか

公式FAQにあったが基本的には性能低下はネットワークが原因になることが多いらしい。次にメモリでメモリの使用率が高くなると書き込みたいメモリのサイズの探索が走ったりswapが走ったりするので遅くなる。

redis-documentasion-japanese.readthedocs.io

evictするのも良さそうだけどevictに追いつくくらいのメモリ使用率とかだとそれはそれで性能は低下しそう(未検証)

メモリの使用率とかを見てみる

infoとかで見れるやつ。この辺は何が違うのかを理解して見ていく必要があると感じた。

redis.io

used_memory

Redisがアロケータ (標準libc, jemalloc あるいは tcmallocなどの代替のアロケータ)を使用して割り当てた総バイト数

実装はこの辺

// この辺数をredisはatomicにメモリサイズとして使っている
static redisAtomic size_t used_memory = 0;

// updateはこの関数
#define update_zmalloc_stat_alloc(__n) atomicIncr(used_memory,(__n))
#define update_zmalloc_stat_free(__n) atomicDecr(used_memory,(__n))

// この関数を読んで取得
size_t zmalloc_used_memory(void) {
    size_t um;
    atomicGet(used_memory,um);
    return um;
}
used_memory_rss

オペレーティングシステムから見たRedisが割り当てたバイト数 (別名 常駐セットサイズ)。これは top(1) と ps(1)のようなツールによって報告された数です

psなどで出力されるrssの値なのでバイナリ自身や共有ライブラリもこの値に含まれる。

実装はこの辺。procfsをそのまま除くという感じだった。_SC_PAGESIZEとかやってるけど特殊環境で走らせるとこの辺の数値が4kを返さなかったりするからバグりそう。

size_t zmalloc_get_rss(void) {
    int page = sysconf(_SC_PAGESIZE);
    size_t rss;
    int fd, count;
    char *p, *x;

    snprintf(filename,256,"/proc/%ld/stat",(long) getpid());
    if ((fd = open(filename,O_RDONLY)) == -1) return 0;
    if (read(fd,buf,4096) <= 0) {
        close(fd);
        return 0;
    }
    return rss;
}

以下はそれぞれの関係式をまとめてみた。

used_memory_rss > used_memory

関係が一番良い動作。バイナリとかライブラリ以外は全てredisのメモリアロケーション配下になっている

used_memory > used_memory_rss

場合はswapしている領域をredisが使っている可能性がある。rssにはswap領域は加わらない

used_memory_rss >>> used_memorn

redisが管理しているメモリよりもOS的にはもっと使っているように見えている(メモリの断片化)。

used_memory_peak

Redisによって消費されたピークメモリ (バイト単位)

used_memoryの過去の最大値。rssの最大値ではないので注意

実装はredisServerというバカでかい構造体で保持している。仕事以外では読みたくないぐらいでかいw

github.com

mem_fragmentation_ratio

used_memory_rssとused_memory間の比率