redis集羣實現方案:node
關於redis的集羣化方案 目前有三種 redis
(1)Twitter開發的twemproxy 算法
(2)豌豆莢開發的codis 後端
(3)redis官方的redis-clusterruby
簡介:twemproxy架構簡單 就是用proxy對後端redis server進行代理 可是因爲代理層的消耗性能很低 並且一般涉及多個key的操做都是不支持的 並且自己不支持動態擴容和透明的數據遷移 並且也失去維護 Twitter內部已經不使用了。服務器
redis-cluster是三個裏性能最強大的 由於他使用去中心化的思想 使用hash slot方式 將16348個hash slot 覆蓋到全部節點上 對於存儲的每一個key值 使用CRC16(KEY)&16348=slot 獲得他對應的hash slot 並在訪問key時就去找他的hash slot在哪個節點上 而後由當前訪問節點從實際被分配了這個hash slot的節點去取數據 節點之間使用輕量協議通訊 減小帶寬佔用 性能很高 自動實現負載均衡與高可用 自動實現failover 而且支持動態擴展 官方已經玩到能夠1000個節點 實現的複雜度低 總之我的比較喜歡這個架構 由於他的去中心化思想免去了proxy的消耗 是全新的思路。架構
可是它也有一些不足 例如官方沒有提供圖形化管理工具 運維體驗差 全手工數據遷移 而且本身對本身自己的redis命令支持也不徹底等 可是這些問題 我以爲不能掩蓋他關鍵的新思想所帶來的的優點 隨着官方的推動 這些問題應該都能在必定時間內獲得解決 那麼這時候去中心化思想帶來的高性能就會表現出他巨大的優點。app
Codis使用的也是proxy思路 可是作的比較好 是這兩種之間的一箇中間級 並且支持redis命令是最多的 有圖形化GUI管理和監控工具 運維友好 這個過段時間會詳細另外寫出來原理 工做機制和搭建實現。負載均衡
基本介紹:運維
Redis 集羣是一個能夠在多個 Redis 節點之間進行數據共享的設施installation。
Redis 集羣不支持那些須要同時處理多個鍵的 Redis 命令, 由於執行這些命令須要在多個 Redis 節點之間移動數據, 而且在高負載的狀況下, 這些命令將下降Redis集羣的性能, 並致使不可預測的行爲。
Redis 集羣經過分區partition來提供必定程度的可用性availability: 即便集羣中有一部分節點失效或者沒法進行通信, 集羣也能夠繼續處理命令請求。
Redis集羣提供瞭如下兩個好處:
集羣原理:
redis-cluster架構圖:
Redis集羣中內置了 16384 個哈希槽,當須要在 Redis 集羣中放置一個 key-value 時,redis 先對key 使用 crc16 算法算出一個結果,而後把結果對 16384 求餘數,這樣每一個 key 都會對應一個編號在 0-16383 之間的哈希槽,redis 會根據節點數量大體均等的將哈希槽映射到不一樣的節點。
redis-cluster投票:容錯
1. 投票過程是集羣中全部master參與,若是半數以上master節點與master節點通訊超時(cluster-node-timeout),認爲當前master節點掛掉。
2. 何時整個集羣不可用(cluster_state:fail)?
① 若是集羣任意master掛掉,且當前master沒有slave,集羣進入fail狀態,也能夠理解成集羣的slot映射[0-16383]不完整時進入fail狀態。
redis-3.0.0.rc1加入cluster-require-full-coverage參數,默認關閉,打開集羣兼容部分失敗。
② 若是集羣超過半數以上master掛掉,不管是否有slave,集羣進入fail狀態。
redis集羣的搭建
徹底分佈式:redis集羣的節點個數是奇數個,最少有三個節點,爲了保證集羣的高可用性,對每臺redis節點須要進行備份,所以redis集羣須要6臺服務器。
僞分佈式:能夠再一臺服務器上面同時運行6個redis實例,模擬徹底分佈式集羣。須要修改每一個redis實例中的端口號,同時設置cluster-enabled的值爲yes。
硬件環境
本文適用的硬件環境以下:
Linux版本:CentOS release 6.7 (Final) Redis版本:3.2.1
Redis已經成功安裝,安裝路徑爲/home/idata/axing/local/redis-3.2.1。
咱們要在單臺機器上搭建Redis集羣,方式是經過不一樣的TCP端口啓動多個實例,而後組成集羣。
一、啓動Redis多個實例
咱們在Redis安裝目錄下建立目錄cluster,並編寫7000.conf~7005.conf 6個配置文件,這6個配置文件用來啓動6個實例,後面將使用這6個實例組成集羣。
以7000.conf爲例,配置文件須要填寫以下幾項:
port 7000 //端口7000,7002,7003 bind 10.93.84.53 //默認ip爲127.0.0.1 須要改成其餘節點機器可訪問的ip 不然建立集羣時沒法訪問對應的端口,沒法建立集羣 daemonize yes //redis後臺運行 pidfile ./redis_7000.pid //pidfile文件對應7000,7001,7002 cluster-enabled yes //開啓集羣 把註釋#去掉 cluster-config-file nodes_7000.conf //集羣的配置 配置文件首次啓動自動生成 7000,7001,7002 cluster-node-timeout 15000 //請求超時 默認15秒,可自行設置 appendonly yes //aof日誌開啓 有須要就開啓,它會每次寫操做都記錄一條日誌
分別啓動6個實例:
./bin/redis-server cluster/conf/7000.conf ./bin/redis-server cluster/conf/7001.conf ./bin/redis-server cluster/conf/7002.conf ./bin/redis-server cluster/conf/7003.conf ./bin/redis-server cluster/conf/7004.conf ./bin/redis-server cluster/conf/7005.conf
啓動成功後,看一下進程:
# ps -ef | grep redis | grep cluster idata 15711 22329 0 18:40 pts/10 00:00:00 ./bin/redis-server 10.93.84.53:7000 [cluster] idata 15740 22329 0 18:40 pts/10 00:00:00 ./bin/redis-server 10.93.84.53:7001 [cluster] idata 15810 22329 0 18:40 pts/10 00:00:00 ./bin/redis-server 10.93.84.53:7002 [cluster] idata 17023 22329 0 18:42 pts/10 00:00:00 ./bin/redis-server 10.93.84.53:7003 [cluster] idata 17030 22329 0 18:42 pts/10 00:00:00 ./bin/redis-server 10.93.84.53:7004 [cluster] idata 17035 22329 0 18:42 pts/10 00:00:00 ./bin/redis-server 10.93.84.53:7005 [cluster]
至此,ip=10.93.84.53機器上建立了6個實例,端口號爲port=7000~7005。
Redis 3.0以上的集羣方式是經過Redis安裝目錄下的bin/redis-trib.rb腳本搭建。
這個腳本是用Ruby編寫的,嘗試運行,若是打印以下,你能夠跳過本文的第二部分。
idata@qa-f1502-xg01.xg01:~/yangfan/local/redis-3.2.1/bin$ ruby redis-trib.rb Usage: redis-trib <command> <options> <arguments ...> create host1:port1 ... hostN:portN --replicas <arg> check host:port info host:port fix host:port --timeout <arg> reshard host:port --from <arg> --to <arg> --slots <arg> --yes --timeout <arg> --pipeline <arg> rebalance host:port --weight <arg> --auto-weights --use-empty-masters --timeout <arg> --simulate --pipeline <arg> --threshold <arg> add-node new_host:new_port existing_host:existing_port --slave --master-id <arg> del-node host:port node_id set-timeout host:port milliseconds call host:port command arg arg .. arg import host:port --from <arg> --copy --replace help (show this help) For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
二、安裝ruby
下面的過程都是在root權限下完成的。
1)yum安裝ruby和依賴的包。
2)使用gem這個命令來安裝redis接口
3)升級Ruby的版本
4)安裝gem redis接口
5)安裝rubygems
至此,咱們的Ruby和運行redis-trib.rb須要的環境安裝完成了。
三、Redis集羣搭建
有了Ruby執行環境,能夠開始將以前的6個實例組建成集羣了。
命令方式:
ruby ./bin/redis-trib.rb create --replicas 1 10.93.84.53:7000 10.93.84.53:7001 10.93.84.53:7002 10.93.84.53:7003 10.93.84.53:7004 10.93.84.53:7005
--replicas 1表示爲集羣的master節點建立1個副本。那麼6個實例裏,有三個master,有三個是slave。
後面跟上6個實例就行了,形式就是ip:port
執行狀況:
# ruby ./bin/redis-trib.rb create --replicas 1 10.93.84.53:7000 10.93.84.53:7001 10.93.84.53:7002 10.93.84.53:7003 10.93.84.53:7004 10.93.84.53:7005 >>> Creating cluster >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 10.93.84.53:7000 10.93.84.53:7001 10.93.84.53:7002 Adding replica 10.93.84.53:7003 to 10.93.84.53:7000 Adding replica 10.93.84.53:7004 to 10.93.84.53:7001 Adding replica 10.93.84.53:7005 to 10.93.84.53:7002 M: 6346ae8c7af7949658619fcf4021cc7aca454819 10.93.84.53:7000 slots:0-5460 (5461 slots) master M: 5ac973bceab0d486c497345fe884ff54d1bb225a 10.93.84.53:7001 slots:5461-10922 (5462 slots) master M: cc46a4a1c0ec3f621b6b5405c6c10b7cffe73932 10.93.84.53:7002 slots:10923-16383 (5461 slots) master S: 92f62ec93a0550d962f81213ca7e9b3c9c996afd 10.93.84.53:7003 replicates 6346ae8c7af7949658619fcf4021cc7aca454819 S: 942c9f97dc68198c39f425d13df0d8e3c40c5a58 10.93.84.53:7004 replicates 5ac973bceab0d486c497345fe884ff54d1bb225a S: a92a81532b63652bbd862be6f19a9bd8832e5e05 10.93.84.53:7005 replicates cc46a4a1c0ec3f621b6b5405c6c10b7cffe73932 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 10.93.84.53:7000) M: 6346ae8c7af7949658619fcf4021cc7aca454819 10.93.84.53:7000 slots:0-5460 (5461 slots) master 1 additional replica(s) S: a92a81532b63652bbd862be6f19a9bd8832e5e05 10.93.84.53:7005 slots: (0 slots) slave replicates cc46a4a1c0ec3f621b6b5405c6c10b7cffe73932 M: 5ac973bceab0d486c497345fe884ff54d1bb225a 10.93.84.53:7001 slots:5461-10922 (5462 slots) master 1 additional replica(s) S: 942c9f97dc68198c39f425d13df0d8e3c40c5a58 10.93.84.53:7004 slots: (0 slots) slave replicates 5ac973bceab0d486c497345fe884ff54d1bb225a S: 92f62ec93a0550d962f81213ca7e9b3c9c996afd 10.93.84.53:7003 slots: (0 slots) slave replicates 6346ae8c7af7949658619fcf4021cc7aca454819 M: cc46a4a1c0ec3f621b6b5405c6c10b7cffe73932 10.93.84.53:7002 slots:10923-16383 (5461 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
能夠看到16384個slot都已經建立完成,而且創建了3個master和對應的replica:
Using 3 masters: 10.93.84.53:7000 10.93.84.53:7001 10.93.84.53:7002 Adding replica 10.93.84.53:7003 to 10.93.84.53:7000 Adding replica 10.93.84.53:7004 to 10.93.84.53:7001 Adding replica 10.93.84.53:7005 to 10.93.84.53:7002 。。。 [OK] All 16384 slots covered.
四、驗證集羣狀態
登陸集羣客戶端,-c標識以集羣方式登陸:
./bin/redis-cli -h 10.93.84.53 -p 7000 -c
查看集羣狀態:
10.93.84.53:7000> cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:8 cluster_my_epoch:8 cluster_stats_messages_sent:215 cluster_stats_messages_received:215 10.93.84.53:7000> cluster nodes 942c9f97dc68198c39f425d13df0d8e3c40c5a58 10.93.84.53:7004 slave 5ac973bceab0d486c497345fe884ff54d1bb225a 0 1507806791940 5 connected 5ac973bceab0d486c497345fe884ff54d1bb225a 10.93.84.53:7001 master - 0 1507806788937 2 connected 5461-10922 a92a81532b63652bbd862be6f19a9bd8832e5e05 10.93.84.53:7005 slave cc46a4a1c0ec3f621b6b5405c6c10b7cffe73932 0 1507806790939 6 connected cc46a4a1c0ec3f621b6b5405c6c10b7cffe73932 10.93.84.53:7002 master - 0 1507806789937 3 connected 10923-16383 6346ae8c7af7949658619fcf4021cc7aca454819 10.93.84.53:7000 myself,slave 92f62ec93a0550d962f81213ca7e9b3c9c996afd 0 0 1 connected 92f62ec93a0550d962f81213ca7e9b3c9c996afd 10.93.84.53:7003 master - 0 1507806792941 8 connected 0-5460
原理總結:
redis cluster在設計的時候,就考慮到了去中心化,去中間件,也就是說,集羣中的每一個節點都是平等的關係,都是對等的,每一個節點都保存各自的數據和整個集羣的狀態。每一個節點都和其餘全部節點鏈接,並且這些鏈接保持活躍,這樣就保證了咱們只須要鏈接集羣中的任意一個節點,就能夠獲取到其餘節點的數據。
Redis集羣沒有並使用傳統的一致性哈希來分配數據,而是採用另一種叫作哈希槽(hash slot)的方式來分配的,一致性哈希對向集羣中新增和刪除實例的支持很好,可是哈希槽對向集羣新增實例或者刪除實例的話,須要額外的操做,須要手動的將slot從新平均的分配到新集羣的實例中。
redis cluster 默認分配了 16384 個slot,當咱們set一個key時,會用CRC16算法來取模獲得所屬的slot,而後將這個key分到哈希槽區間的節點上,具體算法就是:CRC16(key)%16384。 Redis 集羣會把數據存在一個master節點,而後在這個master和其對應的salve之間進行數據同步。當讀取數據時,也根據一致性哈希算法到對應的master節點獲取數據。只有當一個master 掛掉以後,纔會啓動一個對應的salve節點,充當master。
須要注意的是:必需要3個或以上的主節點,不然在建立集羣時會失敗,而且當存活的主節點數小於總節點數的一半時,整個集羣就沒法提供服務了。