1. 程式人生 > >redis高可用叢集介紹

redis高可用叢集介紹

一、redis的高可用管理工具sentinel介紹

sentinel是一個管理redis例項的工具,它可以實現對redis的監控、通知、自動故障轉移。sentinel不斷的檢測redis例項是否可以正常工作,通過API向其他程式報告redis的狀態,

如果redis master不能工作,則會自動啟動故障轉移程序,將其中的一個slave提升(通過選舉)為master,其他的slave重新設定新的master伺服器。而故障的master再次啟動後會被sentinel自動降級為slave伺服器加入到叢集中。

redis主從的特點:

1、redis使用非同步複製,從伺服器會以每秒一次的頻率向主伺服器報告複製流的處理進度

2、一個主伺服器可以有多個從伺服器,從伺服器也可以有自己的從伺服器(級聯複製)

3、複製功能不會阻塞主伺服器,即使一個或多個從伺服器正在進行初次同步,主伺服器也可以繼續處理命令請求

4、複製功能可以用於資料冗餘,也可以通過讓多個從伺服器處理只讀命令請求來提升擴充套件性

5、Redis從節點預設為只讀,無須手動配置

redis的主從叢集可以實現分擔壓力的效果,但是無法做到高可用,如果master宕掉,服務就不可用了,所以使用redis的sentinel可以實現HA的功能:

sentinel作用如下:

1、監控:sentinel會不斷的檢查你的主伺服器和從伺服器是否執行正常

2、當被監控的某個redis伺服器出現問題時,sentinel可以通過API向管理員或者其他應用程式傳送通知

3、自動故障轉移:當一個主伺服器不能正常工作時,sentinel會開始一次自動故障轉移操作,他會將其中一個從伺服器升級為新的主伺服器,並將其他從伺服器改為複製新的主伺服器;當客戶端試圖連線失效的主伺服器時,叢集也會向客戶端返回新主伺服器的地址,使得叢集可以使用新主伺服器代替失效伺服器。

二、部署說明

redis-server 192.168.248.131

redis-slave 192.168.248.132

redis-slave 192.168.248.133

先進行的主從的配置

安裝redis

redis可以根據自己的需求去redist官網去下載https://redis.io/download

tar –zxvf redis-3.0.7.tar.gz

cd redis-3.0.7

make

mkdir –pv /data/redis

之後將redis的命令檔案拷貝到/usr/local/sbin下面去

cd /usr/local/src/redis-3.0.7/src

cp redis-benchmark  redis-check-aof redis-check-dump redis-cliredis-server  redis-sentinel  /usr/local/sbin

redis-server的redis.conf配置檔案

cat > /etc/redis/redis.conf <<EOF

maxmemory 256mb

daemonize yes

pidfile"/data/redis/redis-6379.pid"

port 6379

bind 0.0.0.0

tcp-backlog 511

timeout 0

tcp-keepalive 0

loglevel notice

logfile "/data/redis/redis.log"

databases 16

save 900 1

save 300 10

save 60 10000

stop-writes-on-bgsave-error yes

rdbcompression yes

rdbchecksum yes

dbfilename "dumpredis-6379.rdb"

dir "/data/redis"

slave-serve-stale-data yes

slave-read-only yes

repl-diskless-sync no

repl-diskless-sync-delay 5

# repl-ping-slave-period 10

# repl-timeout 60

repl-disable-tcp-nodelay no

# repl-backlog-size 1mb

# repl-backlog-ttl 3600

slave-priority 100

# min-slaves-to-write 3

# min-slaves-max-lag 10

appendonly no

appendfilename "appendonly.aof"

appendfsync everysec

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

aof-load-truncated yes

lua-time-limit 5000

slowlog-log-slower-than 10000

slowlog-max-len 128

latency-monitor-threshold 0

notify-keyspace-events ""

hash-max-ziplist-entries 512

hash-max-ziplist-value 64

list-max-ziplist-entries 512

list-max-ziplist-value 64

set-max-intset-entries 512

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

activerehashing yes

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb60

client-output-buffer-limit pubsub 32mb 8mb60

hz 10

aof-rewrite-incremental-fsync yes

EOF

slave的redis.conf

cat >/etc/redis/redis.conf <<EOF

