ニコニコ生放送に見る Redis 活用ノウハウ

第2回 Redisの導入と基本機能

この記事を読むのに必要な時間:およそ 3 分

キーのタイムアウト

memcachedのexpireと同様の仕組みとして,既存のキーにタイムアウトを設定するEXPIREコマンドが用意されています。EXPIREコマンドでは,タイムアウトを秒単位で指定します。

次の例では,文字列をセットしてからタイムアウトを10秒で設定し,その後キーが消えるのを確認しています。

redis> SET mykey something
OK
redis> EXPIRE mykey 10
(integer) 1
redis> GET mykey
"something"
redis> GET mykey
"something"
redis> GET mykey
(nil)

この例のように,単純にSETと同時にEXPIREするだけであれば,SETEXコマンドも使用できます。

redis> SETEX mykey 10 something
OK

はまりどころとして,バージョン2.0では,タイムアウトを設定した値を変更しようとすると元の値がクリアされるという仕様があります。次の例を見てください。

redis> SET mynum 10
OK
redis> EXPIRE mynum 100
(integer) 1
redis> INCR mynum
(integer) 1
redis> GET mynum
"1"

“mynum⁠⁠10⁠の状態でタイムアウトを設定し,その後インクリメントしようとしています。直感的には最後の結果は⁠11⁠になりそうですが,タイムアウト設定後に値を変更しようとしているため,元の⁠10⁠はクリアされて,結果としてインクリメント後の結果は⁠1⁠になってしまいます。

この仕様は,Redisのレプリケーション機能がmasterとslaveでそれぞれタイムアウトを制御していることによる不整合を回避するためのものです。

バージョン2.2ではタイムアウトがmaster側で一元的に管理されるようになり,タイムアウト設定後のバリューも継続して変更可能となるようです。タイムアウトの詳細な仕様については公式のドキュメントを参照ください。

DBの選択

Redisのデータセットは,DB index(デフォルトでは0~15)で表されるDBによって分割されています。サーバーに接続した時点では必ず⁠0⁠のDBを参照するようになっており,参照先のDBを選択するにはSELECTコマンドを実行します。

次の例では,異なるDB(⁠⁠0⁠⁠2⁠⁠)に同じキー名⁠mykey⁠の値を格納しています。

redis> SET mykey ABCDEFG
OK
redis> SELECT 2
OK
redis> SET mykey 1234567
OK
redis> SELECT 0
OK
redis> GET mykey
"ABCDEFG"

DB選択の利用例としては,開発環境上で複数の開発メンバーでRedisサーバーを共有するために,各メンバーごとに個別のDBを割り当ててキーの干渉を防ぐことが挙げられます。

複数コマンドのアトミック実行

Redisは,複数のコマンドをアトミックに実行するMULTI/EXECという仕組みを備えています。次のケースを考えてみましょう。

  • ウェブページのアクセス数をカウントするキー“counter”がある。
  • このカウンタの現在値を取得し,同時に“0”にリセットしたい。

この場合,現在値を取得するGETと,⁠0⁠にリセットするSETがアトミックに処理されないと,カウントの取りこぼしが発生してしまいます※1⁠。これをMULTI/EXECで実装すると次のようになります。

redis> MULTI
OK
redis> GET counter
QUEUED
redis> SET counter 0
QUEUED
redis> EXEC
1. "10000"
2. OK

MULTIに続くコマンドはすぐには実行されず,キューに積まれた状態になります(QUEUED⁠⁠。最後にEXECを実行することによって,キューに積まれたすべてのコマンドがアトミックに実行されます。この例ではEXECの結果が2つ返っていますが,一つ目が最初のGETの結果(⁠⁠counter⁠の現在値)で,二つ目がSETの結果になっています。

なお,MULTI/EXECはトランザクション処理として実装されているわけではありません。例えば,EXECで複数のコマンドを実行中にエラーが発生してもロールバックされず,単純に残りの処理が継続して実行されてしまう点に注意してください。

他のMULTI/EXEC関連のコマンドとしては,キューに積まれたコマンドをキャンセルするDISCARDや,バージョン2.1以降では,CAS操作を実現するWATCHなどがあります。

※1
実はこのようなニーズのためのGETSETという特別なコマンドが用意されています。

キーの検索

Redisに大量のデータを格納するようになると,キー名の一部が分かっていて,それに該当するキーを検索したいという場面がよくあります。KEYSコマンドを使えば,globスタイルのパターンマッチングによって現在のデータセットから該当するキー名の一覧を得ることができます。

例として,キー名が次のフォーマットで設計されているとします。

user:ユーザID:属性名

このとき,ユーザID ⁠123⁠に関するキーは次のように取得できます。

redis> KEYS user:123:*
1. "user:123:age"
2. "user:123:location"
3. "user:123:name"

次に,属性⁠location⁠に該当するキーを検索してみます。

redis> KEYS user:*:location
1. "user:123:location"
2. "user:456:location"
3. "user:252:location"

この例は小規模なものですが,本番稼働中の大規模なデータセットで実行した場合,全キーのスキャンにかかるコストが大きいため,サービスのパフォーマンスが低下する恐れがあります。あくまでも開発中や本番環境の調査時などの使用にとどめた方が良いでしょう。

まとめ

今回は,Redisサーバーのインストールから,コマンドラインクライアント「redis-cli」を使った基本的な操作,さらにタイムアウトやキー検索などRedis特有の重要な機能について説明しました。

次回からは,Redisの「data structure server」の側面である各種データ型について掘り下げていきます。

著者プロフィール

小野侑一(おのゆういち)

株式会社ドワンゴ ニコニコ生放送システムリーダー。

ニコニコ生放送での開発経験を通して,ウェブをリアルタイム化する技術の重要性に着目。その成果としてリアルタイムタグ検索やRedisを活用したリアルタイム視聴者集計システムを開発。現在は全文検索のリアルタイム化に注目している。

Twitter@synk