1. 程式人生 > >Redis主從復制與sentinel模式

Redis主從復制與sentinel模式

redis

第1章 Redis主從復制:

基於RDB持久化的功能來實現主從復制的功能

1.1 redis復制特性:

1. 使用異步復制

2. 一個主服務器可以有多個從服務器

3. 從服務器也可以有自己的從服務器

4. 復制功能不會阻塞主服務器

5. 可以通過復制功能來讓主服務器免於執行持久化操作,由從服務器執行持久化操作即可

技術分享圖片

1.1 主從復制原理:

1. 從服務器向主服務器發送sync命令

2. 街道sync命令的主服務器會調用bgsave命令,創建一個RDB文件,並使用緩沖區記錄接下來執行的所有命令

3. 當主服務器執行完bgsave命令時,它會向從服務器發送

RDB文件,而從服務器則會接受並載入這個文件

4. 主服務器將緩沖區存儲的所有寫命令發送給從服務器

1.2 復制中的syncpsync:

Redis2.8版本之後,redis使用psync代替sync命令,psync比起sync最大的改進在於實現了部分重同步的特性,即在服務器斷線重新連接的時候,只要條件允許,psync可以讓主服務器指向從服務器同步斷線期間確實的數據,而不用重新向從服務器同步整個數據庫

1.3 復制一致性的問題:

技術分享圖片

在讀寫分離環境下,客戶端向主服務器發送寫命令 SET n 10086,主服務器在執行這個寫命令之後,向客戶端返回回復,並將這個寫命令傳播給從服務器。

接到回復的客戶端繼續向從服務器發送讀命令

GET n ,並且因為網絡狀態的原因,客戶端的 GET命令比主服務器傳播的 SET 命令更快到達了從服務器。

因為從服務器鍵 n 的值還未被更新,所以客戶端在從服務器讀取到的將是一個錯誤(過期)的 n值。

1.1.1 復制安全性的提升:

主服務器只在有至少 N 個從服務器的情況下,才執行寫操作從 Redis 2.8 開始, 為了保證數據的安全性, 可以通過配置, 讓主服務器只在有至少 N 個當前已連接從服務器的情況下, 才執行寫命令。

不過, 因為 Redis 使用異步復制, 所以主服務器發送的寫數據並不一定會被從服務器接收到, 因此, 數據丟失的可能性仍然是存在的。

1.1.2 通過以下兩個參數保證數據的安全:

min-slaves-to-write <number of slaves>

min-slaves-max-lag <number of seconds>

第2章 主從復制搭建過程:

2.1 準備實例的目錄:

[root@gitlab data]# ll

total 0

drwxr-xr-x 2 root root 6 Apr 17 00:05 6380

drwxr-xr-x 2 root root 6 Apr 17 00:05 6381

drwxr-xr-x 2 root root 6 Apr 17 00:05 6382

2.2 配置文件內容:

除端口不同,其余都相同

port 6380

daemonize yes

pidfile /data/6380/redis.pid

loglevel notice

logfile "/data/6380/redis.log"

dbfilename dump.rdb

dir /data/6380

protected-mode no

2.3 啟動實例:

for i in {0..2};do redis-server /data/638${i}/redis.conf ; done

2.4 主從環境說明:

主庫為6380,從庫為6381,6382

2.4.1 開啟主從:

[root@gitlab ~]# redis-cli -p 6381

127.0.0.1:6381> SLAVEOF 127.0.0.1 6380

OK

[root@gitlab ~]# redis-cli -p 6382

127.0.0.1:6382> SLAVEOF 127.0.0.1 6380

OK

2.4.2 主庫查看狀態:

127.0.0.1:6380> info replication

# Replication

role:master

connected_slaves:2

slave0:ip=127.0.0.1,port=6381,state=online,offset=85,lag=0

slave1:ip=127.0.0.1,port=6382,state=online,offset=85,lag=0

master_repl_offset:85

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:2