slaveof 192.168.248.131  6379

maxmemory 256mb

daemonize yes

pidfile"/data/redis/redis-6379.pid"

port 6379

bind 0.0.0.0

tcp-backlog 511

timeout 0

tcp-keepalive 0

loglevel notice

logfile "/data/redis/redis.log"

databases 16

save 900 1

save 300 10

save 60 10000

stop-writes-on-bgsave-error yes

rdbcompression yes

rdbchecksum yes

dbfilename "dumpredis-6379.rdb"

dir "/data/redis"

slave-serve-stale-data yes

slave-read-only yes

repl-diskless-sync no

repl-diskless-sync-delay 5

# repl-ping-slave-period 10

# repl-timeout 60

repl-disable-tcp-nodelay no

# repl-backlog-size 1mb

# repl-backlog-ttl 3600

slave-priority 100

# min-slaves-to-write 3

# min-slaves-max-lag 10

appendonly no

appendfilename "appendonly.aof"

appendfsync everysec

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

aof-load-truncated yes

lua-time-limit 5000

slowlog-log-slower-than 10000

slowlog-max-len 128

latency-monitor-threshold 0

notify-keyspace-events ""

hash-max-ziplist-entries 512

hash-max-ziplist-value 64

list-max-ziplist-entries 512

list-max-ziplist-value 64

set-max-intset-entries 512

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

activerehashing yes

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb60

client-output-buffer-limit pubsub 32mb 8mb60

hz 10

aof-rewrite-incremental-fsync yes

EOF

在slave的配置檔案中需要指明的是slaveof  masterip  port

之後就組成了redis的叢集,但是這樣同樣會存在問題,如果我們的master出現問題之後,slave就會找不到master同步資料,另外client端也會發生找不到master從而不能寫的請求被拒絕的情況。

所以下面為redis新增sentinel新增哨兵,哨兵的作用就是當redis的master發生改變的時候,會在其餘的slave中重新選舉一個新的master,如果原來的master的redis服務恢復之後,他不會重新的搶回master的角色,而是會被降級為slave。

redis-sentinel.conf

cat>/etc/redis/sentinel.conf <<EOF

dir /tmp     

sentinel monitor mymaster 192.168.248.131 6379 2     

sentinel down-after-milliseconds mymaster 30000     

sentinel parallel-syncs mymaster 1     

sentinel failover-timeout mymaster 180000 

EOF

三個節點的sentinel.conf配置檔案是一樣的。

之後啟動redis-server和redis-sentinel服務

redis-server  /etc/redis/redis.conf &

redis-sentinel  /etc/redis/sentinel.conf &

表示兩個服務全部從在後臺啟動。

redis配置檔案解析

maxmemory 256mb

redis可以使用的最大的記憶體大小,redis訪問速度非常快的原因是他把資料全部的載入到記憶體中去,然後在持久化到磁碟中。但是如果記憶體滿了的話,那麼redis就會清除一些key,這些key是設定了超時時間的key,雖然超時時間還沒有到,但是仍然有可能被刪除。如果刪除了這些key之後,仍然沒有辦法多餘空間的話,那麼redis就會返回錯誤給連線的客戶端。

daemonize yes

是不是以守護程序的方式執行,如果此處是yes的話,在啟動redis的時候,我們就不需要使用&,讓服務去後臺執行。

pidfile"/data/redis/redis-6379.pid"

redis的pid檔案所在的位置

port 6379

redis監聽的埠

bind 0.0.0.0

監聽的地址,如果為了保證安全的話在此處可以進行限制為自己需要的內網地址

tcp-backlog 511

為了避免redis客戶端連線的慢,需要調節的redis客戶端的最大的數量,這個值會預設的設定為/proc/sys/net/core/somaxconn下面的數量,所以如果想要修改的話,記住兩處都要修改

timeout 0

客戶端連線的超時時間,如果是0的話表示的話,不超時,不管這個連線

tcp-keepalive 0

是不是啟用長連線,0表示不啟用

loglevel notice

日誌的級別,日誌級別有四種debug  notice  info warning

logfile "/data/redis/redis.log"

日誌檔案的位置

databases 16

啟用的資料庫

save 900 1

save 300 10

save 60 10000

