一、redis cluster環境搭建:
1.了解Redis Cluster原理:
docker redis集群、? ?詳細了解可參考:http://doc.redisfans.com/topic/cluster-tutorial.html#id5
? ??Redis Cluster?是Redis的集群實現,內置數據自動分片機制,集群內部將所有的key映射到16384個Slot中,集群中的每個Redis Instance負責其中的一部分的Slot的讀寫。集群客戶端連接集群中任一Redis Instance即可發送命令,當Redis Instance收到自己不負責的Slot的請求時,會將負責請求Key所在Slot的Redis Instance地址返回給客戶端,客戶端收到后自動將原請求重新發往這個地址,對外部透明。一個Key到底屬于哪個Slot由crc16(key) % 16384 決定。
? ? 關于負載均衡,集群的Redis Instance之間可以遷移數據,以Slot為單位,但不是自動的,需要外部命令觸發。
master和slave怎么共享。? ? 關于集群成員管理,集群的節點(Redis Instance)和節點之間兩兩定期交換集群內節點信息并且更新,從發送節點的角度看,這些信息包括:集群內有哪些節點,IP和PORT是什么,節點名字是什么,節點的狀態(比如OK,PFAIL,FAIL等)是什么,包括節點角色(master 或者 slave)等。
? ? 關于可用性,集群由N組主從Redis Instance組成。主可以沒有從,但是沒有從意味著主宕機后主負責的Slot讀寫服務不可用。一個主可以有多個從,主宕機時,某個從會被提升為主,具體哪個從被提升為主,協議類似于Raft,參見這里。如何檢測主宕機?Redis Cluster采用quorum+心跳的機制。從節點的角度看,節點會定期給其他所有的節點發送Ping,cluster-node-timeout(可配置,秒級)時間內沒有收到對方的回復,則單方面認為對端節點宕機,將該節點標為PFAIL狀態。通過節點之間交換信息收集到quorum個節點都認為這個節點為PFAIL,則將該節點標記為FAIL,并且將其發送給其他所有節點,其他所有節點收到后立即認為該節點宕機。從這里可以看出,主宕機后,至少cluster-node-timeout時間內該主所負責的Slot的讀寫服務不可用。
2.redis集群搭建(redis cluster需要ruby環境支持)
windows 安裝redis。2.1 redis安裝
? ?Redis對于Linux是官方支持的,參考:http://redis.io/download。
? ?Redis官方是不支持windows的,只是 Microsoft Open Tech group 在 GitHub上開發了一個Win64的版本,項目地址:https://github.com/MSOpenTech/redis/releases。
redis session、? ?下載某版本下的Redis-x64-3.2.100.zip以及Source code?(zip)
2.2 ruby安裝(搭建redis cluster是需要ruby環境支持)
? ?ruby下載安裝http://rubyinstaller.org/downloads/
? ?
?
2.3 安裝 RubyGEM,Redis 的 ruby 支持環境
? ? ?rubygem下載地址:https://rubygems.org/pages/download
? ? ?下載下來是一個壓縮包,解壓運行里面的 setup.rb 安裝 rubyGems。
? ? ? 安裝ruby依賴,由于墻的原因ruby自帶的源有時候很慢,我們換成淘寶的源,不然下面安裝redis依賴會失敗
? ? ?cmd下替換ruby自帶的源如下:? ? ?
ruby -v //查看ruby版本 gem -v //查看gem版本 gem sources //查看gem的源 gem source -l //查看gem的源 gem source -a https://ruby.taobao.org //添加淘寶ruby源 gem source -r https://rubygems.org/ //移除ruby自帶源 gem install redis //安裝redis依賴
2.4 使用redis cluster:
? ?要讓redis集群正常運作至少需要三個主節點,因此我們創建6個節點,三個主節點,三個從節點。
2.4.1 創建集群目錄,cmd命令:
E:
cd redis
mkdir 7000 7001 7002 7003 7004 7005
將redis解壓后文件夾中的redis.windows.conf以及redis-server等內容,分別拷貝到新建的六個文件夾中
2.4.2 更改配置
?將六個文件夾下的redis.windows.conf文件中以下屬性進行修改:
port 7001(對應文件夾的端口號)
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
2.4.3 創建redis啟動腳本
@echo off cd 7000 (對應文件夾,依次創建) redis-server.exe redis.windows.conf @pause
創建批量啟動腳本
@echo on start 7000.bat start 7001.bat start 7002.bat start 7003.bat start 7004.bat start 7005.bat @pause
或者可以:
@echo off
start Redis-Server ./7000/redis.windows.conf
start Redis-Server ./7001/redis.windows.conf
start Redis-Server ./7002/redis.windows.conf
start Redis-Server ./7003/redis.windows.conf
start Redis-Server ./7004/redis.windows.conf
start Redis-Server ./7005/redis.windows.conf
@pause
2.4.4 創建集群
解壓Redis的Source code?(zip)包,copy其中src下的redis-trib.rb(ruby編寫,之前的ruby環境就是為這個準備的)到E:\Redis
cmd如下:
e: cd redis 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
redis-trib.rb
create: 這表示我們希望創建一個新的集群。
選項 --replicas 1 :表示我們希望為集群中的每個主節點創建一個從節點。
之后跟著的其他參數則是實例的地址列表, 我們希望程序使用這些地址所指示的實例來創建新集群。就是讓 redis-trib 程序創建一個包含三個主節點和三個從節點的集群。
執行結果如下:
E:\Redis>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 //這里可以看到主從對應關系7003是7001的副本 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: 7247e10169405fc4b1792d5068902407e8431cc0 127.0.0.1:7000slots:0-5460 (5461 slots) master M: ddde095bcebb14a734b124cd2bd9aac8985d5a6d 127.0.0.1:7001slots:5461-10922 (5462 slots) master M: 8583514abc3a324099144dc8bac8f6d4c3c03bd4 127.0.0.1:7002slots:10923-16383 (5461 slots) master S: 397cd20d54aadb0625e629647244cd556beae174 127.0.0.1:7003replicates 7247e10169405fc4b1792d5068902407e8431cc0 S: 9869f6f33638f47da17d303ad5c497727839b120 127.0.0.1:7004replicates ddde095bcebb14a734b124cd2bd9aac8985d5a6d S: d27177a907f27c546dda2693d9c4a723d92be6de 127.0.0.1:7005replicates 8583514abc3a324099144dc8bac8f6d4c3c03bd4 Can I set the above configuration? (type 'yes' to accept): yes//對配置沒問題就輸入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: 7247e10169405fc4b1792d5068902407e8431cc0 127.0.0.1:7000slots:0-5460 (5461 slots) master M: ddde095bcebb14a734b124cd2bd9aac8985d5a6d 127.0.0.1:7001slots:5461-10922 (5462 slots) master M: 8583514abc3a324099144dc8bac8f6d4c3c03bd4 127.0.0.1:7002slots:10923-16383 (5461 slots) master M: 397cd20d54aadb0625e629647244cd556beae174 127.0.0.1:7003slots: (0 slots) masterreplicates 7247e10169405fc4b1792d5068902407e8431cc0 M: 9869f6f33638f47da17d303ad5c497727839b120 127.0.0.1:7004slots: (0 slots) masterreplicates ddde095bcebb14a734b124cd2bd9aac8985d5a6d M: d27177a907f27c546dda2693d9c4a723d92be6de 127.0.0.1:7005slots: (0 slots) masterreplicates 8583514abc3a324099144dc8bac8f6d4c3c03bd4 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.//這表示集群中的?16384?個槽都有至少一個主節點在處理, 集群運作正常。
現在的master是7000 7001 7002這三臺機,redis會對key做?CRC16 校驗和后分別存儲這三臺機上,沒問題就輸入 yes。
例如 7000 這臺機 slots:0-5460 的意思是,對key 做?CRC16 校驗和后 值在 0-5460范圍內都會存到這臺機器里。
例如 key=288 對應的CRC16校驗和 為 4258,應該存在7000這臺機里
PS:使用前應該對業務做梳理,根據系統中key的特點來調整各個機器的slots范圍, 不然系統的key基本集中在一兩臺機器上集群的效果就不大了。
至此,windows下redis cluster搭建成功。
2.4.5 在redis-cli下測試一下:
D:\Redis>redis-cli -c -p 7001 127.0.0.1:7001> set lcawen hello OK 127.0.0.1:7001> set hello world -> Redirected to slot [866] located at 127.0.0.1:7000 OK 127.0.0.1:7000> get lcawen -> Redirected to slot [10428] located at 127.0.0.1:7001 "hello" 127.0.0.1:7001> get hello -> Redirected to slot [866] located at 127.0.0.1:7000 "world" 127.0.0.1:7000> keys * 1) "hello" 127.0.0.1:7000> get lcawen -> Redirected to slot [10428] located at 127.0.0.1:7001 "hello" 127.0.0.1:7001> keys * 1) "lcawen"
? ?附Redis配置文件詳解:
# 守護進程模式 daemonize yes # pid file pidfile /var/run/redis.pid# 監聽端口 port 7003# TCP接收隊列長度,受/proc/sys/net/core/somaxconn和tcp_max_syn_backlog這兩個內核參數的影響 tcp-backlog 511# 一個客戶端空閑多少秒后關閉連接(0代表禁用,永不關閉) timeout 0# 如果非零,則設置SO_KEEPALIVE選項來向空閑連接的客戶端發送ACK tcp-keepalive 60# 指定服務器調試等級 # 可能值: # debug (大量信息,對開發/測試有用) # verbose (很多精簡的有用信息,但是不像debug等級那么多) # notice (適量的信息,基本上是你生產環境中需要的) # warning (只有很重要/嚴重的信息會記錄下來) loglevel notice# 指明日志文件名 logfile "./redis7003.log"# 設置數據庫個數 databases 16# 會在指定秒數和數據變化次數之后把數據庫寫到磁盤上 # 900秒(15分鐘)之后,且至少1次變更 # 300秒(5分鐘)之后,且至少10次變更 # 60秒之后,且至少10000次變更 save 900 1 save 300 10 save 60 10000# 默認如果開啟RDB快照(至少一條save指令)并且最新的后臺保存失敗,Redis將會停止接受寫操作 # 這將使用戶知道數據沒有正確的持久化到硬盤,否則可能沒人注意到并且造成一些災難 stop-writes-on-bgsave-error yes# 當導出到 .rdb 數據庫時是否用LZF壓縮字符串對象 rdbcompression yes# 版本5的RDB有一個CRC64算法的校驗和放在了文件的最后。這將使文件格式更加可靠。 rdbchecksum yes# 持久化數據庫的文件名 dbfilename dump.rdb# 工作目錄 dir ./# 當master服務設置了密碼保護時,slav服務連接master的密碼 masterauth 0234kz9*l# 當一個slave失去和master的連接,或者同步正在進行中,slave的行為可以有兩種: # # 1) 如果 slave-serve-stale-data 設置為 "yes" (默認值),slave會繼續響應客戶端請求, # 可能是正常數據,或者是過時了的數據,也可能是還沒獲得值的空數據。 # 2) 如果 slave-serve-stale-data 設置為 "no",slave會回復"正在從master同步 # (SYNC with master in progress)"來處理各種請求,除了 INFO 和 SLAVEOF 命令。 slave-serve-stale-data yes# 你可以配置salve實例是否接受寫操作。可寫的slave實例可能對存儲臨時數據比較有用(因為寫入salve # 的數據在同master同步之后將很容易被刪除 slave-read-only yes# 是否在slave套接字發送SYNC之后禁用 TCP_NODELAY? # 如果你選擇“yes”Redis將使用更少的TCP包和帶寬來向slaves發送數據。但是這將使數據傳輸到slave # 上有延遲,Linux內核的默認配置會達到40毫秒 # 如果你選擇了 "no" 數據傳輸到salve的延遲將會減少但要使用更多的帶寬 repl-disable-tcp-nodelay no# slave的優先級是一個整數展示在Redis的Info輸出中。如果master不再正常工作了,哨兵將用它來 # 選擇一個slave提升=升為master。 # 優先級數字小的salve會優先考慮提升為master,所以例如有三個slave優先級分別為10,100,25, # 哨兵將挑選優先級最小數字為10的slave。 # 0作為一個特殊的優先級,標識這個slave不能作為master,所以一個優先級為0的slave永遠不會被 # 哨兵挑選提升為master slave-priority 100# 密碼驗證 # 警告:因為Redis太快了,所以外面的人可以嘗試每秒150k的密碼來試圖破解密碼。這意味著你需要 # 一個高強度的密碼,否則破解太容易了 requirepass 0234kz9*l # redis實例最大占用內存,不要用比設置的上限更多的內存。一旦內存使用達到上限,Redis會根據選定的回收策略(參見: # maxmemmory-policy)刪除key maxmemory 3gb# 最大內存策略:如果達到內存限制了,Redis如何選擇刪除key。你可以在下面五個行為里選: # volatile-lru -> 根據LRU算法刪除帶有過期時間的key。 # allkeys-lru -> 根據LRU算法刪除任何key。 # volatile-random -> 根據過期設置來隨機刪除key, 具備過期時間的key。 # allkeys->random -> 無差別隨機刪, 任何一個key。 # volatile-ttl -> 根據最近過期時間來刪除(輔以TTL), 這是對于有過期時間的key # noeviction -> 誰也不刪,直接在寫操作時返回錯誤。 maxmemory-policy volatile-lru# 默認情況下,Redis是異步的把數據導出到磁盤上。這種模式在很多應用里已經足夠好,但Redis進程 # 出問題或斷電時可能造成一段時間的寫操作丟失(這取決于配置的save指令)。 # # AOF是一種提供了更可靠的替代持久化模式,例如使用默認的數據寫入文件策略(參見后面的配置) # 在遇到像服務器斷電或單寫情況下Redis自身進程出問題但操作系統仍正常運行等突發事件時,Redis # 能只丟失1秒的寫操作。 # # AOF和RDB持久化能同時啟動并且不會有問題。 # 如果AOF開啟,那么在啟動時Redis將加載AOF文件,它更能保證數據的可靠性。 appendonly no# aof文件名 appendfilename "appendonly.aof"# fsync() 系統調用告訴操作系統把數據寫到磁盤上,而不是等更多的數據進入輸出緩沖區。 # 有些操作系統會真的把數據馬上刷到磁盤上;有些則會盡快去嘗試這么做。 # # Redis支持三種不同的模式: # # no:不要立刻刷,只有在操作系統需要刷的時候再刷。比較快。 # always:每次寫操作都立刻寫入到aof文件。慢,但是最安全。 # everysec:每秒寫一次。折中方案。 appendfsync everysec# 如果AOF的同步策略設置成 "always" 或者 "everysec",并且后臺的存儲進程(后臺存儲或寫入AOF # 日志)會產生很多磁盤I/O開銷。某些Linux的配置下會使Redis因為 fsync()系統調用而阻塞很久。 # 注意,目前對這個情況還沒有完美修正,甚至不同線程的 fsync() 會阻塞我們同步的write(2)調用。 # # 為了緩解這個問題,可以用下面這個選項。它可以在 BGSAVE 或 BGREWRITEAOF 處理時阻止主進程進行fsync()。 # # 這就意味著如果有子進程在進行保存操作,那么Redis就處于"不可同步"的狀態。 # 這實際上是說,在最差的情況下可能會丟掉30秒鐘的日志數據。(默認Linux設定) # # 如果你有延時問題把這個設置成"yes",否則就保持"no",這是保存持久數據的最安全的方式。 no-appendfsync-on-rewrite yes# 自動重寫AOF文件 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb# AOF文件可能在尾部是不完整的(這跟system關閉有問題,尤其是mount ext4文件系統時 # 沒有加上data=ordered選項。只會發生在os死時,redis自己死不會不完整)。 # 那redis重啟時load進內存的時候就有問題了。 # 發生的時候,可以選擇redis啟動報錯,并且通知用戶和寫日志,或者load盡量多正常的數據。 # 如果aof-load-truncated是yes,會自動發布一個log給客戶端然后load(默認)。 # 如果是no,用戶必須手動redis-check-aof修復AOF文件才可以。 # 注意,如果在讀取的過程中,發現這個aof是損壞的,服務器也是會退出的, # 這個選項僅僅用于當服務器嘗試讀取更多的數據但又找不到相應的數據時。 aof-load-truncated yes# Lua 腳本的最大執行時間,毫秒為單位 lua-time-limit 5000# Redis慢查詢日志可以記錄超過指定時間的查詢 slowlog-log-slower-than 10000# 這個長度沒有限制。只是要主要會消耗內存。你可以通過 SLOWLOG RESET 來回收內存。 slowlog-max-len 128# redis延時監控系統在運行時會采樣一些操作,以便收集可能導致延時的數據根源。 # 通過 LATENCY命令 可以打印一些圖樣和獲取一些報告,方便監控 # 這個系統僅僅記錄那個執行時間大于或等于預定時間(毫秒)的操作, # 這個預定時間是通過latency-monitor-threshold配置來指定的, # 當設置為0時,這個監控系統處于停止狀態 latency-monitor-threshold 0# Redis能通知 Pub/Sub 客戶端關于鍵空間發生的事件,默認關閉 notify-keyspace-events ""# 當hash只有少量的entry時,并且最大的entry所占空間沒有超過指定的限制時,會用一種節省內存的 # 數據結構來編碼。可以通過下面的指令來設定限制 hash-max-ziplist-entries 512 hash-max-ziplist-value 64# 與hash似,數據元素較少的list,可以用另一種方式來編碼從而節省大量空間。 # 這種特殊的方式只有在符合下面限制時才可以用 list-max-ziplist-entries 512 list-max-ziplist-value 64# set有一種特殊編碼的情況:當set數據全是十進制64位有符號整型數字構成的字符串時。 # 下面這個配置項就是用來設置set使用這種編碼來節省內存的最大長度。 set-max-intset-entries 512# 與hash和list相似,有序集合也可以用一種特別的編碼方式來節省大量空間。 # 這種編碼只適合長度和元素都小于下面限制的有序集合 zset-max-ziplist-entries 128 zset-max-ziplist-value 64# HyperLogLog稀疏結構表示字節的限制。該限制包括 # 16個字節的頭。當HyperLogLog使用稀疏結構表示 # 這些限制,它會被轉換成密度表示。 # 值大于16000是完全沒用的,因為在該點 # 密集的表示是更多的內存效率。 # 建議值是3000左右,以便具有的內存好處, 減少內存的消耗 hll-sparse-max-bytes 3000# 啟用哈希刷新,每100個CPU毫秒會拿出1個毫秒來刷新Redis的主哈希表(頂級鍵值映射表) activerehashing yes# 客戶端的輸出緩沖區的限制,可用于強制斷開那些因為某種原因從服務器讀取數據的速度不夠快的客戶端 client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60# 默認情況下,“hz”的被設定為10。提高該值將在Redis空閑時使用更多的CPU時,但同時當有多個key # 同時到期會使Redis的反應更靈敏,以及超時可以更精確地處理 hz 10# 當一個子進程重寫AOF文件時,如果啟用下面的選項,則文件每生成32M數據會被同步 aof-rewrite-incremental-fsync yes
3.Redis容災部署(哨兵Sentinel)
哨兵的作用
1.?監控:監控主從是否正常
2.?通知:出現問題時,可以通知相關人員
3.?故障遷移:自動主從切換
4.?統一的配置管理:連接者詢問sentinel取得主從的地址
Raft分布式算法
1.?主要用途:用于分布式系統,系統容錯,以及選出領頭羊
2.?作者:Diego Ongaro,畢業于哈佛
3.?目前用到這個算法的項目有:
a. CoreOS :?見下面
b. ectd : a distributed, consistent shared configuration?
c. LogCabin :?分布式存儲系統
d. redis sentinel : redis?的監控系統
Sentinel使用的Raft算法核心:?原則
1.?所有sentinel都有選舉的領頭羊的權利
2.?每個sentinel都會要求其他sentinel選舉自己為領頭羊(主要由發現redis客觀下線的sentinel先發起選舉)
3.?每個sentinel只有一次選舉的機會
4.?采用先到先得的原則
5.?一旦加入到系統了,則不會自動清除(這一點很重要, why?)
6.?每個sentinel都有唯一的uid,不會因為重啟而變更
7.?達到領頭羊的條件是?N/2 + 1個sentinel選擇了自己
8.?采用配置紀元,如果一次選舉出現腦裂,則配置紀元會遞增,進入下一次選舉,所有sentinel都會處于統一配置紀元,以最新的為標準。
Raft分布式算法的應用
coreos:云計算新星?Docker?正在以火箭般的速度發展,與它相關的生態圈也漸入佳境,CoreOS?就是其中之一。CoreOS?是一個全新的、面向數據中心設計的?Linux?操作系統,在2014年7月發布了首個穩定版本,目前已經完成了800萬美元的A輪融資。
?
Sentinel實現Redis容災部署,Sentinal配置:
# Example sentinel.conf# port <sentinel-port> port 26371# 守護進程模式 daemonize yes# 指明日志文件名 logfile "./sentinel.log"# 工作路徑,sentinel一般指定/tmp比較簡單 dir ./# 哨兵監控這個master,在至少quorum個哨兵實例都認為master down后把master標記為odown # (objective down客觀down;相對應的存在sdown,subjective down,主觀down)狀態。 # slaves是自動發現,所以你沒必要明確指定slaves。 sentinel monitor TestMaster 127.0.0.1 7003 1# master或slave多長時間(默認30秒)不能使用后標記為s_down狀態。 sentinel down-after-milliseconds TestMaster 1500# 若sentinel在該配置值內未能完成failover操作(即故障時master/slave自動切換),則認為本次failover失敗。 sentinel failover-timeout TestMaster 10000# 設置master和slaves驗證密碼 sentinel auth-pass TestMaster 0234kz9*lsentinel config-epoch TestMaster 15 sentinel leader-epoch TestMaster 8394# #除了當前哨兵, 還有哪些在監控這個master的哨兵,即其他的哨兵 sentinel known-sentinel TestMaster 127.0.0.1 26372 0aca3a57038e2907c8a07be2b3c0d15171e44da5 sentinel known-sentinel TestMaster 127.0.0.1 26373 ac1ef015411583d4b9f3d81cee830060b2f29862sentinel current-epoch 8394
?