repl_backlog_histlen:84

2.4.3 從庫狀態:

127.0.0.1:6381> info replication

# Replication

role:slave

master_host:127.0.0.1

master_port:6380

master_link_status:up

master_last_io_seconds_ago:4

master_sync_in_progress:0

slave_repl_offset:141

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

127.0.0.1:6382> info replication

# Replication

role:slave

master_host:127.0.0.1

master_port:6380

master_link_status:up

master_last_io_seconds_ago:10

master_sync_in_progress:0

slave_repl_offset:169

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

2.5 主從復制管理:

宕掉主庫:

127.0.0.1:6380> shutdown

主從切換:

slaveof no one

第3章 Redis哨兵模式:

技術分享圖片

1.1 sentinel的功能:

1. 監控,sentinel會不斷的檢查你的主服務器和從服務器是否運行正常

2. 提醒.當被監控的某個redis服務器出現問題時,sentinel可以通過API向管理員或者其他應用程序發送通知

3. 自動故障遷移

1.2 服務器連接:

1.2.1 sentinel通過用戶配置的配置文件來發現主服務器

技術分享圖片

sentinel會與被監視的主服務器創建兩個網絡連接:

1. 命令連接用於向主服務器發送命令

2. 訂閱連接用於定於而制定的頻道,從而發現

1.1.1 發現並連接從服務器:與從服務器類似

技術分享圖片

1.1.1 發現其他sentinel:

sentinel會通過命令連接想被監視的主從服務器發送hello信息,該消息包含sentinelIP,端口號,ID等內容,以此來向其他sentinelU宣告自己的存在,於此同時sentinel會通過訂閱連接接受其他sentinelhello信息,以此來發現監視同一個主服務器的其他sentinel

技術分享圖片

1.1.1 多個sentinel之間的連接:

sentinel之間只會互相創建命令連接,用於進行通信,因為已經有主從服務器作為發送和接受hello信息的中介,所以sentinel之間不會創建訂閱連接

技術分享圖片

1.1 failover:

一次故障轉移的步驟:

1. 發現主服務器已經進入客觀下線狀態。

2. 基於Raft leader election 協議 進行投票選舉

3. 如果當選失敗,那麽在設定的故障遷移超時時間的兩倍之後,重新嘗試當選。 如果當選成功, 那麽執行以下步驟。

4. 選出一個從服務器,並將它升級為主服務器。

5. 向被選中的從服務器發送 SLAVEOF NO ONE 命令,讓它轉變為主服務器。

6. 通過發布與訂閱功能, 將更新後的配置傳播給所有其他 Sentinel ,其他 Sentinel 對它們自己的配置進行更新。

7. 向已下線主服務器的從服務器發送 SLAVEOF 命令,讓它們去復制新的主服務器。

8. 當所有從服務器都已經開始復制新的主服務器時, leader Sentinel 終止這次故障遷移操作。

1.2 部署sentinel:

創建目錄

[root@gitlab data]# mkdir 26380

[root@gitlab data]# cd 26380/

編寫配置文件

[root@gitlab 26380]# vim sentienl.conf

port 26380

dir "/data/26380"

sentinel monitor mymaster 127.0.0.1 6380 1

sentinel down-after-milliseconds mymaster 60000

啟動sentinel服務

redis-sentinel /data/26380/sentienl.conf &

配置文件說明:

# 指定監控master

sentinel monitor mymaster 127.0.0.1 6370 2

# {2表示多少個sentinel同意}

# 安全信息

sentinel auth-pass mymaster root

# 超過15000毫秒後認為主機宕機

sentinel down-after-milliseconds mymaster 15000

# 當主從切換多久後認為主從切換失敗

sentinel failover-timeout mymaster 900000

# 這兩個配置後面的數量主從機需要一樣,epochmaster的版本

sentinel leader-epoch mymaster 1

sentinel config-epoch mymaster 1

