redis、それは危険なほどのスピード | サイバーエージェント 公式エンジニアブログ
redislogo

どうも、プラットフォームDivでエンジニアをやっている Wataru です。
最近3人目の子供が産まれて、産後自宅勤務をさせてくれた弊社はとてもいい会社だと思います。出産予定のあるエンジニアのかたは是非弊社に転職を。

さて、今回はRedisの紹介をさせて頂きたいと思います。

Redisってすごくマイナーなわけではないのですが、めちゃくちゃ便利なのにあまり注目されていないなーという印象があるので、これを機会に是非使ってみてもらえると嬉しいです。

Redisって何?

Redisとは「remote dictionary server」から名前が付けられたオープンソースのkey-valueデータストアです。
MemcacheDB等のKVSとの最大の違いは、格納するバリューがデータ構造というところです。
つまり、リスト・セット・ハッシュなどのデータ構造で格納できるのでバリューに対してアトミックな操作ができます。
例えば、リストではプッシュしたりポップしたりできるのです。
これによって大規模なデータの操作をする時にデータ構造だけプログラムの外部で管理する事ができるので大変便利です。
RedisはANSI Cで書かれていて、すべてのデータセットをメモリ内に読み込むため、危険なほどのスピードで動作するというのが売りです。
Salvatore Sanfilippo 氏によって開発されていてスポンサーにはVMwareがついています。
またリリースも頻繁に行われていて、そういった意味でも安心感のあるプロダクトとなっています。

Redisをランキング生成に使ってみてはどうだろう

データ構造を操作できるRedisの使い道は、ページビューの集計とか傾向分析とか色々と考えられますが、今回はRedisのデータ構造の中でも「ソート済みセット型」というのを使って、リアルタイムランキングを生成する方法を考えてみたいと思います。
リアルタイムランキングは、参照したタイミングで自分の順位を取得するわけですが、同率も考慮しなければいけないので下記のような手順で算出します。

①自分のポイントを取得
②自分のポイントより高得点のユーザー数をカウント
③それを+1したものが自分の順位

実際にRedisのコマンドではこんな感じになります。

redis 127.0.0.1:6379> zscore rank ${userのid}
redis 127.0.0.1:6379> zcount rank (${上で取得したscore} +inf

これで取得したrank+1が順位になります。

MySQLで同じ事をする場合のSQLはこんな感じですね。

SELECT count(id)+1 FROM ranking WHERE point < (SELECT point FROM ranking WHERE id=${userid})


KVSなのにこんな事できるなんてすごい!!

Redis、なにそれ美味しいの?

という訳で一応MySQLと比較してみました。
MySQLはメモリーエンジンを使っています。
DDLはこんな感じです。
drop table if exists ranking;
create table ranking(
  id VARCHAR(12) NOT NULL PRIMARY KEY,
  point BIGINT NOT NULL,
  INDEX USING HASH (point)
) ENGINE=MEMORY;
10万レコードにランダムなポイントを付けて書き込み、読み取りをするという検証方法です。
検証に使ったソースはGitHubにあげてありますので、そちらを参照していただければと思います。

https://github.com/wataru420/redisTest

検証環境

サーバDell PowerEdge R300
OSCentOS release 5.4 (Final)
CPUIntel(R) Core(TM)2 Duo CPU E6405 @ 2.13GHz ×2
Memory12G
MySQL5.5.15
Redis2.4.1
Java1.6.0 29
scala2.9.1

比較結果は下記の通り。


書き込み性能
RedisMySQL
1回目10581ms12080ms
2回目10658ms12061ms
3回目10519ms12171ms
4回目10791ms12054ms
5回目10571ms11793ms
6回目10590ms12473ms
7回目10890ms11937ms
8回目10524ms12008ms
9回目10658ms12017ms
10回目10495ms11919ms
平均10628ms12051ms

読み取り性能
RedisMySQL
1回目480254ms910331ms
2回目480016ms918647ms
3回目478447ms918561ms
4回目480574ms910602ms
5回目478681ms917728ms
6回目479560ms916124ms
7回目480081ms909503ms
8回目480529ms917050ms
9回目479809ms917383ms
10回目478096ms909949ms
平均479605ms914588ms


書き込みは若干、読み取りは圧倒的にRedisの方が早いという結果になりました。
Redisは書き込み時に順序付けした状態で書き込んでいるので読み取りが高速になるのかと思います。

まとめ

ランキングは昨今のソーシャルアプリには無くてはならない要素になっています。
またランキング以外にもオンメモリーで処理をしたいようなデータを扱う際はRedisはとても有効だと思います。
この記事を読んでRedis使ってみたいなと思って頂けたら幸いです。

是非みなさんも危険なほどのスピードを体験してみてください。

参考文献

redis公式サイト
http://redis.io/
redisドキュメント日本語訳
http://redis.shibu.jp/index.html
redisのgithubレポジトリー
https://github.com/antirez/redis