hoge-hogeoのひきこもごも

インフラエンジニアだけど形を持ったインフラを触ったことがない人の徒然

pythonでRedisの大量データからttl一覧を取得したい(2)

Redisのキーってttl切れしても実はメモリ上には残ってて、volatile-lruとかが発生するまで残ってるんじゃね? getかttlとかで引けば消えるんじゃね?

っていう話が上がって、とりあえずscanしてttl引いてみよう、getしてみようという話。

スクリプト1

collect_key_by_pattern.py

概要

パターンマッチを指定してn件ずつscan

scan_result_${pattern}.txtにkeyを出力

INPUT/OUTPUT
IN/OUT 備考
INPUT なし
OUTPUT scan_result_${pattern}.txt
引数
$n 説明 備考
1 対象のRedis endpoint 127.0.0.1
2 scanに渡すmatchパターン refresh_token 成果物のファイル名に使われるので、「:」を渡すとファイル名にそのまま渡されて少しださい
3 scanに渡すrange 1000
ソース
#!/usr/bin/env
 
import sys
import redis
import logging
 
 
INITIAL_CUR = 0
REDIS_HOST = len(sys.argv) > 1 and sys.argv[1] or '127.0.0.1'
MATCH_PATTERN = len(sys.argv) > 2 and sys.argv[2] or ''
COUNT = len(sys.argv) > 3 and sys.argv[3] or '100'
OUTPUT = 'scan_result_' + MATCH_PATTERN + '.txt'
 
logger = logging.getLogger()
logger.setLevel(10)
# for file
fh = logging.FileHandler(OUTPUT)
logger.addHandler(fh)
 
def utf8(byte):
    if byte:
        return str(byte, 'utf-8')
 
if __name__ == '__main__':
    if len(sys.argv[1:]) < 3:
        sys.exit("Usage: %s <redis-endpoint> <match-pattern>" % sys.argv[0])
    r = redis.StrictRedis(host=REDIS_HOST, port=ほげ)
    next_cur = INITIAL_CUR
    while True:
        res_scan = r.scan(cursor=next_cur, match=MATCH_PATTERN + '*', count=COUNT)             # SCAN
        print(len(res_scan[1]))
        next_cur = res_scan[0]
        if res_scan[1]:
            for key in res_scan[1]:
                logger.info(utf8(key))
        if next_cur == INITIAL_CUR:
            break
実行
$ python36 collect_key_by_pattern.py 127.0.0.1 refresh_token 1000
$ 

とくに出力はしない

成果物
$ head scan_result_refresh_token.txt
refresh_token:76c1b0bca4097cb1d42d2aa9c694d1bdbce5cc94
refresh_token:299251bad808a5b71ef8b806c689182e328701d3
refresh_token:02be609d8f80183f22edca17217d06d43717d64f

スクリプト2

get_ttl.py

概要

key, ttlのフォーマットでファイル出力

ttl切れを判定し、あったらファイル出力

INPUT/OUTPUT
IN/OUT 備考
INPUT scan_result_${pattern}.txt
OUTPUT key_ttl.log, expired_keys.txt
引数
$n 説明 備考
1 対象のRedis endpoint 127.0.0.1
2 検索するキーを記載したファイル scan_result_laravel.txt
ソース
#!/usr/bin/env
#coding:utf-8
import sys
import redis
import pdb
import logging
 
REDIS_HOST = len(sys.argv) > 1 and sys.argv[1]
INPUT_FILE = len(sys.argv) > 2 and sys.argv[2]
KEY_TTL = 'key_ttl.log'
 
#logger1==========================================
logger = logging.getLogger('LoggingTest')
logger.setLevel(10)
fh = logging.FileHandler(KEY_TTL)
logger.addHandler(fh)
#logger1==========================================
 
#logger2==========================================
logger_for_output = logging.getLogger('logger_for_output')
logger_for_output.setLevel(10)
# for file
fh = logging.FileHandler('expired_keys.txt')
logger_for_output.addHandler(fh)
#logger2==========================================
 
def utf8(byte):
    if byte:
        return str(byte, 'utf-8')
 
if __name__ == '__main__':
    if len(sys.argv[1:]) < 2:
        sys.exit("Usage: %s <redis-endpoint> <input file>" % sys.argv[0])
    r = redis.StrictRedis(host=REDIS_HOST, port=ほげ)
    # keyを元にttlを抽出、"key ttl"のフォーマットで中間ファイルを出力
    with open(INPUT_FILE) as f:
        for key in f:
            key_ = key.rstrip('\n')
            res_ttl = r.ttl(key_)      # TTL
            logger.info('%s  %s', key_, res_ttl)
    # 中間ファイルからkey, ttlを抽出して、ttl切れがないか確認
    with open(KEY_TTL) as f:
        for key in f:
            if key.split()[1] <= '0':
                logger_for_output.info(key.rstrip('\n'))
実行
$ python36 get_ttl.py 127.0.0.1 scan_result_refresh_token.txt
$

特に何も出ない

成果物

ttlが設定されていないキーが出力された。(テストデータ)

$ head expired_keys.txt 
refresh_token:cfa85abcc28d616f46c78f3c289609db0a1b1526  -1
refresh_token:182433e52a42776f95ff871a79f21e2a3c4ee9c17  -1
refresh_token:182433e52a42776f95ff871a79f21e2a3c4ee9c11  -1

あとで、実際にRedisにデータを突っ込んで試してみよう。

ダメでも、scanしてRedis内のキーの割合を算出する程度の役には立つだろう。。。