在相應的時間內有多少個key發生了變化,就將資料持久化到磁碟中去

stop-writes-on-bgsave-error yes

當後臺儲存失敗,持久化失敗的是,是不是停止進行寫操作

rdbcompression yes

資料是否壓縮

rdbchecksum yes

是否對資料進行校驗

dbfilename "dumpredis-6379.rdb"

持久化資料的名稱

dir "/data/redis"

資料的儲存路徑

slave-serve-stale-data yes

當slave和master數去聯絡或者是在進行資料複製的時候,是不是仍然提供給客戶端服務

slave-read-only yes

slave是不是隻是隻讀的

repl-diskless-sync no

複製集同步策略:磁碟或者socket

新slave連線或者老slave重新連線時候不能只接收不同,得做一個全同步。需要一個新的RDB檔案dump出來,然後從master傳到slave。可以有兩種情況:

1)基於硬碟(disk-backed):master建立一個新程序dump RDB,完事兒之後由父程序(即主程序)增量傳給slaves。

2)基於socket(diskless):master建立一個新程序直接dumpRDB到slave的socket,不經過主程序,不經過硬碟。

基於硬碟的話,RDB檔案建立後,一旦建立完畢,可以同時服務更多的slave。基於socket的話,新slave來了後,得排隊(如果超出了repl-diskless-sync-delay還沒來),完事兒一個再進行下一個。

當用diskless的時候,master等待一個repl-diskless-sync-delay的秒數,如果沒slave來的話,就直接傳,後來的得排隊等了。否則就可以一起傳。

disk較慢,並且網路較快的時候,可以用diskless。(預設用disk-based)

repl-diskless-sync-delay 5

同步延遲時間

# repl-ping-slave-period 10

# repl-timeout 60

repl-disable-tcp-nodelay no

# repl-backlog-size 1mb

# repl-backlog-ttl 3600

slave-priority 100

slave的優先順序(和競選master有關係)

# min-slaves-to-write 3

# min-slaves-max-lag 10

appendonly no

redis非同步的dump資料到disk,如果是斷電了那麼就會有比部分資料丟失,aof則提供了更好的方式,保證瞭如果發生錯誤那麼丟失的僅僅是上一秒的資料或者是上一次寫操作的資料。當aof檔案過大的話就會重新再生成另外的一個aof檔案

appendfilename "appendonly.aof"

aof檔案的名稱

appendfsync everysec

檔案的同步的方式,有單重  no always  everysec ,第一種的話由作業系統自己決定,這樣子會跟快,第二種的話是每次寫操作更新速度慢但是最安全,第三種是每秒進行一次 兩種的折中辦法

no-appendfsync-on-rewrite no

當fsync為always或者everysec,當一個bgsave或者AOF rewrite執行緒正在耗費大量I/0,redis可能會在fsync上阻塞很久。發生之後就無法fix,即使是另一個執行緒跑fsync,也會阻塞我們同步的write方法。

如下方法可以解決這個問題:當bgsave()或bgrewriteaof()在跑,主程序的fsync()就無法呼叫。也就是當子程序在save,那段時光相當於redis是appendaof no的。也就是有可能會丟失最多30s的log。

所以如果你有lag問題,把下邊改成yes,否則就用no。yes意思是暫停aof,拒絕主程序的這次fsync。no是redis是排隊的,不會被prevent了,但主程序是阻塞的。

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

自動重寫AOF

當AOF檔案大小到一定比例,就自動隱式呼叫BGREWRITEAOF

過程:redis記住最後一次rewrite時aof檔案大小(重啟後沒rewrite的話,就是啟動時AOF檔案的大小),如果現在AOF大小和上次的比例達到特定值就重寫。也要指定最小AOF大小,防止到2倍:1M的時候也重寫。

aof-load-truncated yes

aof檔案在尾部是不完整的,那redis重啟的時候load進記憶體的時候就會出現問題,如果aof-load-truncated 為yes的時候就會盡量多的將資料load進記憶體中,如果是no的話就必須手動的修復資料,利用redis-check-aof就行資料的修復

lua-time-limit 5000

lua時間時間為毫秒

slowlog-log-slower-than 10000

慢日誌的時間為微秒

slowlog-max-len 128

latency-monitor-threshold 0

