👶

Redisの基本: 一般的なデータ型とベストプラクティス

2025/03/13に公開

表紙

Redis の一般的なデータ型

文字列(Strings)

Redis の文字列は基本的なデータ型であり、文字列値を保存および取得するために使用されます。

  • ユースケース:テキストや数値の保存に適しており、例えばユーザーの名前、メールアドレス、ページカウンターなどに利用できます。また、バイナリデータの保存も可能なため、画像やシリアライズされたオブジェクトの格納にも使えます。
  • メリット:操作が簡単で、インクリメント(INCR)などの原子操作を実行できます。
// 文字列を保存
let _: () = conn.set("username", "alice").await.unwrap();

// 文字列を取得
let username: String = conn.get("username").await.unwrap();

リスト(Lists)

Redis のリストは、文字列の集合であり、挿入順に並べられます。

  • ユースケース:メッセージキュー、アクティビティログ、最近アクセスしたアイテムのリストなどの実装に適しています。リストは両端に要素を追加または削除できるため、スタックまたはキューとして使用できます。
  • メリット:高速な挿入・削除が可能で、FIFO(先入れ先出し)キューや LIFO(後入れ先出し)スタックとして利用できます。
// リストの先頭に要素を追加
let _: () = conn.lpush("events", "login").await.unwrap();
let _: () = conn.lpush("events", "logout").await.unwrap();

// リストの要素を取得
let events: Vec<String> = conn.lrange("events", 0, -1).await.unwrap();

セット(Sets)

セットは、重複のない文字列の無秩序な集合です。

  • ユースケース:タグ、アクセスした IP アドレス、ソーシャルネットワークの友達リストなど、順序を必要としない一意な要素の保存に使用されます。
  • メリット:要素の追加、削除、存在チェックを高速に行え、さらに集合演算(和集合、積集合、差集合)を実行できます。
// セットに要素を追加
let _: () = conn.sadd("tags", "redis").await.unwrap();
let _: () = conn.sadd("tags", "database").await.unwrap();

// セットの全メンバーを取得
let tags: Vec<String> = conn.smembers("tags").await.unwrap();

ソート済みセット(Sorted Sets)

ソート済みセットは、セットに似ていますが、各メンバーにスコア(数値)が関連付けられます。

  • ユースケース:ランキング、優先度キュー、スコア付きのデータの保存に適しています。
  • メリット:セットの基本操作に加え、スコアや辞書順による要素の取得や範囲検索が可能です。
// ソート済みセットに要素を追加
let _: () = conn.zadd("leaderboard", "alice", 100).await.unwrap();
let _: () = conn.zadd("leaderboard", "bob", 200).await.unwrap();

// ソート済みセットの要素を取得
let leaderboard: Vec<(String, f64)> = conn.zrange_withscores("leaderboard", 0, -1).await.unwrap();

ハッシュ(Hashes)

ハッシュはキーと値のペアの集合であり、プログラミング言語の辞書やオブジェクトに似ています。

  • ユースケース:ユーザー情報(名前、年齢、メールアドレスなど)の保存など、複数の関連データをまとめて管理するのに適しています。
  • メリット:複数のフィールドを一度に読み書きでき、オブジェクトの表現やデータの集約に便利です。
// ハッシュにキーと値を追加
let _: () = conn.hset("user:100", "email", "alice@example.com").await.unwrap();

// ハッシュのすべてのキーと値を取得
let user_info: HashMap<String, String> = conn.hgetall("user:100").await.unwrap();

ビットマップ(Bitmaps)

ビットマップは、ビット単位で構成された配列で、各ビットは独立して設定または取得が可能です。

  • ユースケース:ユーザーの出席状況、特定機能のオン/オフ状態など、存在の有無をマークする場面に適しています。
  • メリット:非常に高い空間効率を持ち、大量のブール値データを扱うのに適しています。
// ビットマップでビットを設定
let _: () = conn.setbit("features", 0, true).await.unwrap();  // 機能0を有効にする

// ビットマップからビット値を取得
let feature_enabled: bool = conn.getbit("features", 0).await.unwrap();

ハイパーログログ(HyperLogLogs)

HyperLogLog は、集合の基数(ユニークな要素の数)を効率的に推定する確率的データ構造です。

  • ユースケース:ウェブサイトのユニークビジター数など、大規模データのユニーク要素数の推定に適しています。
  • メリット:伝統的なカウント方法と比較してメモリ使用量が少なく、大規模データ処理に適しています。
// HyperLogLog に要素を追加
let _: () = conn.pfadd("pageviews", "user1").await.unwrap();
let _: () = conn.pfadd("pageviews", "user2").await.unwrap();

