RedisをPacemakerで冗長化する

本稿では、Pacemaker/Corosyncを使用してRedisのクラスタを構成する方法をご紹介します。
RedisはSentinelでマスター・スレーブ構成の管理を行うことができますが、最低3個のSentinelが必要になります。また、仮想IPについては自前でスクリプトを作成するなどの工夫が必要になります。

2ノードで完結させたい場合や、その他のリソースもあわせて管理したい場合はPacemaker/Corosyncを使用するのが便利です。Pacemakerには標準でRedisのリソースエージェントが含まれているため、比較的容易にRedisのクラスタを構築することができます。

前提

以下の環境を前提とします。今回はOS標準のPacemakerを使用します。

  • OS: CentOS 7.4
  • パッケージ:
    • redis-5.0.5-1.el7.remi
    • pacemaker-1.1.19-8.el7_6.4
    • corosync-2.4.3-4.el7
ホスト名 IPアドレス
server1 192.168.237.101
server2 192.168.237.102
(VIP) 192.168.237.150

RedisとPacemakerのクラスタ構成は以下のようになります。

RedisとPacemakerの構成

Pacemakerのインストールと初期設定

両方のノードに必要なパッケージをインストールします。なお、Redisのインストールおよびマスター・スレーブレプリケーションの設定は完了しているものとします。

# yum install corosync pacemaker pcs fence-agents-all

クラスタを新規作成します。

server1# pcs cluster auth server1 server2 -u hacluster -p (haclusterユーザのパスワード) --force
server1# pcs cluster setup --name cluster1 server1 server2

corosync.conf の quorum の設定に以下を追加します。これは2ノードクラスタで片方のノード単独で起動できるようにするために必要です(理由は後述します)。

quorum {
    provider: corosync_votequorum
    two_node: 1
    wait_for_all: 0  ★追加
}

クラスタを起動します。

server1# pcs cluster start --all

server1# pcs status
Cluster name: cluster1
Stack: corosync
Current DC: server1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Mon Jul  1 16:57:00 2019
Last change: Mon Jul  1 16:56:58 2019 by root via cibadmin on server1

2 nodes configured
0 resources configured

Online: [ server1 server2 ]

No resources


Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled

今回は動作確認のためSTONITHを無効化し、1回の障害検知でフェイルオーバーするように設定します。

# pcs property set stonith-enabled=false
# pcs resource defaults resource-stickiness=INFINITY migration-threshold=1

Pacemakerリソースの作成

仮想IPリソースを作成します。

# pcs resource create VIP ocf:heartbeat:IPaddr2 \
  ip=192.168.237.150 cidr_netmask=24 nic=eth1 \
  op monitor interval=10s

Redisのマスター・スレーブリソースを作成します。Pacemakerのマスター・スレーブリソースは、複数のノードに複製され、主従関係をもつリソースです。リソースエージェントは resource-agents パッケージに含まれる ocf:heartbeat:redis を使用します。以下の例では、redisリソースおよびそのマスター・スレーブリソースを一度に作成しています。マスター・スレーブリソースはデフォルトで「<リソースID>-master」(redis-master)という名前が付きます。

# pcs resource create redis ocf:heartbeat:redis \
  op start timeout=300s \
  op monitor interval=5s \
  op monitor interval=3s role=Master \
  master

VIPリソースとRedisのマスター・スレーブリソースのマスター側を colocation 制約で同じサーバに結び付けます。

# pcs constraint colocation add VIP with master redis-master score=INFINITY

この時点でリソースは起動しますが、一度両ノードのPacemakerを停止します。設定中にリソースを起動させたくない場合は先に両ノードをスタンバイモード(pcs node standby/unstandby)にしておいてもよいです。

server2# systemctl stop pacemaker
server1# systemctl stop pacemaker

クラスタの起動

Masterにしたいノード(server1)でPacemakerを起動します。

server1# systemctl start pacemaker
server1# pcs status
Cluster name: cluster1
Stack: corosync
Current DC: server1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Fri Jul 19 14:20:49 2019
Last change: Fri Jul 19 14:15:52 2019 by root via crm_attribute on server2