1.2.1 確認一主兩從環境良好,然後宕掉6380節點:

127.0.0.1:6380> shutdown

1.2.2 等待進行驗證:

127.0.0.1:6381> info replication

# Replication

role:master

connected_slaves:1

slave0:ip=127.0.0.1,port=6382,state=online,offset=1928,lag=1

master_repl_offset:1928

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:2

repl_backlog_histlen:1927

repl_backlog_histlen:0

127.0.0.1:6382> info replication

# Replication

role:slave

master_host:127.0.0.1

master_port:6381

master_link_status:up

master_last_io_seconds_ago:2

master_sync_in_progress:0

slave_repl_offset:2474

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

第2章 Redis

redis cluster部署:

安裝ruby支持

yum install ruby rubygems -y
gem sources -a http://mirrors.aliyun.com/rubygems/
gem sources --remove http://rubygems.org/
gem sources -l
gem install redis -v 3.3.3

準備集群所需節點:

創建程序目錄:

[root@gitlab data]# mkdir {7000..7005}

編寫配置文件:

port 7000

daemonize yes

pidfile /data/7000/redis.pid

loglevel notice

logfile "/data/7000/redis.log"

dbfilename dump.rdb

dir /data/7000

protected-mode no

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

啟動實例:

for i in {0..5};do redis-server /data/700${i}/redis.conf ; done

[root@gitlab data]# ps -ef |grep redis

root 19490 1 0 03:40 ? 00:00:00 redis-server *:7000 [cluster]

root 19492 1 0 03:40 ? 00:00:00 redis-server *:7001 [cluster]

root 19494 1 0 03:40 ? 00:00:00 redis-server *:7002 [cluster]

root 19496 1 0 03:40 ? 00:00:00 redis-server *:7003 [cluster]

root 19498 1 0 03:40 ? 00:00:00 redis-server *:7004 [cluster]

root 19500 1 0 03:40 ? 00:00:00 redis-server *:7005 [cluster]

加載節點並啟動集群:

[root@gitlab data]# redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \

> 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

>>> Creating cluster

>>> Performing hash slots allocation on 6 nodes...

Using 3 masters:

127.0.0.1:7000

127.0.0.1:7001

127.0.0.1:7002

Adding replica 127.0.0.1:7003 to 127.0.0.1:7000

Adding replica 127.0.0.1:7004 to 127.0.0.1:7001

Adding replica 127.0.0.1:7005 to 127.0.0.1:7002

M: 41679c9a4392f205496746f51fe2d167ce307c86 127.0.0.1:7000

slots:0-5460 (5461 slots) master

M: b22bd736f693bf1573c0e3aff0403516871865ce 127.0.0.1:7001

slots:5461-10922 (5462 slots) master

M: e61c8c741d9a1e69ca2d9a6f36e46177915393c0 127.0.0.1:7002

slots:10923-16383 (5461 slots) master

S: 1b87225b8c1c8a9ebfbb9ac37a8c5a963d569513 127.0.0.1:7003

replicates 41679c9a4392f205496746f51fe2d167ce307c86

S: 3b26d115ce27c4e72b60a5fd4985658dacfe44fb 127.0.0.1:7004

replicates b22bd736f693bf1573c0e3aff0403516871865ce

S: 4a3c744e24e980f84836d6cd708dcadf5e505158 127.0.0.1:7005

replicates e61c8c741d9a1e69ca2d9a6f36e46177915393c0

Can I set the above configuration? (type 'yes' to accept): yes

>>> Nodes configuration updated

>>> Assign a different config epoch to each node

>>> Sending CLUSTER MEET messages to join the cluster

Waiting for the cluster to join...

>>> Performing Cluster Check (using node 127.0.0.1:7000)

M: 41679c9a4392f205496746f51fe2d167ce307c86 127.0.0.1:7000

slots:0-5460 (5461 slots) master

1 additional replica(s)

