20
redis 活用術 初級 発表者:鄭・在燮 -普段使ってないコマンドを有効に活用しよう-

Redis 活用術 初級

Embed Size (px)

Citation preview

Page 1: Redis 活用術 初級

redis 活用術 初級

発表者:鄭・在燮

-普段使ってないコマンドを有効に活用しよう-

Page 2: Redis 活用術 初級

目次

• ログの管理に活用

• 「いいね!」管理に活用

• 訪問者数(DAUなど)に活用

• 最近クリックした商品リスト表示に活用

• 同点問題を解決するには

• Pipelineについて

• Keysコマンドの代案について

• BigO表記法について

Page 3: Redis 活用術 初級

ログの管理に活用

…サーバが複数…

log log log log log log log

・ログを調べるために各サーバ接続し、調べるのはとても大変

Page 4: Redis 活用術 初級

ログの管理に活用

…サーバが複数…

redis バッチサーバ

ストレージ

バッチ処理で定期的にストレージに保存

一つのサーバで確認 できるので楽

Page 5: Redis 活用術 初級

ログの管理に活用

■方法1 WEBサーバ側 ・APPEND key value:ログを継続的に追加 バッチサーバ側 ・GETSET key value:keyの値を読み込み、keyの値を空にする ※GET&SETは他のアクセスで途中に新しいログ書き込みがある可能性があるためだめ!

このやり方には実は問題が一つある

APPENDコマンドは値を追加するたびにメモリの当てる・解放 →作り変える作業が発生

一つのkeyではなく複数のkeyにログを保存する方法にしたら、バッチ処理が何かの理由で止まってしまったら、どのkeyまで処理されたのかがわかりにくい

Page 6: Redis 活用術 初級

ログの管理に活用

■方法2 ・Listデータ型を使用 WEBサーバ側 ・LPUSH key value [value ...]:Listデータ型にログを継続的に追加 バッチサーバ側 ・RPOP key:最初に書き込まれたデータから値を取得&削除

バッチ処理が何かの理由で止まってしまっても、どこまで処理されたか気にせずRPOPで処理可能

Page 7: Redis 活用術 初級

「いいね!」管理に活用

・SETデータ型を使用 ・SETデータ型は重複を許容しない

・SADD key member [member ...]:書き込み毎のkeyに対して「いいね」が押されたらユーザーIDを追加 ・SREM key member [member ...]:「いいね」を取り消す ・SISMEMBER key member:ユーザーが「いいね」を押したかどうか判定 ・SCARD key:「いいね」が押された回数を取得

Page 8: Redis 活用術 初級

訪問者数(DAUなど)に活用

・BITを使用 ・BITは0or1。ユーザー毎にフラグを立てるようなデータに適している ・unique:visitors:20140422→[0,0,1,1,0,1,0,0][1,0,0,1,0,1,0,1][,0,0,1,0,1,0,1,0]…

offset 0 7 8 15

・offsetをユーザーIDだと考える ・SETBIT key offset value:offsetにユーザーIDを、valueに1を ・BITCOUNT key [start] [end]:bitが1であるデータのカウントを取得→DAU ・start、endはByte単位なので使用にご注意 ・DAU計算をバッチ処理などに頼らずに低費用で即時に確認できる

Page 9: Redis 活用術 初級

訪問者数(DAUなど)に活用 ・1週間連続でログインしたユーザー数を出してほしい ・GETBIT key offset:offsetの値を取得 for i=0, ‘全体ユーザーArray’ { a = GETBIT(unique:visitors:20140416, i); b = GETBIT(unique:visitors:20140417, i); c = GETBIT(unique:visitors:20140418 i); d = GETBIT(unique:visitors:20140419, i); e = GETBIT(unique:visitors:20140420, i); f = GETBIT(unique:visitors:20140421, i); g = GETBIT(unique:visitors:20140422, i); isLogin = (a && b && c && d && e && f && g); if (isLogin) { weeklyVisitCount++; } } ・ユーザー毎に7回のGETBITが発生。ユーザーが1000万人なら7000万回。

Page 10: Redis 活用術 初級

訪問者数(DAUなど)に活用 ・BITOP operation destkey key [key ...]:ビット演算した結果をdestkeyへ保存 operationは「AND, OR, XOR, NOT」が可能 AND:両方1の場合1 OR:片方が1の場合1 XOR:相違の値の場合(0と1, 1と0)1 NOT:逆の値を返す ・BITOP AND key unique:visitors:20140416 unique:visitors:20140417 unique:visitors:20140418 … 1週間分 ・ビット演算結果を保存したkeyに対してBITCOUNTコマンドで1週間連続ログインしたユーザー数を取得 →2回のコマンドで取得可能に

Page 11: Redis 活用術 初級