2 nodes configured
3 resources configured

Online: [ server1 ]
OFFLINE: [ server2 ]

Full list of resources:

 VIP    (ocf::heartbeat:IPaddr2):       Started server1
 Master/Slave Set: redis-master [redis]
     Masters: [ server1 ]
     Stopped: [ server2 ]

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled

server1ですべてのリソースの起動が完了したことを確認したら、server2のPacemakerを起動します。

server2# systemctl start pacemaker

しばらく待ち、リソースの起動が正常に完了すると以下のようになります。

# pcs status
Cluster name: cluster1
Stack: corosync
Current DC: server1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Fri Jul 19 14:24:24 2019
Last change: Fri Jul 19 14:15:52 2019 by root via crm_attribute on server2

2 nodes configured
3 resources configured

Online: [ server1 server2 ]

Full list of resources:

 VIP    (ocf::heartbeat:IPaddr2):       Started server1
 Master/Slave Set: redis-master [redis]
     Masters: [ server1 ]
     Slaves: [ server2 ]

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled

# pcs constraint
Location Constraints:
Ordering Constraints:
Colocation Constraints:
  VIP with redis-master (score:INFINITY) (rsc-role:Started) (with-rsc-role:Master)
Ticket Constraints:

Redisのレプリケーションが正常に行われていることを確認します。

server1# redis-cli info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.237.102,port=6379,state=online,offset=1372,lag=0

server2# redis-cli info replication
# Replication
role:slave
master_host:server1
master_port:6379
master_link_status:up

また、MasterノードにVIPが割り振られていることを確認します。

server1# ip -4 addr show dev eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.237.101/24 brd 192.168.237.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet 192.168.237.150/24 brd 192.168.237.255 scope global secondary eth1
       valid_lft forever preferred_lft forever

server2# ip -4 addr show dev eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    inet 192.168.237.102/24 brd 192.168.237.255 scope global eth1
       valid_lft forever preferred_lft forever

フェイルオーバー

RedisのMasterプロセスに障害を発生させ、server2がMasterになることを確認します。

server1# killall redis-server
server1# pcs status
Cluster name: cluster1
Stack: corosync
Current DC: server1 (version 1.1.19-8.el7_6.4-c3c624ea3d) - partition with quorum
Last updated: Fri Jul 19 15:34:23 2019
Last change: Fri Jul 19 15:33:18 2019 by root via crm_attribute on server2

2 nodes configured
3 resources configured

Online: [ server1 server2 ]

Full list of resources:

 VIP    (ocf::heartbeat:IPaddr2):       Started server2
 Master/Slave Set: redis-master [redis]
     Masters: [ server2 ]
     Stopped: [ server1 ]

Failed Actions:
* redis_demote_0 on server1 'not running' (7): call=49, status=complete, exitreason='',
    last-rc-change='Fri Jul 19 15:33:18 2019', queued=0ms, exec=85ms


Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled

redis リソースをクリーンアップし、server1がSlaveとして復旧することを確認します。

server1# pcs resource cleanup redis
Cleaned up redis:0 on server2
Cleaned up redis:0 on server1
Cleaned up redis:1 on server2
Cleaned up redis:1 on server1
Waiting for 1 replies from the CRMd. OK

# pcs status resources
 VIP    (ocf::heartbeat:IPaddr2):       Started server2
 Master/Slave Set: redis-master [redis]
     Masters: [ server2 ]
     Slaves: [ server1 ]

リソース起動時の注意点

Pacemaker/Corosyncの2ノードクラスタのデフォルトでは、両ノードのPacemakerが起動した時点でリソースを起動します。この場合、RedisのMasterとSlaveはほぼ同時に起動し、Masterの準備が完了していない状態でSlaveが接続しようとするため、レプリケーションの開始に失敗する場合があります。これを防ぐため、上記手順ではCorosyncの設定を変更し、Masterの起動を待ってからSlaveを起動するようにしています。