Redis
 Computer >> コンピューター >  >> プログラミング >> Redis

Redis入門ガイド:CLIの基本操作から主要コマンド、実践プロジェクトまで徹底解説

Redisは、キャッシュやレート制限など、さまざまなプロジェクトで活用されている人気のインメモリデータベースです。

この記事では、Redisをインメモリデータベースとして活用する方法、なぜRedisを使うべきなのか、さらに知っておくべき重要な機能まで、順を追ってわかりやすく解説します。それでは始めましょう。

インメモリデータベースとは?

従来のデータベースは、アクセス頻度の高い「ホット」なインデックスなどをメモリ上に保持して高速化を図り、残りのデータはディスクに保存するという構成が一般的です。

一方、Redisはレイテンシ(遅延)の最小化とデータの高速な読み書きに重点を置いています。そのため、ストレージデバイス(SSD/HDD)ではなく、完全にメモリ(RAM)上で動作します。速度こそが命なのです。

Redisはキーバリュー型のデータベースですが、単純なデータベースだと侮ってはいけません。キーとバリューの保存・取得には実に多彩な方法が用意されています。

なぜRedisが必要なのか?

Redisの使い道は多岐にわたりますが、代表的なユースケースとして次の2つが挙げられます。

  1. アプリケーションのステートレス化:コード層をステートレス(状態を持たない)にすると、水平スケーリングが可能になります。Redisを中央のストレージシステムとして使い、アプリケーション側はロジックの処理だけに集中できるのです。
  2. 複数アプリ間でのデータ共有:例えば、payments.example.comへのブルートフォース攻撃を検知した際に、login.example.comでも同じ攻撃者をブロックしたいケースを考えてみましょう。Redisを使えば、互いに独立した複数のサービスが共通のメモリ空間を共有できます。

Redisは覚えるべきコマンドが少なく、比較的簡単に学べるのが魅力です。続いて、Redisの主要な概念とよく使われるコマンドを見ていきましょう。

Redis CLI(REPL)

RedisにはCLIが付属しており、これはコマンドラインのREPL(Read-Eval-Print Loop)版です。入力した内容がその場で評価され、結果が即座に返されます。

このREPLは、アプリケーション開発中に特定のキーの値やRedisの状態を手軽に確認したいときに非常に便利です。Redisにおける「Hello World」とも言えるPINGコマンドも、このCLIからすぐに試せます。

よく使われるRedisコマンド

ここからは、Redisの動作を理解するうえで欠かせない頻出コマンドを紹介します。

SET

SETは、キーに値を設定するためのコマンドです。

SET mehul "developer from india"

この例では、キーmehulに値developer from indiaが設定されます。

GET

GETは、設定済みのキーから値を取得するコマンドです。

GET mehul

先ほど設定した文字列「developer from india」が返されます。

SETNX

SETNXは、キーが存在しない場合にのみ値を設定するコマンドです。既存のキーの値を誤って上書きしてしまうのを防ぎたいときなど、さまざまな場面で役立ちます。

SET key1 value1
SETNX key1 value2
SETNX key2 value2

この例を実行すると、key1value1のまま、key2にはvalue2が設定されます。2番目のコマンドはkey1がすでに存在するため無視されるからです。

MSET

MSETはSETと似ていますが、1つのコマンドで複数のキーをまとめて設定できます。

MSET key1 "value1" key2 "value2" key3 "value3"

長いコマンドでは、どれがキーでどれが値なのか見分けにくくなりがちです。そこでおすすめなのが、値は必ずダブルクォートで囲み、キーはクォートなしで記述する(有効なキー名であれば)というルールです。可読性が大きく向上します。

MGET

MGETはGETと似ていますが、複数の値を一度に取得できます。

MGET key1 key2 key3 key4

この例では、value1value2value3nullの4つの値が配列として返されます。key4は設定していないためnullになるのです。

DEL

DELは、キーを削除するシンプルなコマンドです。

SET key value
GET key # "value" が返る
DEL key
GET key # null が返る

INCR と DECR

この2つのコマンドは、数値型のキーをインクリメント(増加)・デクリメント(減少)させるために使います。「GETして+1してSETする」という2段階の操作を1回で実行できるため非常に便利で、実際によく使われます。