notify-keyspace-events ""

hash-max-ziplist-entries 512

hash-max-ziplist-value 64

list-max-ziplist-entries 512

list-max-ziplist-value 64

set-max-intset-entries 512

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

activerehashing yes

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb60

client-output-buffer-limit pubsub 32mb 8mb60

hz 10

aof-rewrite-incremental-fsync yes

當child程序在rewrite AOF檔案,如果這個選項是yes,那麼這個file每32MB會寫fsync()。這個是保證增量寫硬碟而防止寫硬碟時I/O突增

當redis-server啟動之後可以使用redis-cli info來檢視redis的資訊

redis-sentinel介紹

redis-sentinel實現的是對redis服務進行監控,是想一下加入我們的redis叢集中有三臺機器,mater角色實現的是write以及read的功能。並且slave一般都是read-only的。當master出現意外的情況下,這時候客戶端的write請求就會被拒絕掉,這個顯然是不合理的。所以需要有新的slave重新升級為master。

master的sentinel.conf檔案內容

cat >/etc/redis/sentinel.conf<<EOF

port 26379    

dir /tmp    

sentinel monitor mymaster 192.168.248.131  6379 2    

sentinel down-after-milliseconds mymaster30000    

sentinel parallel-syncs mymaster 1    

sentinel failover-timeout mymaster 180000

EOF

redis-sentinel配置詳解

port 26379     監聽的埠

dir /tmp     存放的目錄

sentinel monitor mymaster 192.168.1.2416379 2   

監聽的master的名稱(隨意起名字)地址埠號 後面的是2表示的是在叢集中至少有兩個slave同時判斷master失效,master才算失效(object_down)

sentinel down-after-milliseconds mymaster30000   

經過多長時間之後如果還不能和master聯絡上之後,就認定master已經down掉,預設的時間是30s

sentinel parallel-syncs mymaster 1    

指定在故障轉移的過程中,多少個slave和新的master進行資料的同步如果在,這個數值越小,所需的同步時間越長(一共有n個slave,每次只進行一個的同步當時需要的時間會比較長)當客戶端執行slaveof並進行同步時,會中斷和客戶端的請求,所以如果後面的數字越大,那麼會給客戶端的訪問帶來一定的問題

sentinel failover-timeout mymaster180000 

故障切換的過程中slave和新的master同步的超時時間,如果在超時時間內沒有完成,則認為失敗。預設時間為3minutes

note:在進行redis的故障轉移過程中,redis配置檔案會被rewrite為新的slaveof,也就是redis的配置檔案會被重寫

在此redis 主從加上sentinel就已經搭建好了。現在還存在一個問題,如果程式中寫死了寫快取的地址,就是192.168.248.254,但是當masterdown掉之後新的master的地址可能是發生變化的,所以此時我們需要keepalived來實現地址的漂移。

redis-server + redis-sentinel + keepalived

安裝之前先解決掉依賴

yum –y install  openssl-devel

tar –zxvf keepalived-1.2.20.tar.gz

cd keepalived-1.2.20

./configure –prefix=/usr/local/keepalived

make

make install

mkdir /etc/keepalived

cd /usr/local/keepalived

cp etc/keepalived/keepalived.conf/etc/keepalived

cp rc.d/init.d/keepalived /etc/init.d

cp sysconfig/keepalived  /etc/sysconfig/

cp sbin/keepalived /usr/sbin/

預設keepalived的日誌會存放到/var/log/message中,在此處可以進行自定義

修改/etc/sysconfig/keepalived

KEEPALIVED_OPTIONS="-D -d -S 0"

修改/etc/rsyslog.conf  追加下面的配置

local0.*   /var/log/keepalived.log  

cat>/etc/keepalived/keepalived.conf<< EOF                                       

! Configuration File for keepalived

global_defs {

  notification_email {

    [email protected]

    [email protected]

    [email protected]

   }

  notification_email_from [email protected]

  smtp_server  127.0.0.1

  smtp_connect_timeout 30

  router_id LVS_DEVEL

  vrrp_skip_check_adv_addr

  vrrp_strict chk_redis {

      script "redis-cli info | grep role:master &>/dev/null2>&1"

      weight -10

      interval 1

      timeout 2

      rise 1

      fall 2

}

}

