TairHash は Tair 独自の拡張データ構造であり、各フィールドに生存時間 (TTL) とバージョン番号を指定できます。単一のユーザーが複数のデバイスからログインする場合、各セッションを Redis 文字列として保存すると、ユーザー ID とデバイスタイプを 1 つのキーに連結する必要があります (例: User_1_phone)。TairHash は、セッション構造をそのデータモデルに直接マッピングすることで、この回避策を不要にします。key をユーザー ID に、field をデバイスタイプに、value をセッショントークンに設定します。TairHash はキーとフィールドの両方で TTL 設定をサポートしているため、追加のアプリケーションロジックなしで、トークンはデバイスごとに独立して期限切れになります。
標準の Redis 文字列が不十分な理由
単一デバイスセッションの場合、Redis 文字列はうまく機能します。複数デバイスセッションでは、次の 3 つの問題が発生します。
| 問題 | 影響 |
|---|---|
| 文字列の連結 | アプリケーションは、読み取りと書き込みのたびに user_1_phone のような複合キーを構築および解析する必要があります。 |
| エンコーディングのオーバーヘッド | キーの解析を繰り返すと、CPU とコードの複雑さが増加します。 |
| ストレージの重複 | ユーザー ID プレフィックスが、デバイス固有のすべてのキーで繰り返されます。 |
TairHash はこれら 3 つすべてを解決します。ユーザーごとに 1 つのキー、デバイスごとに 1 つのフィールド、フィールドごとに 1 つの TTL です。

ユースケース
TairHash のフィールドレベル TTL は、いくつかのセッション管理パターンに適しています。
複数デバイストークン管理:単一のユーザーキーの下に、デバイスごとに 1 つのトークンを保存します。各トークンは、そのデバイスのセッションアクティビティに基づいて独立して期限切れになります。
アクティブセッションの追跡:
EXHGETALLを使用して、ユーザーのすべてのアクティブなセッションを一覧表示します。期限切れのフィールドは自動的に除外されるため、結果は常に現在のアクティブな状態を反映します。セッションの自動クリーンアップ:ログイン時にトークンに短い TTL を設定します。ユーザーがデバイスで TTL より長く非アクティブである場合、そのセッションはスケジュールされたクリーンアップジョブなしで削除されます。
主要なコマンド
| 目的 | コマンド | 説明 |
|---|---|---|
| TTL 付きでトークンを書き込む | EXHSET key field value EX seconds | フィールドレベルの TTL を秒単位で設定します。 |
| すべてのアクティブなトークンを読み取る | EXHGETALL key | 期限切れになっていないフィールドのみを返します。 |
前提条件
開始する前に、次のものがあることを確認してください。
Tair インスタンス (Tair 拡張が有効になっている Alibaba Cloud Redis)
Python 3.8 以降
tair-py がインストールされていること (
pip3 install tair) — ソースは github.com/alibaba/tair-py で入手できます。
セッショントークンの保存と取得
次の例では、複数のデバイスにまたがる 2 人のユーザーのトークンを保存し、6 秒間待機してから、残りのアクティブなトークンを取得します。6 秒後、user1 の phone トークン (TTL = 5 秒) は期限切れになり、結果から除外されます。
# -*- coding: utf-8 -*-
#!/usr/bin/env python
import os
import time
from tair import Tair
from tair import ResponseError
def get_tair() -> Tair:
# Tair インスタンスに接続します。
# host: ご利用の Tair インスタンスのエンドポイント
# port: デフォルトは 6379 です
# username: デフォルトアカウントを使用する場合は空白のままにします
# password: 環境変数 TAIR_PASSWORD から読み取ります
return Tair(
host="r-bp************.redis.rds.aliyuncs.com",
port=6379,
db=0,
username="",
password=os.environ.get("TAIR_PASSWORD"),
)
def add_user_token(tair: Tair, user_id: str, device: str, token: str, ttl_seconds: int) -> bool:
# フィールドごとの TTL を持つ EXHSET を使用してセッショントークンを保存します。
# key = user_id (1 人のユーザーのすべてのデバイスをグループ化します)
# field = device (デバイスタイプを識別します)
# value = token (セッショントークン)
# ex = TTL (秒単位)
try:
result = tair.exhset(user_id, device, token, ex=ttl_seconds)
return result == 1
except ResponseError as e:
print(e)
return False
def print_active_tokens(tair: Tair, user_id: str):
# EXHGETALL は、まだ期限切れになっていないフィールドのみを返します。
for entry in tair.exhgetall(user_id):
print("{}:{}".format(user_id, entry))
if __name__ == "__main__":
tair = get_tair()
user_1 = "user1"
user_2 = "user2"
# 異なる TTL を持つ 4 つのトークンを書き込みます。
add_user_token(tair, user_1, "phone", "token_123", 5) # 5 秒で期限切れ
add_user_token(tair, user_1, "pad", "token_124", 10) # 10 秒で期限切れ
add_user_token(tair, user_2, "pad", "token_456", 10) # 10 秒で期限切れ
add_user_token(tair, user_2, "pc", "token_457", 10) # 10 秒で期限切れ
# 6 秒間待機します。user1 の phone トークン (TTL = 5 秒) は期限切れになります。
print("Waiting 6 seconds...")
time.sleep(6)
# 4 つのトークンのうち 3 つだけが返されます。user1/phone は期限切れになっています。
print_active_tokens(tair, user_1) # user1/pad のみを出力
print_active_tokens(tair, user_2) # user2/pad と user2/pc を出力期待される出力:
Waiting 6 seconds...
user1:{field: pad, value: token_124}
user2:{field: pad, value: token_456}
user2:{field: pc, value: token_457}user1/phone は、クエリの前に 5 秒の TTL が経過したため、存在しません。それぞれ 10 秒の TTL が設定された残りの 3 つのトークンは、まだアクティブです。