S: 1b87225b8c1c8a9ebfbb9ac37a8c5a963d569513 127.0.0.1:7003

slots: (0 slots) slave

replicates 41679c9a4392f205496746f51fe2d167ce307c86

S: 4a3c744e24e980f84836d6cd708dcadf5e505158 127.0.0.1:7005

slots: (0 slots) slave

replicates e61c8c741d9a1e69ca2d9a6f36e46177915393c0

M: e61c8c741d9a1e69ca2d9a6f36e46177915393c0 127.0.0.1:7002

slots:10923-16383 (5461 slots) master

1 additional replica(s)

M: b22bd736f693bf1573c0e3aff0403516871865ce 127.0.0.1:7001

slots:5461-10922 (5462 slots) master

1 additional replica(s)

S: 3b26d115ce27c4e72b60a5fd4985658dacfe44fb 127.0.0.1:7004

slots: (0 slots) slave

replicates b22bd736f693bf1573c0e3aff0403516871865ce

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

[root@gitlab data]#

2.1 集群管理:

2.1.1 寫入數據:

[root@gitlab data]# redis-cli -c -p 7000

127.0.0.1:7000> set too bar

OK

127.0.0.1:7000> get too

"bar"

2.1.2 查看集群狀態:

[root@gitlab data]# redis-cli -p 7000 cluster nodes | grep master

41679c9a4392f205496746f51fe2d167ce307c86 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460

e61c8c741d9a1e69ca2d9a6f36e46177915393c0 127.0.0.1:7002 master - 0 1523908330620 3 connected 10923-16383

b22bd736f693bf1573c0e3aff0403516871865ce 127.0.0.1:7001 master - 0 1523908331131 2 connected 5461-10922

2.1.3 重新分片實戰:

[root@gitlab data]# redis-trib.rb reshard 127.0.0.1:7000

>>> Performing Cluster Check (using node 127.0.0.1:7000)

M: 41679c9a4392f205496746f51fe2d167ce307c86 127.0.0.1:7000

slots:0-5460 (5461 slots) master

1 additional replica(s)

S: 1b87225b8c1c8a9ebfbb9ac37a8c5a963d569513 127.0.0.1:7003

slots: (0 slots) slave

replicates 41679c9a4392f205496746f51fe2d167ce307c86

S: 4a3c744e24e980f84836d6cd708dcadf5e505158 127.0.0.1:7005

slots: (0 slots) slave

replicates e61c8c741d9a1e69ca2d9a6f36e46177915393c0

M: e61c8c741d9a1e69ca2d9a6f36e46177915393c0 127.0.0.1:7002

slots:10923-16383 (5461 slots) master

1 additional replica(s)

M: b22bd736f693bf1573c0e3aff0403516871865ce 127.0.0.1:7001

slots:5461-10922 (5462 slots) master

1 additional replica(s)

S: 3b26d115ce27c4e72b60a5fd4985658dacfe44fb 127.0.0.1:7004

slots: (0 slots) slave

replicates b22bd736f693bf1573c0e3aff0403516871865ce

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

How many slots do you want to move (from 1 to 16384)? 3 分三個槽位出去

What is the receiving node ID? e61c8c741d9a1e69ca2d9a6f36e46177915393c0 接受節點的ID

Please enter all the source node IDs.

Type 'all' to use all the nodes as source nodes for the hash slots.

Type 'done' once you entered all the source nodes IDs.

Source node #1:41679c9a4392f205496746f51fe2d167ce307c86 給出節點的ID

Source node #2:done 沒有了就添寫done

Ready to move 3 slots.

Source nodes:

M: 41679c9a4392f205496746f51fe2d167ce307c86 127.0.0.1:7000

slots:0-5460 (5461 slots) master

1 additional replica(s)

Destination node:

M: e61c8c741d9a1e69ca2d9a6f36e46177915393c0 127.0.0.1:7002

slots:10923-16383 (5461 slots) master

1 additional replica(s)

Resharding plan:

