コンテンツにスキップ

Redis@NoSQL

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. DBエンジンの種類

インメモリ方式

メモリ上にデータを保管する。

揮発的なため、Redisを再起動するとデータが削除されてしまう。


オンディスク方式

ディスク上にデータを永続化する。


02. ユースケース

セッション

記入中...


クエリキャッシュ

記入中...


DB排他制御 (分散ロック)

▼ Python

*実装例*

import redis

client = redis.Redis()

# ロックを定義する
client.setnx('LOCK_NAME', 'foo_lock')  # True

# 確認する
client.get('LOCK_NAME')  # 'foo_lock'

# 同じキーで登録を試みると失敗する。この判定を排他制御のために使用する。
client.setnx('LOCK_NAME', 'foo_lock')  # False

# アンロックする
client.delete('LOCK_NAME')

▼ TypeScript

import redisClient from "redis";

const newLock = (client: ReturnType<typeof redisClient>, timeout = 50000) => {
  return async (
    lockName: string,
    onLockSuccess: () => Promise<void>,
    onLockFailed: () => Promise<void>,
  ) => {
    const keyName = `lock:${lockName}`;
    try {
      // キー名を指定し、Redisにキャッシュを保存する
      const result = await client.set(keyName, "{}", {
        // PXオプションで、ロックの有効期限を設定する
        PX: timeout,
        // NX(Redisのキーが存在しない場合のみ設定)オプションで、キーによる排他制御を実現する
        NX: true,
      });
      // resultがnullでない場合、ロックを開始したことを意味する
      if (result !== null) {
        // ロックが成功した場合、onLockSuccessコールバックを実行する
        await onLockSuccess();
        // resultがnullの場合、ロックに失敗したことを意味する
      } else {
        await onLockFailed();
      }
    } catch (e) {
      logger.error(`failed to connect redis ${e}`);
      await onLockSuccess();
    }
  };
};

await redisClient.connect();
newLock(redisClient, 10000);

▼ Go

*実装例*

func (c *Client) updateCache(ctx context.Context, contentID string) error {

        // ロックする
        // ロックのクライアントで障害が起こってアンロックできなくなることを防ぐために、ロックの失効時間を設定しておく
        nx, err := c.cli.SetNX(ctx, "lock:"+contentID, true, lockTTL).Result()

        if err != nil {
                return err
        }

        if !nx {
                return errors.New("failed to lock")
        }

        // 処理の最後にアンロックする
        defer func() {
                c.cli.Del(ctx, "lock:"+contentID)
        }()

        // なんらかの永続処理
        // ...

        // 処理結果のキャッシュを作成する
        _, err = c.cli.Set(ctx, contentID, content, cacheTTL).Result()

        if err != nil {
                return err
        }

        return nil
}