親アプリケーションとの往復通信を避けられるうえ、トランザクションを使わずに安全に操作できる点も大きなメリットです(詳細は後述します)。

SET favNum 10
INCR favNum # 11
INCR favNum # 12
DECR favNum # 11

EXPIRE

EXPIREは、キーに有効期限を設定するコマンドです。厳密にはタイマーではなく、「期限切れのタイムスタンプ」を記録し、その時刻を過ぎるとキーは再設定されるまで常にnullを返すようになります。

SET bitcoin 100
EXPIRE bitcoin 10
GET bitcoin # 100
# 10秒後
GET bitcoin # null

EXPIREを使用すると、有効期限の情報も保存する必要があるため、キー全体のメモリ消費がわずかに増えます。とはいえ、このオーバーヘッドを気にする必要はほぼないでしょう。

TTL

TTLは、キーがあとどれくらい生存するか(残り時間)を確認するコマンドです。

SET bitcoin 100
TTL bitcoin # -1
TTL somethingelse # -2
EXPIRE bitcoin 5
# 2秒待機
TTL bitcoin # 3 が返る
# 1秒後
GET bitcoin # null
TTL bitcoin # -2

このコードから読み取れるTTLの戻り値のルールは以下の通りです。

  1. キーは存在するが有効期限が設定されていない場合:-1を返す
  2. キーが存在しない場合:-2を返す
  3. キーが存在し、有効期限が設定されている場合:残り秒数を返す

SETEX

SETEXを使えば、SETEXPIREを1つのコマンドで同時に実行できます。

SETEX key 10 value

この例では、キーが「key」、値が「value」、TTL(有効期限)が10秒です。10秒経過すると、このキーは自動的に削除されます。

これで基本的なRedisコマンドとCLIの使い方はマスターできました。次は、これらの知識を実践的なプロジェクトで活かしてみましょう。

プロジェクト1:RedisによるAPIキャッシュシステムの構築

このプロジェクトでは、Redisを使ったAPIキャッシュシステムを構築します。サードパーティサーバーからのレスポンスをキャッシュし、一定時間はそのキャッシュを再利用する仕組みです。

これにより、サードパーティのレート制限に引っかかるのを防げます。また、キャッシュはサイトの表示速度向上にもつながるため、正しく実装すれば一石二鳥です。

Node.jsを使えば、ブラウザ上でインタラクティブにこのプロジェクトを構築できます。まずは、Node.jsでのコアロジックがどのように動作するかを見てみましょう。

app.post('/data', async (req, res) => {
 const repo = req.body.repo
 const value = await redis.get(repo)
 if (value) {
 // キャッシュヒットの場合
 res.json({
 status: 'ok',
 stars: value
 })
 return
 }
 const response = await fetch(`https://api.github.com/repos/${repo}`).then((t) => t.json())
 if (response.stargazers_count != undefined) {
 await redis.setex(repo, 60, response.stargazers_count)
 }
 res.json({
 status: 'ok',
 stars: response.stargazers_count
 })
})

このコードの流れを解説します。

  • まず、渡されたリポジトリ名(facebook/reactのような形式)をキーに、Redisキャッシュから値を取得します。ヒットすれば、GitHubサーバーへの往復通信を省き、キャッシュされたスター数を即座に返します。
  • キャッシュになければ、GitHubのAPIにリクエストを送り、スター数を取得します。リポジトリが存在しない・非公開の場合に備えて、スター数がundefinedでないかを確認します。値があれば、setexで60秒の有効期限付きでキャッシュに保存します。
  • 有効期限を設けるのは、古いデータを永遠に返し続けないためです。これにより、スター数は最低でも1分に1回は更新されることになります。

プロジェクト2:RedisによるAPIレート制限

このプロジェクトでは、特定のエンドポイントにレート制限をかけ、悪意あるアクセスからAPIを保護する仕組みを構築します。

ログイン機能や機密性の高いAPIエンドポイントでは、一人のユーザーに数千件ものリクエストを送られるのは避けたいところです。そんなときにこの手法が威力を発揮します。

ここではIPアドレス単位でレート制限を行います。Node.jsでのコアロジックは以下の通りです。

