Redisクリーンアップ

6543 ワード

Redisはいいものだが、むやみに使ってはいけない.節制もなく、規範的に使っていない.その結果、後期の掃除は異常に難しい.
最近整理する需要があって、収集して整理して、ノートの予備とします.
RDB
オンラインRedisインスタンスは一般的に大きく、通常、サーバホスト環境のメモリに余裕がありません.サーバのダウンタイムやサービスのブロックを避けるために、サービスカートンはmasterサーバやオンラインサーバで操作しないでください.
https://jmaitrehenry.ca/2017/11/22/found-keys-without-expiration-in-redis/
この文章はとても良い探査方法を紹介して、中で大体2つの次元を話しました:
  • 期限切れKEY:長い間積み上げて、サーバーのメモリがきつくなる
  • 大値KEY:蓄積が多く、サービス遅延、カートン
  • 期限切れKEY
    大まかな意味は、keysを取得し、各keyに対してttlを行い、対応する期限切れ時間を算出することである.にある
    http://doc.redisfans.com/key/ttl.html
    コマンドリファレンスにはTTLコマンドについての詳細な説明があります.
    Redis 2.8以降、TTLはkeyに対して3つの戻り結果を示す:X(>=0がゼロより大きい整数)は、X秒後expire-1は、そのkeyが期限切れでないことを示す-2は、このkeyが期限切れであることを示し、Redisによって削除される
    2つのファイルを統合することで、keysの有効期限が-1のkeyをフィルタリングし、ビジネスコードにexpire時間を忘れたエラーがあるかどうかを発見します.核心的な考え方は以下の通りです.
  • 入手keysリンクではdockerが使用されており、Redisの例としてvolumeをマウントし、コマンドで入手できます.このようなメリットは、タイムリーにRedisを掛けても上品ではありません.どうせdockerなので、もう一つ起きないわけにはいきません.しかし、これは唯一の方法ではありません.パソコンのメモリが十分であれば、dumpを手に入れました.rdbの後は好きなように使えますが、最後にkeysを手に入れればいいです.特に正確にする必要はないので、scan cursor count方式を使用しています.
  • keys対応のttl
  • を入手
    #!/usr/bin/bash
    cat keys | xargs -n 1 -L 1 redis-cli ttl > ttl
    

    上の方法は、簡単で乱暴ですが、効率が低く、あまりよくありません.理想的な状態ではPIPELINEを使いますが、一度にPIPELINEが多すぎず、処理上限を超えてもよくないので、できるだけバランスのとれた量を探して処理します.
  • 期限切れのないkey集合をフィルタリング
  • #!/usr/bin/bash
    paste -d " " keys ttl | grep .*-1$ | cut -d " " -f 1 > without_ttl
    

    これでRedisに期限切れのないkeyを見つけることができ、テキストを分析したり、接頭辞文字列をパターンマッチングしたりすることで、すぐに問題点を見つけることができると信じています.
    大きい値KEY
    一般的に、KEYの分布と大きさは業務と密接に関係しており、通常、このタイプのKEYは多くないが、極端な場合、現れるとサービスに不安定な要素をもたらす.これらのキーに対してHGETALL,LRANGE,SMEMBERS,ZRANGEを行うたびに,サーバがブロックされ,カートン感が顕著になる.
    Redisは大きなKEYを表示するコマンドを持っています.
    redis-cli -h host -p port --bigkeys 
    

    それは自動的に私達に現在の各種類の下で大きいKEYの具体的な情報を分析することを助けます.
  • https://gist.github.com/iBaozi/460fa9c5d0fd90a0bfc7luaスクリプトによる検索
  • redis-cli -h host -p port DEBUG OBJECT keyname
  • https://gist.github.com/epicserve/5699837下地はやはりdebug object xxx包装しただけです.

  • 非RDB
    メモリが十分なローカルサーバがないので、最初の方法で好きなようにすることはできません.
    scan cursor count
    

    いい方法で、scanはkeys集合を手に入れて、ゆっくりとkeysに対してTTLを手に入れて、効率は高くありませんが、少しずつ着実に分析して、効果は悪くありません.
    製造データソース
    #coding: utf8
    __author__ = "   "
    __email__ = "[email protected]"
    # padding rand keys to redis
    import redis
    import random
    client = redis.Redis("localhost", 6379)
    
    #    ,    True, KEY ,       EXPIRE,        
    WITHOUT_TTL = False
    
    
    # padding strings
    print("padding string keys")
    for i in range(1, 1000000):
        if WITHOUT_TTL == True:
            client.set("string:{}".format(i), "value: {}".format(i))
        else:
            if i % 2 == 0:
                client.expire("string:{}".format(i), random.randint(0, i))
    
    # padding list
    print("padding list keys")
    for i in range(1, 1000000):
        ls = random.choices([item for item in range(1, 1000)], k=5)
        if WITHOUT_TTL == True:
            client.lpush("list:{}".format(i), ls)
        else:
            if i % 2 == 0:
                client.expire("list:{}".format(i), random.randint(0, i))
    
    # padding set
    print("padding set keys")
    for i in range(1, 1000000):
        ls = random.choices([item for item in range(1, 1000)], k=5)
        if WITHOUT_TTL == True:
            client.sadd("set:{}".format(i), ls)
        else:
            if i % 2 == 0:
                client.expire("set:{}".format(i), random.randint(0, i))
    
    # padding hash
    print("padding hash keys")
    for i in range(1, 1000000):
        members = {key: key**2 for key in random.choices([item for item in range(1, 1000)], k=5)}
        if WITHOUT_TTL == True:
            client.hmset("hash:{}".format(i), members)
        else:
            if i % 2 == 0:
                client.expire("hash:{}".format(i), random.randint(0, i))
    
    # padding sorted_set
    print("padding zset keys")
    for i in range(1, 1000000):
        if WITHOUT_TTL == True:
            for j in range(i):
                client.zadd("zset:{}".format(i), i*2, i)
        else:
            if i % 2 == 0:
                client.expire("zset:{}".format(i), random.randint(0, i))
    

    午前中に食事の前に500万個のKEYを置いて、午後帰ってきてみるともうずいぶん期限切れになった.
    ➜  rediscleaner redis-cli info keyspace
    # Keyspace
    db0:keys=3873122,expires=1870761,avg_ttl=261110455
    ➜  rediscleaner redis-cli info memory
    # Memory
    used_memory:760203104
    used_memory_human:724.99M
    used_memory_rss:326615040
    used_memory_rss_human:311.48M
    used_memory_peak:847701600
    used_memory_peak_human:808.43M
    used_memory_peak_perc:89.68%
    used_memory_overhead:251183030
    used_memory_startup:980528
    used_memory_dataset:509020074
    used_memory_dataset_perc:67.04%
    total_system_memory:8589934592
    total_system_memory_human:8.00G
    used_memory_lua:37888
    used_memory_lua_human:37.00K
    maxmemory:0
    maxmemory_human:0B
    maxmemory_policy:noeviction
    mem_fragmentation_ratio:0.43
    mem_allocator:libc
    active_defrag_running:0
    lazyfree_pending_objects:0
    

    SCAN
    #coding: utf8
    __author__ = "   "
    __email__ = "[email protected]"
    # cleaner for rubbish keys without ttl in redis.
    
    import redis
    
    client = redis.Redis("localhost", 6379)
    offset, sequence = client.scan(0, count=100)
    print("handling offset: {}".format(0))
    with open("./keys", "a") as file:
        while offset !=0:
            print("handling offset: {}".format(offset))
            file.writelines([item.decode("utf8") + str("
    ") for item in sequence]) offset, sequence = client.scan(offset, count=100) print("done.")

    フィルタ検索
    ttl.sh
    #!/usr/bin/bash
    cat keys | xargs -n 1 -L 1 redis-cli ttl > ttl
    

    filter_keys.sh
    #!/usr/bin/bash
    paste -d " " keys ttl | grep .*-1$ | cut -d " " -f 1 > without_ttl
    

    最後に400万個以上のkeyが6時間も走ってやっと走った(PIPELINEを使わなかった結果)効果:
    ➜  rediscleaner wc keys && wc ttl && wc without_ttl
     4004138 4004138 48594962 keys
     4004138 4004138 18833511 ttl
     2002317 2002317 24300318 without_ttl
    ➜  rediscleaner
    
    keys,ttl,without_ttlを取得することで,期限切れのないkey集合を取得できる.次に、具体的なビジネス問題を分析するために使用できます.プロジェクトコードと照らし合わせると、より良い効果が得られます.
    分析ツール
    TODOは現在、完全な分析ツールを作る考えがあります.
  • Redis全体のkey現状を探る
  • monitorしばらくの間のkeyリクエスト現状