Djangoのcacheフレームワークで複数の値をまとめて取得、更新する

試したバージョンはPython3.10, Django 4.2.4, pymemcache 4.0.0

Djangoのキャッシュフレームワークを使うと、memcachedやRedisなどをキャッシュサーバーとして利用できる。 複数の値をキャッシュサーバーから読み書きする際、 cache.get() cache.set() を何度も呼ぶと、キャッシュサーバーとの通信のレイテンシーの影響を受けて遅くなりやすい。

同一ホスト内にキャッシュサーバーがいる場合はさほど問題にならず、クラウド上にデプロイしてサーバーを分けたときに問題に気づきやすい。

キャッシュ読み書きを複数回行う例

まず、 cache.set() cache.get() をキャッシュの読み書きする都度呼び出すコードを示す。

>>> from django.core.cache import cache
>>> cache.set("k1", "spam")
>>> cache.set("k2", "egg")
>>> cache.set("k3", "ham")
>>> cache.get("k1")
'spam'
>>> cache.get("k2")
'egg'
>>> cache.get("k3")
'ham'

このコードだと cache.set() を3回、 cache.get() を3回呼び出していて、たとえばキャッシュバックエンドがmemcachedの場合、サーバーとの通信が6回発生する。

仮に1回の通信に50ミリ秒かかるとすると、50ms * 6回=300ms程度かかってしまう。回数が増えると線形にパフォーマンスが劣化していく。

複数の値をまとめて読み書きする例

複数の値をまとめて読み書きする場合は、 cache.set_many()cache.get_many() を使う。

>>> from django.core.cache import cache
>>> cache.set_many({"k1": "spam", "k2": "egg", "k3": "ham"})
[]
>>> cache.get_many(["k1", "k2", "k3"])
{'k1': 'spam', 'k2': 'egg', 'k3': 'ham'}

このコードだと、memcachedの場合はサーバーとの通信は2回で済む。読み書きする値の数が増えても、レイテンシの影響は大きくならない。

複数の値の読み書きは、バックエンドクラスの実装にも依存するので、どの場合でもこのAPIを使うと速くなるとは言い切れないことに注意する。

キャッシュサーバーを使うときは、実装によっては「ローカルの開発時は速いのに本番環境ではレイテンシの影響で遅くなる」という可能性があることを考慮しておくとよい。

参考