// 推定基数を取得
let unique_pageviews: i64 = conn.pfcount("pageviews").await.unwrap();

データ型の選択

バックエンド業務で最適な Redis データ型を選択するためには、自身のデータ構造とユースケースを理解することが重要です。以下は、一般的なバックエンドシナリオと推奨される Redis データ型の例です。

ユーザーセッション(User Sessions)

  • 推奨データ型:ハッシュ(Hash)
  • 理由:ハッシュは、ユーザー ID、トークン、最終アクセス日時など、セッションオブジェクトの複数の属性を格納でき、特定のフィールドを個別に更新または取得できます。
let _: () = conn.hset("session:userid", "token", "abc123").await.unwrap();
let _: () = conn.hset("session:userid", "last_access", "2023-01-01").await.unwrap();

リアルタイムメッセージングまたはイベントキューイング(Real-time Messaging or Event Queuing)

  • 推奨データ型:リスト(List)
  • 理由:リストは FIFO キューとして動作し、リアルタイムのメッセージ処理やタスクキューに適しています。
let _: () = conn.rpush("events_queue", "event1").await.unwrap();
let event: String = conn.lpop("events_queue").await.unwrap();

アクセスカウンターまたはレート制限(Access Counters or Rate Limiting)

  • 推奨データ型:文字列(String)
  • 理由:文字列型は原子操作によるインクリメントをサポートし、カウンターとしての使用に適しています。
let _: () = conn.incr("page_view_count", 1).await.unwrap();
let count: i64 = conn.get("page_view_count").await.unwrap();

ランキングまたはスコアソーティング(Leaderboards or Score Sorting)

  • 推奨データ型:ソート済みセット(Sorted Set)
  • 理由:スコアによる自動ソートが可能で、ランキングなどスコア順のデータに最適です。
let _: () = conn.zadd("leaderboard", "user123", 2500).await.unwrap();
let leaderboard: Vec<(String, f64)> = conn.zrange_withscores("leaderboard", 0, -1).await.unwrap();

ユニーク値のコレクション(タグやカテゴリなど)(Unique Value Collections like Tags or Categories)

  • 推奨データ型:セット(Set)
  • 理由:重複のないデータの保存に適しており、タグの管理などに便利です。
let _: () = conn.sadd("tags", "redis").await.unwrap();
let tags: Vec<String> = conn.smembers("tags").await.unwrap();

複数属性のオブジェクト保存(Multi-attribute Object Storage)

  • 推奨データ型:ハッシュ(Hash)
  • 理由:複数の属性を個別に管理でき、オブジェクトの保存に便利です。
let _: () = conn.hset("user:100", "name", "Alice").await.unwrap();
let user: HashMap<String, String> = conn.hgetall("user:100").await.unwrap();

機能フラグまたはトグル(Feature Flags or Toggles)

  • 推奨データ型:ビットマップ(Bitmap)
  • 理由:機能のオン/オフなど、ブール値の保存に適しています。
let _: () = conn.setbit("features", 1, true).await.unwrap();
let feature_on: bool = conn.getbit("features", 1).await.unwrap();

最適なデータ型の選択は、具体的なニーズに依存します。単純なキーと値のペアであれば文字列型が適していますが、ユーザープロファイルやセッション情報のように複数のフィールドを持つ場合はハッシュ型が便利です。ランキングやスコア順のデータ管理が必要であれば、ソート済みセットが最適です。

それぞれのユースケースに応じた最適なデータ型を選択し、効率的なデータ管理を行いましょう。


私たちはLeapcell、バックエンド・プロジェクトのホスティングの最適解です、組み込みのサーバーレスRedisを搭載しています。

Leapcell

Leapcellは、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです:

複数言語サポート

  • Node.js、Python、Go、Rustで開発できます。

無制限のプロジェクトデプロイ

  • 使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。

比類のないコスト効率

  • 使用量に応じた支払い、アイドル時間は課金されません。
  • 例: $25で6.94Mリクエスト、平均応答時間60ms。

洗練された開発者体験

  • 直感的なUIで簡単に設定できます。
  • 完全自動化されたCI/CDパイプラインとGitOps統合。
  • 実行可能なインサイトのためのリアルタイムのメトリクスとログ。

簡単なスケーラビリティと高パフォーマンス

  • 高い同時実行性を容易に処理するためのオートスケーリング。
  • ゼロ運用オーバーヘッド — 構築に集中できます。

ドキュメントで詳細を確認!

Try Leapcell

Xでフォローする:@LeapcellHQ


ブログでこの記事を読む

Discussion