Redis事始め

NoSQL の Redis は機能がコンパクトにまとまっていて、学習しやすそうだったので、ちょっと触ってみた。

インストール

ソースコード

CI

recidiv という Tcl でかかれた CI を利用

Linux 環境

$ wget http://redis.googlecode.com/files/redis-2.4.7.tar.gz
$ make
$ make test
…
\o/ All tests passed without errors!

Cleanup: may take some time... OK
make[1]: Leaving directory `/home/john/dev/redis-2.4.5/src'

テスト時のエラー

テストの実行には tcl が必要。インストールされていない場合は次のようなエラーが出力される。

$ make test
You need 'tclsh8.5′ in order to run the Redis test.

エラーメッセージ通り tclsh8.5 をインストールすること。

$ sudo apt-get install tcl8.5 # Debian variant
$ sudo yum install tcl # RetHat variant

FreeBSD 環境
README 通りに $ make を実行すると、次のようなエラーが起きる。

$ make
cd src && make all
"Makefile", line 16: Need an operator
"Makefile", line 19: Need an operator
"Makefile", line 21: Missing dependency operator
"Makefile", line 22: Missing dependency operator
…

make ではなく gmake を指定。インストールされていなければ $ pkg_add -r gmake でインストールする。
テスト用の tcl は tcl-8.5.11 をインストール

$ sudo pkg_add -r tcl-8.5.11

Windows 環境

次のURLからバイナリーをダウンロード

https://github.com/dmajkic/redis/downloads

Windows 向けパッチが Microsoft Interop Team から提供されたが、Reject されている。経緯は以下の URL を参照

バインディングのインストール

Python

http://pypi.python.org/pypi/redis/
$ pip install redis

Ruby

http://rubygems.org/gems/redis
$ gem install redis

上記はピュア Python/Ruby で書かれている。パーサー部分が C で書かれ、高速に動作するバインディング(hiredis)もあるので、実用の際はそちらを利用すべし。
インストールの際には redis を hiredis に変えれば OK

サーバーの起動

src ディレクトリに移動し、redis-server を起動

$ ./redis-server
[451] 05 Feb 00:10:25 # Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'
[451] 05 Feb 00:10:25 * Server started, Redis version 2.4.5

デフォルトでは 6379 ポートでリクエストを受け付ける

クライアントの起動
cli, telnet, netcat での接続を確認。

CLI

$ ./redis-cli
redis 127.0.0.1:6379> PING
PONG
redis 127.0.0.1:6379> SET foo hello
OK
redis 127.0.0.1:6379> GET foo
"hello"

telnet

$ telnet localhost 6379
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
PING
+PONG
SET foo hello
+OK
GET foo
$5
hello

netcat

$ (echo -en "PING\r\n";sleep 1) | nc localhost 6379
+PONG

netcat はレスポンスを待たずに終了するようで、redis からのレスポンスを受け取れるように “sleep 1” を挟んである

https://github.com/antirez/redis/issues/229

通信プロトコルの仕様

http://redis.io/topics/protocol

サーバと通信時にクライアントが TCP で送信するデータは以下の仕様になっている。

*<number of arguments> CR LF
$<number of bytes of argument 1> CR LF
<argument data> CR LF
...
$<number of bytes of argument N> CR LF
<argument data> CR LF

コマンド例

PING の場合、引数はないので number of arguments は 1
PING のバイト数は4。
以上から “*1\r\n$4\r\nPING\r\n” となる

実際の通信パケットは tcpdump を使って次のように確認できる。

$ sudo /usr/sbin/tcpdump -ni lo port 6379 -Xn

ソケットプログラム例

以上をまとめてると、クライアントを実装すると以下のようになる

import socket
import sys

class redis_sock:
    def __init__(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def connect(self, host, port):
        self.sock.connect((host, port))

    def send(self, command):
        command = ['$%d\r\n%s\r\n' % (len(cmd), cmd) for cmd in command]
        data = '*%d\r\n%s' % (len(command), ''.join(command))
        print repr(data)
        self.sock.send(data)

    def recv(self):
        data = self.sock.recv(1024)
        print repr(data)

def test(cmd):
    sock = redis_sock()
    sock.connect('localhost', 6379)
    sock.send(cmd)
    sock.recv()

if __name__ == '__main__':
    test(['PING'])
    test(['SET', 'foo', 'hello'])
    test(['GET', 'foo'])

実行結果は以下

'*1\r\n$4\r\nPING\r\n'
'+PONG\r\n'
'*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$5\r\nhello\r\n'
'+OK\r\n'
'*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n'
'$5\r\nhello\r\n'

サーバー設定

redis サーバの設定は redis.conf で設定する

サーバ起動時に引数で設定ファイルへのパスを指定する

$ redis-server /path/to/redis.conf

デーモン起動

redis.conf の次の箇所を修正する。

# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no

# When running daemonized, Redis writes a pid file in /var/run/redis.pid by
# default. You can specify a custom pid file location here.
pidfile /var/run/redis.pid

レプリケーション

マスターとは別ポートで起動し redis.conf の以下の slaveof 設定をマスターの情報に変更する

################################# REPLICATION #################################

# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. Note that the configuration is local to the slave
# so for example it is possible to configure the slave to save the DB with a
# different interval, or to listen to another port, and so on.
#
# slaveof <masterip> <masterport>

master-slave 構成にした時の起動ログは以下

マスターログ

$ ./redis-server
[10135] 05 Feb 00:21:14 * Server started, Redis version 2.4.5
[10135] 05 Feb 00:21:14 * DB loaded from disk: 0 seconds
[10135] 05 Feb 00:21:14 * The server is now ready to accept connections on port 6379
[10135] 05 Feb 00:21:14 - 0 clients connected (0 slaves), 717496 bytes in use
[10135] 05 Feb 00:21:19 - 0 clients connected (0 slaves), 717496 bytes in use
[10135] 05 Feb 00:21:21 - Accepted 127.0.0.1:54682
[10135] 05 Feb 00:21:21 * Slave ask for synchronization
[10135] 05 Feb 00:21:21 * Starting BGSAVE for SYNC
[10135] 05 Feb 00:21:21 * Background saving started by pid 10141
[10141] 05 Feb 00:21:21 * DB saved on disk
[10135] 05 Feb 00:21:21 * Background saving terminated with success
[10135] 05 Feb 00:21:21 * Synchronization with slave succeeded
[10135] 05 Feb 00:21:25 - 0 clients connected (1 slaves), 726088 bytes in use

スレーブログ

$ ./redis-server redis-slave.conf
[10138] 05 Feb 00:21:21 * Server started, Redis version 2.4.5
[10138] 05 Feb 00:21:21 * DB loaded from disk: 0 seconds
[10138] 05 Feb 00:21:21 * The server is now ready to accept connections on port XXXX
[10138] 05 Feb 00:21:21 - 0 clients connected (0 slaves), 717512 bytes in use
[10138] 05 Feb 00:21:21 * Connecting to MASTER...
[10138] 05 Feb 00:21:21 * MASTER <-> SLAVE sync started
[10138] 05 Feb 00:21:21 * Non blocking connect for SYNC fired the event.
[10138] 05 Feb 00:21:21 * MASTER <-> SLAVE sync: receiving 10 bytes from master
[10138] 05 Feb 00:21:21 * MASTER <-> SLAVE sync: Loading DB in memory
[10138] 05 Feb 00:21:21 * MASTER <-> SLAVE sync: Finished with success
[10138] 05 Feb 00:21:26 - 1 clients connected (0 slaves), 726064 bytes in use
Advertisements
Tagged with:
Posted in database

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
  • RT @__apf__: How to write a research paper: a guide for software engineers & practitioners. docs.google.com/presentation/d… /cc @inwyrd 4 months ago
  • RT @HayatoChiba: 昔、自然と対話しながら数学に打ち込んだら何かを悟れるのではと思いたち、専門書1つだけ持ってパワースポットで名高い奈良の山奥に1週間籠ったことがある。しかし泊まった民宿にドカベンが全巻揃っていたため、水島新司と対話しただけで1週間過ぎた。 それ… 5 months ago
  • RT @googlecloud: Ever wonder what underwater fiber optic internet cables look like? Look no further than this deep dive w/ @NatAndLo: https… 5 months ago
  • @ijin UTC+01:00 な時間帯で生活しています、、、 10 months ago
  • RT @mattcutts: Google's world-class Site Reliability Engineering team wrote a new book: amazon.com/Site-Reliabili… It's about managing produc… 1 year ago
%d bloggers like this: