第1章 Redis哨兵模式:

1. 監控,sentinel會不斷的檢查你的主伺服器和從伺服器是否運作正常
2. 提醒.當被監控的某個redis伺服器出現問題時,sentinel可以通過API向管理者或者其他應用程式發送通知
3. 自動故障遷移
sentinel會與被監視的主伺服器建立兩個網絡連接配接:
1. 指令連接配接用于向主伺服器發送指令
2. 訂閱連接配接用于訂閱指定的頻道,進而發現
sentinel會通過指令連接配接想被監視的主從伺服器發送hello資訊,該消息包含sentinel的IP,端口号,ID等内容,以此來向其他sentinel 宣告自己的存在,于此同時sentinel會通過訂閱連接配接接受其他sentinel的hello資訊,以此來發現監視同一個主伺服器的其他sentinel
sentinel之間隻會互相建立指令連接配接,用于進行通信,因為已經有主從伺服器作為發送和接受hello資訊的中介,是以sentinel之間不會建立訂閱連接配接
一次故障轉移的步驟:
1. 發現主伺服器已經進入客觀下線狀态。
2. 基于Raft leader election 協定 , 進行投票選舉
3. 如果當選失敗,那麼在設定的故障遷移逾時時間的兩倍之後,重新嘗試當選。 如果當選成功, 那麼執行以下步驟。
4. 選出一個從伺服器,并将它更新為主伺服器。
5. 向被選中的從伺服器發送 SLAVEOF NO ONE 指令,讓它轉變為主伺服器。
6. 通過釋出與訂閱功能, 将更新後的配置傳播給所有其他 Sentinel ,其他 Sentinel 對它們自己的配置進行更新。
7. 向已下線主伺服器的從伺服器發送 SLAVEOF 指令,讓它們去複制新的主伺服器。
8. 當所有從伺服器都已經開始複制新的主伺服器時, leader 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
# 這兩個配置後面的數量主從機需要一樣,epoch為master的版本
sentinel leader-epoch mymaster 1
sentinel config-epoch mymaster 1
127.0.0.1:6380> shutdown
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
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_first_byte_offset:0
第2章 Redis cluster
Ø redis叢集是一個可以在多個redis節點之間進行資料共享的設施
Ø redis叢集不支援哪些需要同時處理多個鍵的redis指令,因為執行這些指令需要在多個redis節點之間移動資料,并且在高負載的情況下,這些指令将降低redis叢集的性能,并導緻不可預測的行為
Ø redis叢集通過分區來提供一定程度的可用性,即使叢集中有一部分節點失效或者無法進行通訊,叢集也可以繼續處理指令請求,将資料自動切分到多個節點的能力
Ø 當叢集中的一部分節點失效或者無法進行通訊時,仍然可以繼續處理指令請求的能力
redis叢集使用資料分片,而非一緻性hash來實作,一個redis叢集包含16384個哈希槽,資料庫中的每個鍵都屬于這16384哈希槽其中一個,叢集使用公式來計算鍵值屬于哪個槽
節點 A 負責處理 0 号至 5500 号哈希槽。
節點 B 負責處理 5501 号至 11000 号哈希槽。
節點 C 負責處理 11001 号至 16384 号哈希槽。
Ø 所有的redis節點彼此互聯ping-pong機制,内部使用二進制協定傳輸速度和帶寬
Ø 節點的fail是通過叢集中超過半數的master節點檢測失效時才失效
Ø 用戶端與redis節點直連,不需要中間proxy層,客戶頓不需要連接配接叢集中所有節點,連接配接叢集中任何一個可用節點即可
把所有的實體節點映射到哈希槽上,cluster負責維護
為了使得叢集在一部分加點下線或者無法與叢集中大多數節點進行通訊的情況下,仍然可以正常運作,redis叢集對節點使用了主從複制功能:叢集中每個節點都有1個至N個複制品,其中一個複制品為主節點,而其餘的N-1個複制品為從節點
在之前列舉的節點 A 、B 、C 的例子中, 如果節點 B 下線了, 那麼叢集将無法正常運作, 因為叢集找不到節點來處理 5501 号至 11000 号的哈希
槽。
假如在建立叢集的時候(或者至少在節點 B 下線之前), 我們為主節點 B添加了從節點 B1 , 那麼當主節點 B 下線的時候, 叢集就會将 B1 設定為新的主節點, 并讓它代替下線的主節點 B , 繼續處理 5501 号至 11000 号的哈希槽, 這樣叢集就不會因為主節點 B 的下線而無法正常運作了。
不過如果節點 B 和 B1 都下線的話, Redis 叢集還是會停止運作。
1. 在叢集中,節點會對其它節點進行下線檢測
2. 當一個主節點下線時,叢集中其它節點負責對下年主節點進行故障轉移
3. 換句話說,叢集的節點內建了下線檢測和故障轉移等類似sentinel的功能
4. 因為sentinel是一個獨立運作的監控程式,而叢集的下線檢測和故障轉移等功能是內建在節點中的,他們的運作模式非常的不同,是以盡管這兩者的功能很相似,但叢集的實作沒有重用sentinel的代碼
示例1-1 指令發送到正确的節點 : 就像單機redis伺服器一樣
Ø 槽位說明:
7000: 槽 0~5000
7001:槽 5001~10000
7002:槽 10001~16383
示例1-1 指令發送到了錯誤的節點:
接受到指令的節點并非處理鍵所在槽節點,那麼節點将向用戶端傳回一個轉向錯誤,告知用戶端應該到哪個節點上去執行指令,用戶端根據錯誤提示資訊重新執行指令
Ø 鍵date位于2022槽,該槽由7000負責,但錯誤發送到了7001上,7001向用戶端傳回轉向錯誤
Ø 用戶端根據錯誤提示,轉向到7000,并重新發送指令
Ø 安裝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)
1 additional replica(s)
slots: (0 slots) slave
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@gitlab data]#
Ø 寫入資料:
[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"
Ø 檢視叢集狀态:
[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
Ø 重新分片實戰:
[root@gitlab data]# redis-trib.rb reshard 127.0.0.1:7000
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
Destination node:
M: e61c8c741d9a1e69ca2d9a6f36e46177915393c0 127.0.0.1:7002
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:
Ø 删除一個節點:
如果節點上還有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 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
Ø 添加一個節點:
redis-trib.rb add-node 127.0.0.1:7000 127.0.0.1:7002
注意:添加節點時,要保證節點是全新的
Ø 添加一個從節點:
redis-trib.rb add-node --slave --master-id $[nodeid] 127.0.0.1:7008 127.0.0.1:7000
第2章 Redis API:
Ø 連接配接測試代碼
[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();
?>
Ø 字元串操作
//設定 redis 字元串資料
$redis->set("tutorial-name", "Redis tutorial");
// 擷取存儲的資料并輸出
echo "Stored string in redis:: " . $redis-
>get("tutorial-name");
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'
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")
>>> print(rc.get("foo"))
bar
>>> 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')