クライアントのキャッシュ機能をRedisで実現する

Posted on 2017/07/09

ToC

一定期間(10分程度)だけクライアント上でデータを保持する仕組みが必要になり、簡単なキャッシュの仕組みをRedisを使って実現しました。 検証の中で気づいたこととハマりどころをまとめておきます。

実現したかったこと

  • 通知されるメッセージをキャッシュする(メッセージの受信から10分間)
  • キャッシュが存在する間は、データを参照して別の処理ができる
  • 一定期間が経過した後(10分後)にキャッシュを削除する
  • クライアント側の再起動時には、全てのキャッシュが削除されている(リセット可能)

なぜ Redis?

実現したいことはあまりに一般的によくある内容なので、実装方式は色々あると思います。 そんなわけで、下記のような言い訳も含めてRedisを選択しました。

  • 実行クライアントがRaspberry Piを想定しているので、比較的何でもできそうだった
  • Pythonプログラムで制御したかった(他の機器の制御の都合もあり…)
  • 通知されるメッセージ(Json形式)をHash形式で呼び出して簡単に利用したかった
  • クライアントがブチ切りされたときにもトラブルが少なそうな方式がいい

Redisのインストール

びっくりするぐらい簡単でした。 はい。これだけ。

sudo apt-get install redis-server

ちなみに開発環境として利用したMacではbrewでインストールできました。

Redisの設定

細かいところはあまり理解していないので今後の課題としますが、今回実現したかったメモリー上でのキャッシュのみとする部分を変更します。 ちなみに、Redisデータ永続化の種類とサービス稼動時の切り替え注意点を読んでRedisには3種類の方法があることがわかりました。

今回は、その中の「揮発性」を採用します。 設定は、全てのsaveの設定をコメントアウトすれば良いようなのでコメントアウトして保存します。

# Note: you can disable saving at all commenting all the "save" lines.

#save 900 1
#save 300 10
#save 60 10000

あとは、サービスを再起動すれば完了です。簡単。

PythonからRedisを操作する

あれこれ書くより、まずはソースコード。 (実際のコードから抜き出したので、実際に動かしているものとは少し違いますが、だいたいこんな感じ)

# -*- coding: utf-8 -*-

from __future__ import print_function
from __future__ import unicode_literals
import redis

class RedisEvent(object):
    def __init__(self, **kwargs):
        self.redis_connection_args = kwargs.get('redis', None)
        if self.redis_connection_args is None:
            self.redis_connection_args = {'decode_responses': True}
        self.ttl = kwargs.get('ttl', 600)

    def register(self, **kwargs):
        payload = kwargs.get('payload')
        message_id = payload.MessageId

        connection = redis.Redis(**self.redis_connection_args)
        connection.hmset(name = message_id, mapping=payload)
        connection.expire(name = message_id, time=self.ttl)
        connection.connection_pool.disconnect()
        return

ポイントとなる部分は、このようなところかと思います。

  • pipでredisというパッケージを利用
  • データ取得の時にResponseの「encode & decode問題」にハマるので、Redis接続時にはdecode_responses=Trueに設定したほうが良い
  • Pythonのdict形式でデータを取得するためにデータ型はHashを採用
  • データ登録時にTTL設定を忘れず(key単位でのTTL設定)
  • コネクションが残りっぱなしにならないようにdisconnect()しよう

感想

諸々、ちゃちゃっとできてしまいます。想像を絶する簡単さ。 それでは、Enjoy Redis!!

参照