redis复制、哨兵、集群详细介绍
目錄
1、redis性能瓶頸在哪里?
2、redis為什么需要高可用?
3、主從復制
3.1、主從復制原理
3.1.1、復制初始化
3.1.2、復制同步階段
3.1.3、增量復制
3.1.4、無硬盤復制
3.2、異步復制導致主從庫數據不一致怎么解決?
3.3、主從復制崩潰恢復
4、哨兵
5、集群
5.1、插槽
5.2、集群的主從復制模型
5.3、集群一致性
5.4、搭建集群
6、redis模板配置文件
7、安裝Ruby
1、redis性能瓶頸在哪里?
首先說說redis為什么這么快。主要有以下幾點原因:
- 純內存操作;
- 單線程操作,避免頻繁上下文切換;
- 采用IO多路復用模型;
- 純ANSI C語言編寫;
由于redis是純內存操作并且采用了IO多路復用模型,因此redis的性能瓶頸不應該是CPU,內存和網絡延遲更應該是redis的性能瓶頸。
?
2、redis為什么需要高可用?
需要高可用的原因主要為:
- 單點故障:因此需要將數據生成多個副本分布在不同的機器上;
- 內存容易成為瓶頸:因此需要對數據進行分片;
redis有三種高可用方案,分別是:
- 主從復制
- 哨兵
- 集群
?
3、主從復制
主庫:可以讀寫,將數據同步給從庫
從庫:只能讀,如果修改從庫數據會報錯(將slave-read-only設置為no就不會報錯)
一個主庫可以有多個從庫,但一個從庫只能有一個主庫。從庫也可以作為主庫。
主從復制可以同來實現讀寫分離,比如在電商系統中,讀的壓力大于寫,那么可以配置一主多從的redis高可用架構,主庫用來寫,多個從庫用來讀。
由于主從復制不能有多個主庫,因此當寫壓力過大時一主多從不再滿足需求,此時需要使用redis集群。
?
如何配置主從復制?兩種方法如下:
- 在從庫的redis.conf中配置slaveof host port;
- 在從庫執行slaveof host port命令;
?
info section命令以一種易于理解和閱讀的格式,返回關于Redis服務器的各種信息和統計數值。比如查看復制相關信息,可以使用info replication。
在一個主庫上執行info replication命令打印出來的信息如下所示。
127.0.0.1:6379> INFO replication # Replication role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6380,state=online,offset=14,lag=0 master_replid:0dca9fd8627630d1058cd3ae740c39edc03f07c5 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:14 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:14也可以使用role命令查看節點角色。
?
如果當前庫已經是某個主庫的從庫,那么執行slaveofhost port 將使當前庫停止對舊主庫的同步,丟棄舊數據集,轉而開始接收新主庫的同步。
另外,對一個從庫執行命令slave no one將使得這個從庫關閉復制功能,并從從庫轉變回主庫,原來同步所得的數據集不會被丟棄。
利用slave no one不會丟棄同步所得數據集這個特性,可以在主庫失敗的時候,將從庫作為新的主庫,從而實現無間斷運行。
?
3.1、主從復制原理
3.1.1、復制初始化
從庫啟動后,向主庫發生SYNC命令
主庫接收到命令并在后臺保存RDB快照(異步),并將保存快照期間接收到的客戶端命令緩存起來,然后一起發給從庫
從庫會將收到的內容寫入磁盤臨時文件,最后用臨時文件替換舊的RDB文件(在寫臨時文件期間,從庫不會阻塞客戶端請求,并且用同步前的數據響應客戶端,可以在redis.conf中配置slave-serve-stale-data為no來讓從庫在同步完成前對除了info和slave之外的所有命令響應錯誤)
?
3.1.2、復制同步階段
主庫每當收到寫命令就將命令同步給從庫(同步的內容就是redis通信協議的內容)
?
3.1.3、增量復制
主從庫斷開連接后,從庫再次連接主庫時,不必再進行一次復制初始化,而是直接增量復制(redis2.8版本開始支持)。
原理:
?
3.1.4、無硬盤復制
復制初始化時,由于主庫會進行快照生成RDB文件,因此會影響性能。redis2.8版本支持無硬盤復制(redis.conf中將repl-diskless-sync設置為yes),主庫直接通過網絡將數據發生給從庫
?
3.2、異步復制導致主從庫數據不一致怎么解決?
redis主從復制不保證強一致性,而是保證最終一致性。
另外,可以在主庫的redis.conf中可以做如下配置。
# 允許最小連接的從庫數 min-slaves-to-write 3 # 允許從庫最長失去連接的時間 min-slaves-max-lag 10以上兩個配置只要有一個不滿足,則主庫不可寫。
?
3.3、主從復制崩潰恢復
在主從復制中,主庫一般是禁用持久化的,因為從庫已經做數據備份了,禁用持久化可以提高性能。
從庫崩潰,直接重啟從庫即可
主庫崩潰,不能直接重啟主庫,因為主庫禁用持久化,如果重啟主庫則直接丟失數據,然后同步給從庫,從庫也相應地丟失數據。
為了避免數據丟失,當主庫崩潰時,需要做以下兩步操作:
在從庫執行slave no one命令將從庫升級為主庫
重啟崩潰的主庫,然后使用slave命令將其設置為新主庫的從庫
?
無論主庫崩潰還是從庫崩潰,都需要手動操作,手動操作不僅麻煩還容易出錯,因此redis提供哨兵這一機制來支持自動操作。
?
4、哨兵
哨兵的功能:
- 監控主從庫是否正常運行;
- 主庫故障時自動將主庫轉為從庫;
可以部署多個哨兵,哨兵之間也會互相監控。
哨兵甚至可以監控多個主從系統,通過在sentinel.conf中配置多行sentinel monitor配置來實現。
哨兵是一個可執行文件,在redis的src目錄下面,名稱為redis-sentinel。
在sentinel.conf中,做如下配置。
sentinel monitor mymaster 127.0.0.1 6379 1mymaster是主庫名。
127.0.0.1:6379是主庫的ip和端口號,sentinel.conf中只需要配置要監控的主庫即可,而從庫sentinel會根據主庫自動發現。
1表示至少需要1個哨兵節點同意。
然后執行以下命令啟動sentinel進程
src/redis-sentinel? sentinel.conf
?
下面演示一下哨兵是如何自動化監控主從復制的。
為了簡單起見,現有一主一從,主庫為127.0.0.1::6379,從庫為127.0.0.1::6380。
以上三步哨兵的日志如下圖所示。
?
5、集群
雖然引入了哨兵,但主從復制中每個節點都存儲全量數據,因此最大能存儲多少數據受限于內存最小的那個節點,形成木桶效應,因此需要對redis做數據分片。
客戶端分片:
- 舊版redis使用使用客戶端分片,即由客戶端決定每個鍵交由那個數據庫節點存儲;
- 弊端:如果集群增刪節點,則需要手動遷移數據,且為了保證遷移過程中的數據一致性需要將集群暫時下線;
redis3.0開始支持集群。
集群特點:
- 擁有和單機實例同樣的性能;
- 在網絡分區后提供一定的可訪問性以及對主庫故障恢復的支持;
- redis集群并不支持處理多個key的命令(如mget),這是因為在不同的節點間移動數據會達不到像單機redis那樣的性能,在高負載的情況下可能會導致不可預料的錯誤;
- 只能使用0號數據庫,如果用select切換則報錯;
- 支持數據分片和主從復制;
?
5.1、插槽
redis cluster沒有使用一致性hash,而是有一個哈希槽的概念,默認有16384個插槽。
redis將每個鍵鍵名的有效部分使用CRC16算法計算出散列值,然后對16384取余。
有效部分:
- 如果鍵名中包含{至少一個字符},則有效部分為大括號里面的內容,比如{user001}:username和{user001}:password這兩個鍵的有效部分都是user001,那么它們會被分配到一個結點上,可以使用涉及多鍵的命令(比如mget)去處理它們;
- 如果鍵名中不包含{至少一個字符},則整個鍵名都是有效部分;
- 如果有多個大括號則算法會在匹配第一個大括號就停止,然后進行判斷。比如鍵a{b}cze8trgl8bvbq的有效部分為b,而a{}cze8trgl8bvbq的有效部分為整個鍵名;
集群中的每個主節點負責分配一部分插槽,cluster slots命令用于查看插槽分配情況,而從節點只負責備份主節點的插槽。
增刪節點怎么辦?
- 比如現在有A、B、C三個主節點,假如想增加D節點,那么只要將A、B、C節點中的部分槽遷移到D即可,如果想刪除B節點,則只需要將B節點的槽遷移到A、C節點即可。
增刪節點或者是修改某個節點槽的數量都不會導致集群不可用。
?
5.2、集群的主從復制模型
redis集群是支持主從復制的,目的是為了提高可用性。
比如當前集群有三個主節點A、B、C和三個從節點A1、B1、C1,則有以下情況:
主從節點只要不是都掛,則不需要開啟持久化,如果都掛,那必須要開啟持久化了。
如果你的redis cluster只用于緩存,那么為了最大程度提升性能,不需要開啟持久化。
如果你的redis cluster用來做數據庫,那么就要看情況了,如果主從同時掛掉的幾率不大且你對數據丟失的容忍度還行的話,就不需要開啟持久化,否則需要。
?
5.3、集群一致性
redis集群不保證強一致性,導致不一致的可能原因有兩個:
- 主從節點間是異步復制的;
- 某個主節點發生了網絡分區,比如集群有A、B、C三個主節點以及對應的從節點A1、B1、C1,此時主節點B與集群形成網絡分區,在網絡分區期間某個客戶端往B節點寫數據,如果網絡分區很短暫,那數據就不會丟失;但如果在網絡分區期間集群重新選舉了B1節點為主節點,那么數據就會丟失了;
形成網絡分區的節點的超時時間是可以通過cluster-node-timeout這個配置項配置的,如果沒有超時,則客戶端可以正常向分區節點寫數據,如果超時則不能寫入。
?
5.4、搭建集群
集群至少需要3個節點才能正常運行,下面演示一下在單個centos系統上配置一個3主3從的redis集群。
集群重要配置如下。
cluster-enable yes cluster-node-timeout 5000 cluster-config-file nodes.conf集群文件夾結構如下圖所示。
6381節點配置文件內容如下,其它節點類似(關于模板配置文件見本文第6節-redis模板配置文件)。
include ../run/redis-cluster.conf port 6381 pidfile /usr/local/redis-cluster/run/redis-6381.pid logfile /usr/local/redis-cluster/run/redis-6381.log dir /usr/local/redis-cluster/6381/ cluster-config-file /usr/local/redis-cluster/run/nodes-6381.conf啟動各個節點,用redis-cli連接任意節點執行info cluster命令可以查看集群狀態,cluster_enable為1表示可用。
但此時還不能寫數據,比如在任意節點執行set age 10命令時,會報錯:(error) CLUSTERDOWN Hash slot not served。
這是因為此時每個節點還是獨立狀態,下面需要將各節點聯系在一起,即初始化集群。
如果是舊版本的redis,可以使用src/redis-trib(ruby語言編寫,安裝Ruby見本文第7節-安裝Ruby)來初始化集群,初始化集群的命令如下。
src/redis-trib.rb --replicas 1 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385 127.0.0.1:6386replicas 1表示每個主節點的副本個數為1。
如果執行上述命令提示WARNING: redis-trib.rb is not longer available!,則表示當前版本的redis已經不支持redis-trib.rb,具體的提示信息如下圖所示。
根據該提示,我們知道了應該使用redis-cli來代替redis-trib.rb。
首先在redis-cli中執行cluster help命令,查看與集群cluster相關的命令有哪些,如下所示。
ADDSLOTS <slot> [slot ...] -- 為當前節點分配槽位 BUMPEPOCH -- Advance the cluster config epoch. COUNT-failure-reports <node-id> -- 根據<node-id>返回失敗報告的數量 COUNTKEYSINSLOT <slot> - 根據槽位返回key數量 DELSLOTS <slot> [slot ...] -- 在當前節點刪除指定槽位 FAILOVER [force|takeover] -- 將當前復制節點提升為主節點 FORGET <node-id> -- 從集群中移除節點 GETKEYSINSLOT <slot> <count> -- 返回當前節點存儲在插槽中的鍵名 FLUSHSLOTS -- 刪除當前節點的槽位信息 INFO - 返回關于集群的信息. KEYSLOT <key> -- 根據key返回hash槽 MEET <ip> <port> [bus-port] -- 將節點連接到工作集群 MYID -- 返回當前節點id NODES -- 返回節點看到的集群配置。輸出格式:<id> <ip:port> <flags> <master> <pings> <pongs> <epoch> <link> <slot> ... <slot> REPLICATE <node-id> -- 配置當前節點為<node-id>的復制節點 RESET [hard|soft] -- 重置當前節點 (默認: soft). SET-config-epoch <epoch> - Set config epoch of current node. SETSLOT <slot> (importing|migrating|stable|node <node-id>) -- 設置槽位狀態. REPLICAS <node-id> -- 返回指定主節點的副本節點 SLOTS -- 返回關于槽范圍映射的信息。每個系列都是由:start, end, master and replicas IP addresses, ports and ids?
初始化集群步驟:
1、使用cluster meet命令將各個節點聯系在一起,如下圖所示。
再執行cluster nodes命令,可以看到六個節點聯系在一起了,如下圖所示。但此時這六個節點都是主庫,并且還沒有分配插槽。
2、使用cluster addslots命令為所有主庫分配插槽。
由于cluster addslots命令不支持批量添加插槽,所以我寫了一個shell腳本利用for循環批量分配插槽,shell腳本如下。
for ((i=$3; i<=$4; i ++)) do6381/src/redis-cli -h $1 -p $2 cluster addslots $i > /dev/null done現在讓6381、6382、6383為主庫,我們將16384個插槽分配給這三個主庫,具體分配情況如下:
6381占0~5460號插槽,共5461個
6382占5461~10920號插槽,共5462個
6383占10921~16383號插槽,共5461個
執行如下命令即可分配插槽:
./cluster-addslots.sh 127.0.0.1 6381 0 5460 ./cluster-addslots.sh 127.0.0.1 6382 5461 10920 ./cluster-addslots.sh 127.0.0.1 6383 10921 16383最新使用cluster slots命令查找插槽分配情況。
?
3、使用cluster replicate命令設置從庫
執行如下命令,使得:
- 6384為6381的從庫;
- 6383為6382的從庫;
- 6384為6383的從庫;
最后使用cluster nodes命令查看集群節點信息,即可看到有三個主庫和三個從庫,如下圖所示。
?
集群搭建好后,我們使用redis-cli往集群寫一些數據試試,但如果不幸運的話寫第一個數據就會報錯,如下圖所示。
這是因為redis-cli連接的是6381這個節點,但user:1這個key會被分配到6382節點,因此寫入錯誤。
解決辦法是,redis-cli支持以集群模式連接到某一個節點,并且支持自動重定向,如下圖所示。
?
6、redis模板配置文件
redis-5.0.5版本默認配置文件(去除注釋)如下。
################################## INCLUDES ################################### ################################## MODULES ##################################### ################################## NETWORK ##################################### bind 127.0.0.1 protected-mode yes port 6379 tcp-backlog 511 timeout 0 tcp-keepalive 300 ################################# GENERAL ##################################### daemonize no supervised no pidfile /var/run/redis_6379.pid loglevel notice logfile "" databases 16 always-show-logo yes ################################ SNAPSHOTTING ################################ save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir ./ ################################# REPLICATION ################################# replica-serve-stale-data yes replica-read-only yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no replica-priority 100 ################################## SECURITY ################################### ################################### CLIENTS #################################### ############################## MEMORY MANAGEMENT ################################ ############################# LAZY FREEING #################################### lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no replica-lazy-flush no ############################## APPEND ONLY MODE ############################### 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 aof-use-rdb-preamble yes ################################ LUA SCRIPTING ############################### lua-time-limit 5000 ################################ REDIS CLUSTER ############################### ########################## CLUSTER DOCKER/NAT support ######################## ################################## SLOW LOG ################################### slowlog-log-slower-than 10000 slowlog-max-len 128 ################################ LATENCY MONITOR ############################## latency-monitor-threshold 0 ############################# EVENT NOTIFICATION ############################## notify-keyspace-events "" ############################### ADVANCED CONFIG ############################### hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 stream-node-max-bytes 4096 stream-node-max-entries 100 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit replica 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 dynamic-hz yes aof-rewrite-incremental-fsync yes rdb-save-incremental-fsync yes ########################### ACTIVE DEFRAGMENTATION #######################將默認的配置文件做如下修改(如何修改具體看需求),使其變為所有節點通用的模板配置文件:
- 注釋bind
- protected-mode改為no
- 注釋port
- daemonize改為yes
- 注釋pidfile
- 注釋logfile
- 注釋三個save
- 注釋dir
如果是集群模式,則還需要:
- 新增cluster-enabled yes;
然后再針對單個節點用include指令導入公共模板(注意使用相對路徑,否則啟動會報錯),然后再做一些本節點的特殊配置,如下所示:
include?../run/redis_useful.conf port 6379 pidfile /var/run/redis_6379.pid logfile /var/log/redis_6379.log dir /usr/local/redis-5.0.5/?
7、安裝Ruby
總結
以上是生活随笔為你收集整理的redis复制、哨兵、集群详细介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我屮艸芔茻!!!什么情况,就刚才,百年之
- 下一篇: NES模拟器源码阅读