redisに大量の汚れページの問題がある追跡記録

4774 ワード

転載先:https://www.zybuluo.com/SailorXiao/note/136014
ケース現場
オンラインで1台の機械のメモリ負荷が重いことを発見して、topの後で1つのredisプロセスが大量のメモリを占めていることを発見して、TOPの内容は以下の通りです:
27190   root    20   0  18.6g   18g  600 S  0.3     59.2    926:17.83   redis-server 

redisが18.6 Gの物理メモリを占めていることが分かった.redisはcacheのプログラムデータにしか使用されていないので不思議ですが、redisのinfoコマンドを実行すると、実際のデータ占有量は112 Mしかないことがわかりました.以下のようにします.
# Memory
used_memory:118140384
used_memory_human:112.67M
used_memory_rss:19903766528
used_memory_peak:17871578336
used_memory_peak_human:16.64G
used_memory_lua:31744
mem_fragmentation_ratio:168.48
mem_allocator:libc

そこでpmap-x 27190を用いてredisプロセスのメモリイメージ情報を表示し、結果は以下の通りである.
27190:   ./redis-server ../redis.conf
Address             Kbytes      RSS     Dirty           Mode        Mapping
0000000000400000    548         184         0           r-x--       redis-server
0000000000689000    16          16          16          rw---       redis-server
000000000068d000    80          80          80          rw---       [ anon ]
0000000001eb6000    132         132         132         rw---       [ anon ]
0000000001ed7000    19436648    19435752    19435752    rw---       [ anon ]
00007f5862cb2000    4           0           0           -----       [ anon ]

メモリの汚れたページが大量に存在することがわかりました.メモリ負荷の高い問題は、redisの汚れたページが大量のメモリを消費しているため、明らかになった.しかし、redisはなぜそんなに多くの汚れたページが存在するのだろうか.
ケース分析
linuxの汚れたページの定義を見ました.
   linux      ,                  ,                    ,       ,       ,linux            ,               ,           ,                      ,                      。

つまり、汚れたページは、メモリ内の多くのデータがディスクに更新されないためです.linuxシステムの汚れたページflushメカニズムを見ました.http://blog.chinaunix.net/uid-17196076-id-2817733.htmlメモリflushとの設定が可能であることがわかりました(/proc/sys/vmの下)
dirty_background_bytes/dirty_background_ratio:
    -            (bytes    ) ,              ,          ( bytes     ,ratio      )

dirty_bytes/dirty_ratio:
    -            (bytes    ) ,            ,            ( bytes     ,ratio      )

dirty_expire_centisecs:
    -                    (        ),      dirty,      flush    。          inode     

dirty_writeback_centisecs:
    -         ,  dirty flush    (        )

現在のシステムのflush構成を確認します.問題はありません.dirty_background_ratioは10%、dirty_ratioは20%、dirty_writeback_centisecsは5 s、dirty_expire_centisecsは30 sですが、なぜredisの汚れたページがflushにディスクに入らなかったのでしょうか.
一般的に汚れたページはメモリのデータflushをディスクに入れるのですが、redisの持続化が汚れたページを招いたのではないでしょうか.これらの構成についてredisを表示します.
rdb        
# save 900 1
# save 300 10
# save 60 10000

# append       
appendonly no

#       、           
# maxmemory 
# maxmemory-policy volatile-lru

以上のように、redis自体は完全に閉じて永続化されており、cacheとしてのみ使用され、最大メモリ使用のデフォルト値(制限なし)については、メモリの淘汰メカニズムはvolatile-lruであることが分かった.redisのドキュメントを参照して、対応する淘汰メカニズムを表示します.
volatile-lru:                  (server.db[i].expires)              (   )
volatile-ttl:                  (server.db[i].expires)            
volatile-random:               (server.db[i].expires)         
allkeys-lru:           (server.db[i].dict)              
allkeys-random:        (server.db[i].dict)         
no-enviction:            

現在の使用環境では、プログラムはredisの使用をcacheとし、データにexpireタイムアウト時間を設定し、期限切れになったらredisの削除を待つ.では、汚れたページの原因は、期限切れのデータクリーンアップメカニズムの問題(例えば、クリーンアップがタイムリーではないなど)ではないでしょうか.そのため、Redisが期限切れデータを削除する際に取ったポリシーを表示する必要があります.参照情報は、Redis内のメモリ解放と期限切れキー削除redis期限切れキーのクリアです.
redis期限切れキー削除メカニズム:
    :
    -  expire     ,      ,              ,          ,    ,       。                           

    :
    -           cron    ,   db expire-keys          key(   20 ),  key    。      ,     
    -                 ,            CPU      。

  maxmemory     :
    -   client server  command   ,server    maxmemory     
    -             max-memory,       ,       maxmemory   
    -            (LRU,TTL,RANDOM )

redisは、期限切れキー削除に不活性削除+定期削除+maxmemoryより大きい自動クリアのポリシーを使用します.
ケース位置決め
以上の分析を通じて、問題はすでに明らかになった.原因は以下の通りである.
何らかの理由により、redisが使用するメモリはますます大きくなる(不活性な削除によるexpireのデータの蓄積が多くなるか、またはredis内部の実装に依存する他の理由である可能性がある).
redisはcacheとしてのみ使用され、実際にファイルを読み書きしていないため、オペレーティングシステムはflushをディスクに支援しません(flushができる場所がないため)redisはmaxmemoryを設定していないため、デフォルトはマシンのメモリサイズであり、redis自身が使用するメモリがマシンのメモリに達した場合にのみ、redis自身がクリーンアップ(volatile-lruメカニズム)を行う.
従って、現在のredisのメモリはますます大きくなり、汚れたページのデータはますます多くなり(ほとんどが期限切れのデータである可能性がある)ケース解決
この問題を解決するために、比較的便利で合理的な方法は:
不活性削除は頼りにならない場合がありますが、特にいくつかのlogタイプのデータについては、redisに書き込むと無視され、タイムアウト時間が設定されていますが、効果はありません.
定期的な削除はexpire-keysにもあまり頼りにならず、ランダム性があり、期限切れのデータが削除されていない可能性があります.
対照的に、比較的合理的な方法は、使用状況に基づいてredisのmaxmemoryサイズを設定、redisに自身のデータクリーンアップメカニズムを実現させるために、memをmaxmemory設定範囲内に制限ことを確保することである.