天天看點

利用redis-sentinel+consul實作redis高可用

在前文《利用redis-sentinel+keepalived實作redis高可用》較長的描述了利用redis-sentinel+keepalived實作redis高可用的方案。本文中redis-sentinel的應用場景也是一樣的,也是提供Redis單執行個體服務,當某Redis(master)服務意外停掉或該服務所在的主機發生當機故障或網絡故障時,另一台Redis服務會由slave自動成為master,提供Redis讀寫服務。redis-sentinel的配置可以參考前文,本文略去,隻讨論consul代替keepalived。

由于keepalived的應用場景有限,比如它的核心協定VRRP隻能工作在區域網路内,不能工作在區域網路外(網間、廣域網),而且在網絡不受自己控制時基本不能用,除非設定好的VIP是供區域網路使用。是以特别是在雲計算環境中,使用雲主機(例如阿裡雲ECS等)就不能用keepalived,是以隻能尋找一個可替代keepalived的解決方案來替代它。Consul作為服務注冊、服務發現的最佳選擇,無疑可以很好的替代keepalived。

前文是用的keepalived提供一個VIP為上層應用提供通路入口,本文是将keepalived替換成consul,利用consul的DNS Interface為上層應用提供Redis(master)的IP。

利用redis-sentinel+consul實作redis高可用

前提條件:需要一個可用的consul叢集,可以利用consul叢集本身和配置檔案注冊服務,也可以用一台單獨的主機注冊,還可以用HTTP API向Consul注冊。

為了擷取Redis(master)的IP而不是Redis(Slave)的IP,可以用腳本檢查實作,與keepalived腳本中相似,隻是傳回值将1設定成2,因為consul中傳回值0是沒問題(passed),1是警告(warning),2是嚴重(critical)。

下面是用一台單獨的主機注冊的例子。

json配置檔案如下:

{
  "services": [
    {
      "id": "redisnode1",
      "name": "redis",
      "tags": [
        "master"
      ],
      "address": "192.168.1.241",
      "port": 6379,
      "checks": [
        {
          "script": "/usr/local/sbin/redis-cli -h 192.168.1.241 -p 6379 info | grep role:master || exit 2",
          "interval": "5s"
        }
      ]
    },
    {
      "id": "redisnode2",
      "name": "redis",
      "tags": [
        "master"
      ],
      "address": "192.168.1.242",
      "port": 6379,
      "checks": [
        {
          "script": "/usr/local/sbin/redis-cli -h 192.168.1.242 -p 6379 info | grep role:master || exit 2",
          "interval": "5s"
        }
      ]
    },
    {
      "id": "redisnode3",
      "name": "redis",
      "tags": [
        "master"
      ],
      "address": "192.168.1.243",
      "port": 6379,
      "checks": [
        {
          "script": "/usr/local/sbin/redis-cli -h 192.168.1.243 -p 6379 info | grep role:master || exit 2",
          "interval": "5s"
        }
      ]
    }
  ]
}      

注冊是利用consul agent作為Client運作注冊的,假設consul叢集中某台Server的位址是192.168.1.245。

mkdir -p /usr/local/consul/data /usr/local/consul/config   
cat >/usr/local/consul/config/rediscluster.json<<eof
{
  "services": [
    {
      "id": "redisnode1",
      "name": "redis",
      "tags": [
        "master"
      ],
      "address": "192.168.1.241",
      "port": 6379,
      "checks": [
        {
          "script": "/usr/local/sbin/redis-cli -h 192.168.1.241 -p 6379 info | grep role:master || exit 2",
          "interval": "5s"
        }
      ]
    },
    {
      "id": "redisnode2",
      "name": "redis",
      "tags": [
        "master"
      ],
      "address": "192.168.1.242",
      "port": 6379,
      "checks": [
        {
          "script": "/usr/local/sbin/redis-cli -h 192.168.1.242 -p 6379 info | grep role:master || exit 2",
          "interval": "5s"
        }
      ]
    },
    {
      "id": "redisnode3",
      "name": "redis",
      "tags": [
        "master"
      ],
      "address": "192.168.1.243",
      "port": 6379,
      "checks": [
        {
          "script": "/usr/local/sbin/redis-cli -h 192.168.1.243 -p 6379 info | grep role:master || exit 2",
          "interval": "5s"
        }
      ]
    }
  ]
}
eof
/bin/consul agent -advertise=$(ifconfig $(route -n | awk '/^0.0.0.0/ && /UG/ {print $NF}') | grep inet | egrep -v "(inet6|127.0.0.1)" | cut -d ":" -f2 | cut -d " " -f1) -bind=$(ifconfig $(route -n | awk '/^0.0.0.0/ && /UG/ {print $NF}') | grep inet | egrep -v "(inet6|127.0.0.1)" | cut -d ":" -f2 | cut -d " " -f1) -data-dir=/usr/local/consul/data -config-dir=/usr/local/consul/config -join 192.168.1.245      

需要背景運作時可以添加nohup thiscommandline >/path/to/logfile 2>&1 &

注意:在consul json配置檔案中,每個consul agent的service id都不能重複,name是強制要求的,必須要有,如果id省略,則跟name相同,其他的都是可選的,可有可無。但為了能夠使用某條服務資訊,就必須要有IP和port,當然port可以在應用中指定。check最好要有,否則當出現問題時不能從consul中取消注冊。

注意:上述指令行中使用的是與預設網關同網段IP(公網IP位址),要求此位址與consul叢集位址之間能互相通路。在啟動consul agent之前可以下面兩行指令中的一行确定是否滿足此條件:

consul info -rpc-addr=192.168.1.245:8400   
consul members -rpc-addr=192.168.1.245:8400      

在consul agent啟動後,此時Redis的資訊就會在consul中展示出來,包括UI、DNS Interface和HTTP API中都能查詢到。使用Redis的應用應該将DNS指向consul叢集的DNS位址,這樣才能查詢到Redis服務對應的IP。

通過consul HTTP API中提供的“curl http://192.168.1.245:8500/v1/catalog/service/redis”方法隻能列舉出目前service:redis中有哪些節點,但無法區分這些節點中哪些是正常工作的節點,哪些是有問題的節點,但DNS Interface方法“dig @192.168.1.245 -p 53 redis.service.dc1.consul. ANY”可以準确的将可用的節點的IP找到,如下圖所示。

利用redis-sentinel+consul實作redis高可用
利用redis-sentinel+consul實作redis高可用

例如用redis-cli測試一下Redis叢集。

利用redis-sentinel+consul實作redis高可用

文中隻是利用consul的DNS Interface擷取到了Redis叢集的master的IP,并沒有擷取到port,盡管可以通過“dig @192.168.1.245 -p 53 redis.service.consul SRV”可以擷取到port,但對于上層應用來說并不是很好做,畢竟大部分應用的域名解析是不會查詢SRV記錄的。本文的consul是Consul v0.6.0,目前有更新的版本0.6.3可以使用,https://www.consul.io/downloads.html ,consul可能還有其他比較好用的方法更好的擷取服務的IP和Port,以後使用的過程中也會再補充。更多關于consul的資訊可以參考consul的官方網站:https://www.consul.io/。

繼續閱讀