vrrp_instance VI_1 {

   state  BACKUP

   interface eth1

   virtual_router_id 51

   priority 100

   advert_int 1

   authentication {

       auth_type PASS

       auth_pass 1111

    }

   virtual_ipaddress {

       192.168.248.254

    }

   tack_script {

       chk_redis

}

}

EOF

其餘的slave節點的配置是相同的,但是需要注意的是通訊的介面是不是都是eth0。

至此,我們就配置好了,當keepalived或者是redis出現問題的時候,就會自動的進行IP地址的漂移。

二、redis+keepalived+twemproxy實現redis高可用

twemproxy是Twitter推出的redis叢集的解決方案

twemproxy特點:

1、        對外暴露一個訪問節點

2、        請求分片

3、        分片要合理(分片均勻,相同的請求分配到同樣的redis節點)

對於和sentinel不同的是,sentinel組成是redis的主從叢集,也就是說當master節點出現問題之後,會有一個新的原來的slave成為master節點,然後slave在向master同步資料。所有的主從節點的資料是一致的。但是twemproxy實現的是一個代理的作用,只對外暴露一個節點地址,client端通過這個地址來進行訪問,代理節點將client的請求分發到後面的redis節點。如果一個節點出現問題,這個節點上面的資料會受到影響。

下面簡單的介紹實現方法

首先下載twemproxy

git clone https://github.com/twitter/twemproxy.git

之後執行autoreconf,這時候有可能會包autoconf的版本比較低,需要更高版本的autoconf,這時候需要去下載更高版本的autoconf,http://ftp.gnu.org/gnu/autoconf/可以到這個站點去下載,安裝之後

CFLAGS="-ggdb3 -O0" autoreconf -fvi && ./configure --prefix=/usr/local/twemproxy --enable-debug=log

進行安裝,如果報錯的話解決掉相應的依賴即可。

make && makeinstall

安裝好之後

cd /usr/local/twemproxy

mkdir conf

此時編輯配置檔案,不過同樣可以從原來下載的原始碼包將配置檔案的樣例複製過來,檔案為原來twemproxy的conf目錄下,名字叫做nutcracker.yml,複製到安裝目錄的conf目錄下,過來進行如下的編輯

redis:

  listen: 0.0.0.0:6379

  hash: fnv1a_64

  distribution: ketama

  auto_eject_hosts: true

  redis: true

  timeout: 400

  server_retry_timeout: 2000

  server_failure_limit: 1

  servers:

   - 192.168.248.135:6380:1

   - 192.168.248.136:6380:1

建立好之後就可以啟動了

/usr/local/twemproxy/sbin/nutcracker-d -c /usr/local/twemproxy/nutcracker.yml

在此處,我們想叢集中添加了兩個redis,並且監聽的埠號為6380,權重全部為1,後面權重代表的是前端對後面兩個分配任務的額度。

為了實現高可用下面搭建keepalived

! Configuration File for keepalived

global_defs {

  notification_email {

    #[email protected]

  }

  #notification_email_from [email protected]

 # smtp_server 192.168.200.1

 # smtp_connect_timeout 30

  router_id LVS_DEVEL

}

vrrp_script chk_nutcracker {

       script "killall -0 nutcracker"

       interval 2

       weight -4

}

vrrp_instance VI_85 {

   state BACKUP

   interface eth1

   virtual_router_id 85

   priority 100

   virtual_ro

   advert_int 1

   authentication {

       auth_type PASS

       auth_pass 8888

   }

   virtual_ipaddress {

       192.168.248.254

   }

   track_script {

       chk_haproxy

   }

}

vrrp_instance VI_86 {

   state MASTER

   interface eth1

   virtual_router_id 86

   priority 101

   virtual_ro

   advert_int 1

   authentication {

       auth_type PASS

       auth_pass 5555

   }

   virtual_ipaddress {

       192.168.248.253

   }

   track_script {

       chk_nutcracker

   }

}

兩臺主機分別互相做主從,另外一臺主機做相對應的配置就行。當然如果我們想對keepalived的log進行設定的話,只需要設定/etc/sysconfig/keepalived和/etc/rsyslog.conf就可以了。設定好了之後我們就可以使用VIP來進行redis的處理了。