訪問者数(DAUなど)に活用 ・1週間連続でログインしたユーザーの数ではなくユーザーIDを出してほしい。そのユーザーにはイベント報酬として何かを配りたい。 ・1週間連続でログイン結果をとにかくビット演算する ・GETBITをユーザー数分実行→1000万回発生 方法1 ・BITOPでビット演算→GETで全体値を取得し、PHP側でログインしたユーザーを切り分ける →WEBサーバには費用はかかるが、redisにはやさしい 方法2 ・Luaスクリプトを使用 ※redisでLuaスクリプトを実行するにしてもシングルスレッドということは変わらないので、注意

Page 12: Redis 活用術 初級

最近クリックした商品リスト表示に活用

・最近クリックした商品のリストを常に5件表示したい。詳細画面では30件まで表示したい ・Sorted Setを使用 ・Sorted Setは重複を許容しない&順番がある ・ZADD key score member [score member ...]:scoreにはクリックした時間とする ・ZREVRANGE key start stop [WITHSCORES]:クリックした商品のリストを取得。start stopで何件取ってくるかも可能 ・ZREMRANGEBYRANK key start stop:addして全体件数が31件になったら一番古いものを削除

Page 13: Redis 活用術 初級

同点問題を解決するには

・ZREVRANK、ZRANKという便利なコマンドがある ・同点を考慮した順位を返してはくれない ・今後redisで対応される予定だが、古いバージョンでは以下の方法が考えられる ・ZSCORE key member:ユーザーのスコアを取得 ・ZCOUNT key min max:minにユーザーのスコア、maxに最大値(+inf) ・ZCOUNTの結果から+1すれば同点を考慮した順位になる

Page 14: Redis 活用術 初級

Pipelineについて

・pipelineはredisコマンドをまとめて転送&結果を受け取る方法 ・redisサーバの負荷的にはあまり変わらないが、I/Oを減らせるので結果的にパフォーマンスUPにつながる ・redisのコマンドではない。phpredisのようなクライアントで実現したもの

・まとめたコマンドが実行されるので他のアクセスからのコマンドは待機されるのでは? →待機されない →クライアントによっては内部的にMULTI/EXECを使用していて待機されることもあるので、使っているクライアントを確認するのが必要 ・redisのトランザクションであるMULTI/EXECもコマンドをまとめて実行するが、トランザクションが実行される間は他のコマンドは待機される ・phpredisはどうなっている? $ret = $redis->multi(Redis::MULTI) →トランザクション使用 $ret = $redis->multi(Redis::PIPELINE) →pipeline使用(トランザクション使用しない) ※引数のDefaultは「Redis::MULTI」

Page 15: Redis 活用術 初級

Pipelineについて

・MSET key value [key value ...] ・MGET key [key ...] などのコマンドはまとめてget・setするのでpipelineと同じ効果がある

Page 16: Redis 活用術 初級

Keysコマンドの代案について

・KEYS pattern:patternに合うkey達を探してくれる ・keyの数に比例して費用が高くなるので軽々使ったら痛い目に合う ・でも、とても便利そうなコマンドなので使いたくはなる ・バージョン2.8から追加された「SCAN、SSCAN、ZSCAN、HSCAN」 ・SCAN cursor [MATCH pattern] [COUNT count]:全体keyが対象 ・SSCAN key cursor [MATCH pattern] [COUNT count]:指定setが対象 ・ZSCAN key cursor [MATCH pattern] [COUNT count]:指定sorted setが対象 ・HSCAN key cursor [MATCH pattern] [COUNT count]:指定hashが対象 ・SCANを使用すると次のcursor位置と結果値を返してくれる。 ・帰ってきたcursorで再度SCAN実行。cursorが0になるまで実行 ・数回SCANすることになるが、一つのコマンドが重くはないので他のコマンドが待機されるのを防ぐ

Page 17: Redis 活用術 初級

BigO表記法について

・redisはコマンドの費用を表示するための方法としてBigO表記を採用している ・http://redis.io/commands/mget ・http://redis.io/commands/keys などのコマンド詳細ページから確認できる ・redisコマンドではほとんどが「 O(1)、 O(N)、 O(log(N)) 」 ・同じ「O(N)」でもNの対象が何になるのかによって費用はまったく違うので詳細説明を確認するのが重要 ・たとえば、MGETもKEYSも同じ「O(N)」である

Page 18: Redis 活用術 初級

BigO表記法について

・http://apelbaum.wordpress.com/2011/05/05/big-o/

Page 19: Redis 活用術 初級

おさらい

• List:データ入力の順番操作が簡単

• Set:重複を許容しない

• Sorted set:重複を許容しない&順位

• Bit:0or1。ユーザー毎にフラグを立てる

• pipelineを有効に使おう

• 各コマンドの費用(BigO表記)に気を付ける

Page 20: Redis 活用術 初級

ご清聴ありがとうございました。