2013年1月22日火曜日

Redisってなんじゃ?(レプリケーションとクラスタリング)

Redisはとても高速ですが、メモリ量の圧迫や負荷によっては分散が必要な場合があります。
分散の種類としては、レプリケーションとクラスタリングがあります。

レプリケーションは、マスタに書き込んだデータをスレーブにコピーすることで、書き込みはマスタ、読み取りはスレーブと担当を分けることで負荷を分散させます。読み取りにはマスタも参加することもあります。



クラスタリングは、キーのハッシュ値などによって保存するサーバーが決まり、書き込みと読み取りの両方を同時に負荷分散します。





レプリケーション


レプリケーションはRedisの基本機能として提供されているので、すぐに利用できます。
設定も簡単で、スレーブサーバーの設定ファイルに1行追記するだけです。

それでは試してみます。ここではRedis1をマスター、Redis2をスレーブとします。


インストール&設定

●Redis1(10.0.0.10), Redis2(10.0.0.20)

インストールします。
# cd /usr/local/src
# curl -OL http://redis.googlecode.com/files/redis-2.6.4.tar.gz
# tar xzf redis-2.6.4.tar.gz
# cd redis-2.6.4
# make
# make install
# mkdir /etc/redis /var/lib/redis
# cd /usr/local/src/redis-2.6.4/
# cp redis.conf /etc/redis/
2013/01/22追記:redis-2.6.3だとスムーズに行かない環境があるようなので、記事中のバージョンをredis-2.6.4に変更しました。


●Redis2

スレーブ側の設定ファイルでマスタを指定します。
# vim /etc/redis/redis.conf
---
slaveof 10.0.0.10 6379
---


●Redis1, Redis2

起動します。
# nohup redis-server /etc/redis/redis.conf &



確認

●Redis1

書き込みます。
# redis-cli
redis 127.0.0.1:6379> set hello "world"
OK
redis 127.0.0.1:6379> get hello
"world"


●Redis2

マスタで書き込んだキーを読みとります。
# redis-cli
redis 127.0.0.1:6379> get hello
"world"

ちゃんと取得出来ました。



クラスタリング


現時点での最新安定バージョン2.6.9ではまだクラスタリングはサポートされておらず、unstable版に含まれていす。
この機能はまだ不安定なため、正式サポートを待つ形になります。
別の方法として、twemproxyというmemcached, redisプロトコルに対応したtwitter製のプロキシを使うことで簡単なクラスタリングを実現できます。

ちなみにmemcachedプロトコルでのtwemproxyの使用はこちらが参考になります。
suz-lab:TwemproxyからElastiCacheに分散(同じキーは同じElastiCacheへ)してみる



インストール&設定

●Redis1(10.0.0.10), Redis2(10.0.0.20)

redisは普通にインストールします。
# cd /usr/local/src
# curl -OL http://redis.googlecode.com/files/redis-2.6.4.tar.gz
# tar xzf redis-2.6.4.tar.gz
# cd redis-2.6.4
# make
# make install
# mkdir /etc/redis /var/lib/redis
# cd /usr/local/src/redis-2.6.4/
# cp redis.conf /etc/redis/
# nohup redis-server /etc/redis/redis.conf &
2013/01/22追記:redis-2.6.3だとスムーズに行かない環境があるようなので、記事中のバージョンをredis-2.6.4に変更しました。


●Proxy(10.0.0.30)

twemproxyと必要なautoconfツール群をインストールします。
yumのデフォルトで入るバージョンは古いためエラーになるのでソースから入れます。
# cd /usr/local/src
# curl -OL http://redis.googlecode.com/files/redis-2.6.4.tar.gz
# tar xzf redis-2.6.4.tar.gz
# cd redis-2.6.4
# make
# make install

# cd ../
# curl -OL http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
# tar xvzf autoconf-2.69.tar.gz
# cd autoconf-2.69
# ./configure
# make
# make install

# cd ../
# curl -OL http://ftp.gnu.org/gnu/automake/automake-1.12.tar.gz
# tar xvzf automake-1.12.tar.gz
# cd automake-1.12
# ./configure
# make
# make install

# cd ../
# curl -OL http://ftp.jaist.ac.jp/pub/GNU/libtool/libtool-2.4.2.tar.gz
# tar xvzf libtool-2.4.2.tar.gz
# cd libtool-2.4.2
# ./configure
# make
# make install

# cd ../
# curl -OL https://github.com/twitter/twemproxy/archive/v0.2.2.zip
# unzip v0.2.2.zip
# cd twemproxy-0.2.2/
# /usr/local/bin/autoreconf -fvi
# ./configure
# make
# make install
2013/01/22追記:redis-2.6.3だとスムーズに行かない環境があるようなので、記事中のバージョンをredis-2.6.4に変更しました。


twemproxyの設定ファイルを作成します。
# cd ~/
# vim nuckcracker.yml
redis:
  listen: 0.0.0.0:22222
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  timeout: 400
  redis: true
  servers:
   - 10.0.0.10:6379:1 twemredis1
   - 10.0.0.20:6379:1 twemredis2

  • listen:twemproxyのリスンポートの指定です。 
  • distribution:分散方式(ketama=ConsistentHashingのことです)
  • hash:ハッシュ方式(fnv系はmd5などと比べて短い値でも分散率が高いですが、衝突率はmd5より高いようです) 
  • auto_eject_hosts:失敗が多かったホストを自動的にリングから外されます。 
  • timeout:分散先サーバーとの通信タイムアウト時間(ミリ秒)です。 
  • redis:trueならredisプロトコル、falseならmemcachedプロトコルになります。 
  • servers:分散先のサーバー群です。


起動します。
# nutcracker -c nutcracker.yml -d


確認

●Proxy

いくつかキーとバリューをsetします。
# redis-cli
redis 127.0.0.1:22222> set hoge "moge"
OK
redis 127.0.0.1:22222> get hoge
"moge"
redis 127.0.0.1:22222> set hello "world"
OK
redis 127.0.0.1:22222> get hello
"world"


●Redis1

セットしたキーを取得します。
いくつかは取得できません。
# redis-cli
redis 127.0.0.1:6379> get hoge
"moge"
redis 127.0.0.1:6379> get hello
(nil)


●Redis 2

セットしたキーを取得します。
Redis1で取得できなかったキーは取得でき、Redis1 で取得できたキーは取得出来ません。
# redis-cli
redis 127.0.0.1:6379> get hoge
(nil)
redis 127.0.0.1:6379> get hello
"world"


●Proxy

Proxy側からは両方取得できます。
# redis-cli
redis 127.0.0.1:22222> get hoge
"moge"
redis 127.0.0.1:22222> get hello
"world"

きちんと分散されているようです。



再ハッシュ

自動再ハッシュはサポートされていないので、SLAVEのONとOFFを切り替えを行なったりして、データをコピーしながら再構成していくような工夫が必要なようです。

たとえば、1つのRedisサーバーからもう1台追加してクラスタリングする場合、まずSLAVEOFで1台目をマスタにしてデータをコピーします。その後twemproxyを起動して、2台目をSLAVE解除します。
2台目にコピーされたデータのうち、2台目に割り振られるハッシュキーだけが使用され、約半分は1台目に割り振られるため、使われなくなります。


このようにしてレプリケーションやクラスタリングで負荷を分散させたり、ホットスタンバイをつくることができます。

レプリケーションとクラスタリングを組み合わせたり、シングルポイントとなるtwemproxyを冗長化させたりすることも可能ですね。


以上です。