app.post('/api/route', async (req, res) => {
 // ここに処理を追加
 const ip = req.headers['x-forwarded-for'] || req.ip
 const reqs = await redis.incr(ip)
 await redis.expire(ip, 2)
 if (reqs > 15) {
 return res.json({
 status: 'rate-limited'
 })
 } else if (reqs > 10) {
 return res.json({
 status: 'about-to-rate-limit'
 })
 } else {
 res.json({
 status: 'ok'
 })
 }
})

このコードブロックの動作を確認しましょう。

  • x-forwarded-forヘッダーからIPアドレスを抽出します(Expressを使用しているのでreq.ipでも代用可能です)。
  • IPアドレスをキーとしてINCRを実行します。Redisに該当キーが存在しない場合、INCRは自動的に0から始めて1をセットします。
  • キーに2秒の有効期限を設定します。実運用ではより長い値が望ましいですが、ここはチュートリアルの仕様に従っています。
  • 最後にリクエスト回数をチェックし、閾値を超えていれば、メインの処理本体にリクエストが到達する前にブロックします。

Redisをもっと深く知る

Redisには、ここまで学んできた内容以外にも多くの機能があります。しかし、すでに実務を始めるには十分な知識を身につけています!このセクションでは、さらなる基礎知識をいくつか紹介します。

Redisはシングルスレッドで動作する

Redisは、マルチスレッド対応のマルチコアシステム上でも、シングルスレッドのプロセスとして動作します。これはパフォーマンス上の弱点ではなく、マルチスレッド環境での不整合な読み書きを防ぐための安全策です。

もしRedisがマルチスレッドだったら、単一キーへのアクセス時にスレッドセーフを保証するため、何らかのロック機構が必要になるでしょう。しかし、そのロック機構はおそらくシングルスレッドの逐次アクセスよりも性能が劣ってしまいます。

Redisのトランザクション

もちろん、すべての操作を1つのコマンドで完結できるわけではありません。しかし、複数のコマンドをひとまとまりとして実行すること(つまり、そのブロックの実行中は他の誰もRedisに干渉できない状態)は可能です。これにはMULTIコマンドを使います。

MULTI
SET hello world
SET yo lo
SET number 1
INCR number
EXPIRE hello 10
EXPIRE yo 5
EXEC

このように書くと、すべての操作が一括で実行されます。MULTIの後は何も実行されず、EXECキーワードが現れた瞬間に、まとめてすべてが実行される仕組みです。

さらに高度なユースケース向けに、Redisはリストやセットもサポートしています。また、チャンネルに対してpublish(公開)を行い、そのチャンネルをsubscribe(購読)している他のクライアントに通知を届ける、ブロードキャストサービスとしても使えます。マルチクライアント構成において非常に有用な機能です。

まとめ

この記事が、Redis入門の助けになれば幸いです。ここで学んだ基礎コマンドと2つの実践プロジェクトの知識があれば、キャッシュやレート制限といった実用的なユースケースにすぐに取り掛かれます。

まずはCLIでコマンドを試しながら、実際に手を動かして理解を深めていきましょう。Redisの世界へようこそ!

  1. AWS LambdaとサーバーレスRedisで構築するReact Nativeアプリ:リーダーボード機能の実装ガイド

    この記事では、React Native、Serverless Framework、Upstashを組み合わせて、リーダーボード(ランキング)の閲覧・更新ができるモバイルアプリケーションを開発する方法を解説します。 モバイルアプリの開発にはReact Nativeを使用し、バックエンドはServerless Frameworkで構築します。バックエンドは、AWS Lambda上で動作するPython関数で構成されています。 1. Upstash Redisを活用する 一般的なリーダーボードアプリでは、ユーザー情報と各ユーザーのスコアを保存する必要があります。これらのデータはスコア順にソートされる

  2. Redisリスト入門:リスト型の値を管理するための主要コマンド一覧

    Redisリストとは Redisのリスト(List)は、挿入された順番どおりに並べられた文字列のシーケンスです。Redisでは、このリストをキーに対する値として保存することができます。さらに、さまざまなRedisコマンドを組み合わせることで、データベースに格納されたリスト値の保存・管理・取得を柔軟に行えます。 構文 redis host:post> <Command Name> <key name> 実行例 Redisリスト操作の主なコマンド一覧 Redisデータベース内のリスト値を管理するうえで押さえておきたい重要なコマンドを、以下の表にまとめました。