Redis哨兵模式配置及go客戶端自動切換主節點

哨兵模式介紹

哨兵(Sentinel)模式是Redis高可用的其中一種實現模式,其包含一個主節點(master)、多個從節點(replication,也稱slave),以及多個哨兵節點(sentinel)。每個sentinel節點會對數據節點和其餘sentinel節點進行監控,當它發現節點不可達時,會對節點做下線標識。如果被標識的是“主節點”,它還會和其他的sentinel節點進行“協商”,當大多數sentinel節點都認爲主節點不可達時,它們會選舉一個sentinel節點來完成自動故障轉移的工作,同時會將這個變化實時通知給Redis應用方。整個過程是自動的,不需要人工干預,解決了Redis的高可用問題。

哨兵模式服務端搭建(單機版)

在此採用單機版進行介紹,分佈式版需要將IP地址改爲對應的服務器IP即可。

節點說明 IP地址 redis端口號 sentinel端口號
master 127.0.0.1 6379 26379
replica 127.0.0.1 6380 26380
replica 127.0.0.1 6381 26381

1. redis配置及啓動

在這裏插入圖片描述
首先配置三個redis數據節點爲主從模式,複製redis解壓文件中的redis.conf三份,並重命名爲redis_6379.conf、redis_6380.conf、redis_6381.conf。

修改主節點配置文件 redis_6379.conf:

port 6379
daemonize yes
pidfile "/var/run/redis_6379.pid"
logfile "6379.log"
dir "/usr/bin/sentinel/redis6379/"

修改從節點1的配置文件redis_6380.conf:

port 6380
daemonize yes
pidfile "/var/run/redis_6380.pid"
logfile "6380.log"
dir "/usr/bin/sentinel/redis6380/"
replicaof 127.0.0.1 6379

類似的,修改從節點2的配置文件redis_6381.conf:

port 6381
daemonize yes
pidfile "/var/run/redis_6381.pid"
logfile "6381.log"
dir "/usr/bin/sentinel/redis6381/"
replicaof 127.0.0.1 6379

接下來在命令行啓動主節點和兩個從節點:

redis-server  redis_6379.conf
redis-server  redis_6380.conf
redis-server  redis_6381.conf

連接端口號爲6379的redis服務器,執行info replication可以查看主從節點信息,端口號6379的爲master,端口號爲6380、6381的爲slave。

2. sentinel配置及啓動

接下來配置sentinel,複製redis解壓文件中的sentinel.conf三份,並重命名爲redis_sentinel_26379.conf、redis_sentinel_26380.conf、redis_sentinel_26381.conf。
修改配置文件redis_sentinel_26379.conf:

port 26379
daemonize yes
pidfile "/var/run/redis_sentinel_26379.pid"
logfile "26379.log"
dir "/usr/bin/sentinel/redis6379/"
sentinel monitor mymaster 127.0.0.1 6379 2 
# mymaster是主節點的別名,監控的主節點是127.0.0.1:6379,
# 2代表判斷主節點失敗至少需要2個sentinel節點同意

類似的,修改配置文件redis_sentinel_26380.conf:

port 26380
daemonize yes
pidfile "/var/run/redis_sentinel_26380.pid"
logfile "26380.log"
dir "/usr/bin/sentinel/redis6380/"
sentinel monitor mymaster 127.0.0.1 6379 2 

類似的,修改配置文件redis_sentinel_26381.conf:

port 26381
daemonize yes
pidfile "/var/run/redis_sentinel_26381.pid"
logfile "26381.log"
dir "/usr/bin/sentinel/redis6381/"
sentinel monitor mymaster 127.0.0.1 6379 2

在命令行啓動哨兵節點:

redis-sentinel  redis_sentinel_26379.conf
redis-sentinel  redis_sentinel_26380.conf
redis-sentinel  redis_sentinel_26381.conf

連接端口號爲26379的哨兵節點,執行info sentinel可以查看哨兵信息。
在這裏插入圖片描述

3. 故障轉移示例

執行 ps aux | grep redis 可以看到有單機版本有3個redis數據節點以及3個sentinel節點。
在這裏插入圖片描述
將此時的端口號爲6379的進程殺死可以查看故障轉移,執行 info sentinel 看到主節點已切換至端口號爲6380的節點。此時會將主從節點信息的改動自動寫入redis的配置文件以及sentinel配置文件。
在這裏插入圖片描述
至此介紹完了服務端的配置、啓動、故障轉移演示,實現原理後續繼續發掘。

go客戶端自動切換主節點

哨兵模式的客戶端如果直接連接固定redis的IP地址和端口號,就不會自動切換主節點,因此,需要連接sentinel節點,由sentinel節點獲取主節點的信息,實現服務端故障轉移後,客戶端能夠自動連接到新的主節點上。
以go語言的redis client使用的redigo包爲例,連接哨兵模式服務需要引入sentinel包,
sentinel包地址:https://github.com/FZambia/sentinel
其接口文檔地址:https://godoc.org/github.com/FZambia/sentinel#Sentinel.Discover

客戶端自動切換主節點的Demo如下,newSentinelPool函數實現了自動連接主節點,需要注意的是當主節點宕機時有主從節點切換的過程,此時會有幾秒的連接失敗,但服務端切換完成後,客戶端可以自動連接。

package main

import (
    "errors"
    "fmt"
    "time"
    "github.com/gomodule/redigo/redis"
    "github.com/sentinel-master"
)

// Sentinel provides a way to add high availability (HA) to Redis Pool using
// preconfigured addresses of Sentinel servers and name of master which Sentinels
// monitor. It works with Redis >= 2.8.12 (mostly because of ROLE command that
// was introduced in that version, it's possible though to support old versions
// using INFO command).
//
// Example of the simplest usage to contact master "mymaster":

func newSentinelPool() *redis.Pool {
    sntnl := &sentinel.Sentinel{
        Addrs:      []string{":26379", ":26380", ":26381"},
        MasterName: "mymaster",
        Dial: func(addr string) (redis.Conn, error) {
            timeout := 500 * time.Millisecond
            c, err := redis.DialTimeout("tcp", addr, timeout, timeout, timeout)
            if err != nil {
                fmt.Println("newSentinelPool sntnl.Dial() error [", err, "]")
                return nil, err
            }
            return c, nil
        },
    }
    return &redis.Pool{
        MaxIdle:     3,
        MaxActive:   64,
        Wait:        true,
        IdleTimeout: 240 * time.Second,
        Dial: func() (redis.Conn, error) {
            masterAddr, err := sntnl.MasterAddr()
            if err != nil {
                fmt.Println("newSentinelPool Dial() masterAddr error [", err, "]")
                return nil, err 
            }
            fmt.Println("MasterAddr [", masterAddr, "]")
            c, err := redis.Dial("tcp", masterAddr)
            if err != nil {
                fmt.Println("connect master addr error [", err, "]")
                return nil, err 
            }
            return c, nil
        },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            if !sentinel.TestRole(c, "master") {
                return errors.New("Role check failed")
            } else {
                return nil
            }
        },
    }
}

func main() {
    pool := newSentinelPool()
    conn := pool.Get()
    defer conn.Close()

    err := pool.TestOnBorrow(conn, time.Now())
    if err != nil {
        return
    }

    _,err = conn.Do("SET", "k", "value")
    if err != nil {
        fmt.Println("set error")
        return
    }
    v, err := conn.Do("GET", "k")
    if err != nil {
        fmt.Println("get error")
        return
    }
    fmt.Println("v:",v)
}

參考文獻:
Redis高可用之哨兵模式Sentinel配置與啓動(五)
redis 哨兵(sentinel)安裝部署

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章