使用Ruby通过冗长的结构来使用Redis

下列是一份备忘录。

    • Redisを冗長構成で立ち上げる

 

    • Redis Sentinelでフェイルオーバーさせる

 

    この環境をRubyで使う

Redis是一种开源的内存数据结构存储系统。

一种基于内存的键值存储系统。非常快速。通过将数据复制到一个或多个从节点来提高读取性能。只有主节点可以进行写入操作,但从节点也可以进行读取操作。

Redis Sentinel是什么

Redis的故障转移机制是由Sentinel之间相互监视,当主节点死亡时选择下一个主节点。Sentinel可以从外部修改Redis的配置。

通过Sentinel的投票,决定主控是否存活以及在主控死亡时提升哪个从控。通常情况下,会运行3个或更多的Sentinel。

在进行故障转移时,需要注意Redis Sentinel会修改Redis的配置文件(redis.conf)。

在这个例子中,Redis使用端口6379,Redis Sentinel使用端口26379。

此文的结构 (Cǐ de

    • xxx.xxx.xxx.aaa – 初期設定でマスターになるホスト。Redis Sentinelを動かしている

 

    • xxx.xxx.xxx.bbb – 初期設定でスレーブになるホスト。Redis Sentinelを動かしている

 

    xxx.xxx.xxx.ccc – 初期設定でスレーブになるホスト。Redis Sentinelを動かしている

安装

我在CentOS 6.x上进行了测试。

安装Redis需要jemalloc。只需打开EPEL存储库并运行yum命令(应该可以)。

$ yum install -y ftp://195.220.108.108/linux/remi/enterprise/6/test/i386/redis-3.0.0-2.el6.remi.i686.rpm --enablerepo=epel

Redis的设置

暂时将/etc/redis.conf进行修改。

    • bind 127.0.0.1 があったらコメントアウトする。(他のホストからアクセスさせる場合)

 

    • slaveof xxx.xxx.xxx.aaa 6379 を指定する。(レプリケーションのスレーブになるホストだけ)

 

    必要に応じて、パスワードやiptablesなどを使ってセキュリティを確保する。

自动启动的设置

$ chkconfig redis on

Redis启动

$ service redis start

Redis Sentinel的配置

通常情况下,需要在三个或以上的主机上运行Redis Sentinel。即使没有运行Redis的节点也可以。需要修改/etc/redis-sentinel.conf文件。

    sentinel monitor mymaster xxx.xxx.xxx.aaa 6379 2 を書く (このアドレスとポートは、Redisマスターを示す)

设置自动启动

$ chkconfig redis-sentinel on

Redis Sentinel的启动

$ service redis-sentinel start

确认操作

当安装和确认操作在所有机器上都完成后,尝试确认其功能。

在大师的确认下

$ redis-cli info replication
# Replication
role:master
connected_slaves:2
slave0:ip=xxx.xxx.xxx.bbb,port=6379,state=online,offset=326322,lag=1
slave1:ip=xxx.xxx.xxx.ccc,port=6379,state=online,offset=326322,lag=2
master_repl_offset:326322
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:326321

确认在奴隶身份下

$ redis-cli info replication
# Replication
role:slave
master_host:xxx.xxx.xxx.aaa
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:301712
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

写下来试试看

由于从属方无法进行写入操作,因此需要连接到主控方。从属方仍然可以进行读取操作。

aaa是主机,bbb是自己(从机),ccc是另一台主机(从机)。

$ redis-cli -h xxx.xxx.xxx.aaa set foo "FOO"  # マスターにつないで書く
OK
$ redis-cli -h xxx.xxx.xxx.aaa get foo  # マスターにつないで読む
"FOO"
$ redis-cli get foo  # ローカルにつないで読む
"FOO"
$ redis-cli -h xxx.xxx.xxx.ccc get foo  # 別のスレーブにつないで読む
"FOO"

尝试执行故障转移

当停止Redis主节点时,应该有一个从节点将会晋升为主节点。

$ service redis stop
Stopping redis-server:                                     [  OK  ]
$ redis-cli info replication
Could not connect to Redis at 127.0.0.1:6379: Connection refused  # 止まっている

当检查从属bbb的状态时,我们发现bbb变成了主节点。

$ redis-cli info replication
# Replication
role:master
connected_slaves:1
slave0:ip=xxx.xxx.xxx.ccc,port=6379,state=online,offset=16735,lag=1
master_repl_offset:17017
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:17016

查看在【Slave】ccc上的状态时,发现【bbb】已成为主节点。

$ redis-cli info replication
# Replication
role:slave
master_host:xxx.xxx.xxx.bbb
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:40395
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

原本是主节点的aaa重新启动并检查状态,但bbb仍然保持为主节点。重新启动原本的主节点也无法成为主节点。

$ service redis start
Starting redis-server:                                     [  OK  ]
$ redis-cli info replication
# Replication
role:slave
master_host:xxx.xxx.xxx.bbb
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:57832
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

尝试使用Ruby

为了使用Ruby中的Redis,我们可以使用redis Gem。这个Gem支持Sentinel。只需将与Sentinel相关的参数提供给Redis.new的参数即可。

require 'redis'

sentinels = [
             { host: 'xxx.xxx.xxx.aaa', port: 26379 },
             { host: 'xxx.xxx.xxx.bbb', port: 26379 },
             { host: 'xxx.xxx.xxx.ccc', port: 26379 },
            ]

redis = Redis.new(url:'redis://mymaster', sentinels: sentinels, role:'master')

p redis.get('foo') #=> "FOO"  # 読んでみる

redis.set('bar', 'BAR')  # 書いてみる
p redis.get('bar') #=> "BAR"
bannerAds