Moving slot 0 from 41679c9a4392f205496746f51fe2d167ce307c86

Moving slot 1 from 41679c9a4392f205496746f51fe2d167ce307c86

Moving slot 2 from 41679c9a4392f205496746f51fe2d167ce307c86

Do you want to proceed with the proposed reshard plan (yes/no)? yes

Moving slot 0 from 127.0.0.1:7000 to 127.0.0.1:7002:

Moving slot 1 from 127.0.0.1:7000 to 127.0.0.1:7002:

Moving slot 2 from 127.0.0.1:7000 to 127.0.0.1:7002:

2.1.4 刪除一個節點:

如果節點上還有slot的話,是無法進行刪除的

[root@gitlab data]# redis-trib.rb del-node 127.0.0.1:7000 '41679c9a4392f205496746f51fe2d167ce307c86'

>>> Removing node 41679c9a4392f205496746f51fe2d167ce307c86 from cluster 127.0.0.1:7000

>>> Sending CLUSTER FORGET messages to the cluster...

>>> SHUTDOWN the node.

節點在刪除後,服務自動關閉了,要添加回來的話需要重新啟動

[root@gitlab data]# ps -ef |grep redis

root 19492 1 0 03:40 ? 00:00:12 redis-server *:7001 [cluster]

root 19494 1 0 03:40 ? 00:00:20 redis-server *:7002 [cluster]

root 19496 1 0 03:40 ? 00:00:04 redis-server *:7003 [cluster]

root 19498 1 0 03:40 ? 00:00:04 redis-server *:7004 [cluster]

root 19500 1 0 03:40 ? 00:00:04 redis-server *:7005 [cluster]

root 19608 19171 0 04:33 pts/3 00:00:00 grep --color=auto redis

[root@gitlab data]# redis-server /data/7000/redis.conf

2.1.5 添加一個節點:

redis-trib.rb add-node 127.0.0.1:7000 127.0.0.1:7002

註意:添加節點時,要保證節點是全新的

2.1.6 添加一個從節點:

redis-trib.rb add-node --slave --master-id $[nodeid] 127.0.0.1:7008 127.0.0.1:7000

第3章 Redis API:

3.1 連接測試代碼

[root@clsn ~]# cat /application/nginx/html/check.php

<?php

//連接本地的 Redis 服務

$redis = new Redis();

$redis->connect('127.0.0.1', 6379);

echo "Connection to server sucessfully";

//查看服務是否運行

echo "Server is running: " . $redis->ping();

?>

3.2 字符串操作

<?php

//連接本地的 Redis 服務

$redis = new Redis();

$redis->connect('127.0.0.1', 6379);

echo "Connection to server sucessfully";

//設置 redis 字符串數據

$redis->set("tutorial-name", "Redis tutorial");

// 獲取存儲的數據並輸出

echo "Stored string in redis:: " . $redis-

>get("tutorial-name");

?>

3.3 Python連接redis

unzip redis-py-master.zip

python setup.py install

>>> r = redis.StrictRedis(host='localhost', port=6379, db=0, password='')

>>> r.set('foo', 'bar')

True

>>> r.get('foo')

'bar'

3.4 redis cluster的連接與操作

python連接的話要2.7以上版本才支持:

>>> from rediscluster import StrictRedisCluster

>>> startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]

>>> rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)

>>> rc.set("foo", "bar")

True

>>> print(rc.get("foo"))

bar

3.5 sentinel集群連接並操作:

>>> from redis.sentinel import Sentinel

>>> sentinel = Sentinel([('localhost', 26380)], socket_timeout=0.1)

>>> sentinel.discover_master('mymaster')

>>> sentinel.discover_slaves('mymaster')

>>> master = sentinel.master_for('mymaster', socket_timeout=0.1)

>>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1)

>>> master.set('oldboy', '123')

>>> slave.get('oldboy')

'bar'


Redis主從復制與sentinel模式