高性能網站架構設計之緩存---redis集羣搭建

1、關於redis  clusterhtml

集羣技術是構建高性能網站架構的重要手段,在網站承受高併發訪問壓力的同時,還須要從海量數據中查詢出知足條件的數據,並快速響應,咱們必然想到的是將數據進行切片,把數據根據某種規則放入多個不一樣的服務器節點,來下降單節點服務器的壓力。node

我部署的redis集羣主要是利用切片技術來組建的集羣。web

集羣要實現的目的是要將不一樣的 key 分散放置到不一樣的 redis 節點,這裏咱們須要一個規則或者算法,一般的作法是獲取 key 的哈希值,而後根據節點數來求模,但這種作法有其明顯的弊端,當咱們須要增長或減小一個節點時,會形成大量的 key 沒法命中,這種比例是至關高的,因此就有人提出了一致性哈希的概念。redis

Redis 引入另外一種哈希槽(hash slot)的概念。算法

Redis 集羣中內置了 16384 個哈希槽,當須要在 Redis 集羣中放置一個 key-value 時,redis 先對 key 使用 crc16 算法算出一個結果,而後把結果對 16384 求餘數,這樣每一個 key 都會對應一個編號在 0-16383 之間的哈希槽,redis 會根據節點數量大體均等的將哈希槽映射到不一樣的節點。shell

使用哈希槽的好處就在於能夠方便的添加或移除節點。c#

當須要增長節點時,只須要把其餘節點的某些哈希槽挪到新節點就能夠了;ruby

當須要移除節點時,只須要把移除節點上的哈希槽挪到其餘節點就好了;服務器

1,redis cluster的現狀架構

目前redis支持的cluster特性:

1):節點自動發現

2):slave->master 選舉,集羣容錯

3):Hot resharding:在線分片

4):進羣管理:cluster xxx

5):基於配置(nodes-port.conf)的集羣管理

6):ASK 轉向/MOVED 轉向機制.

2,redis cluster 架構

架構細節:

(1)全部的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.

(2)節點的fail是經過集羣中超過半數的節點檢測失效時才生效.

(3)客戶端與redis節點直連,不須要中間proxy層.客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可

(4)redis-cluster把全部的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value

3,redis-cluster選舉:容錯

(1)領着選舉過程是集羣中全部master參與,若是半數以上master節點與master節點通訊超過(cluster-node-timeout),認爲當前master節點掛掉.

(2):何時整個集羣不可用(cluster_state:fail),當集羣不可用時,全部對集羣的操做作都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤

    a:若是集羣任意master掛掉,且當前master沒有slave.集羣進入fail狀態,也能夠理解成進羣的slot映射[0-16383]不完成時進入fail狀態.

    b:若是進羣超過半數以上master掛掉,不管是否有slave集羣進入fail狀態.

2、redis  cluster搭建

1,安裝redis-cluster依賴

(1)確保系統安裝zlib,不然gem install會報(no such file to load -- zlib)

(2)安裝ruby

  yum install  –y ruby ruby-rdoc ruby-rvm

  yum erase ruby ruby-libs ruby-mode ruby-rdoc ruby-irb ruby-ri ruby-docs

(3)安裝rubygem

  yum install rubygems 或

  1. # rubygems-1.8.16.tgz  

  2. cd /path/gem  

  3. sudo ruby setup.rb  

  4. sudo cp bin/gem /usr/local/bin

 (4)安裝gem-redis

  gem install redis --version 3.0.0

   #因爲源的緣由,可能下載失敗,就手動下載下來安裝  

   #download地址:http://rubygems.org/gems/redis/versions/3.0.0   

  gem install -l /data/soft/redis-3.0.0.gem  

2,安裝redis-cluster

  1. cd /path/redis  

  2. make  

  3. sudo cp redis-server /usr/local/bin  

  4. sudo cp redis-cli /usr/local/bin  

  5. sudo cp redis-trib.rb /usr/local/bin  

3,配置redis-cluster

(1) 配置redis文件結構

image.png

使用包含(include)把通用配置和特殊配置分離,方便維護.

(2)redis通用配置

============================================================================

#GENERAL 
daemonize yes
tcp-backlog 511 
timeout 0 
tcp-keepalive 0 
loglevel notice 
databases 16 
dir /data/webserver/redis/data 
slave-serve-stale-data yes 
#slave只讀 
slave-read-only yes 
#not use default 
repl-disable-tcp-nodelay yes 
slave-priority 100 
#打開aof持久化 
appendonly yes 
#每秒一次aof寫 
appendfsync everysec 
#關閉在aof rewrite的時候對新的寫操做進行fsync 
no-appendfsync-on-rewrite yes 
auto-aof-rewrite-min-size 64mb 
lua-time-limit 5000 
#打開redis集羣 
cluster-enabled yes 
#節點互連超時的閥值 
cluster-node-timeout 15000 
cluster-migration-barrier 1 
slowlog-log-slower-than 10000 
slowlog-max-len 128 
notify-keyspace-events "" 
hash-max-ziplist-entries 512 
hash-max-ziplist-value 64 
list-max-ziplist-entries 512 
list-max-ziplist-value 64 
set-max-intset-entries 512 
zset-max-ziplist-entries 128 
zset-max-ziplist-value 64 
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 
aof-rewrite-incremental-fsync yes

================================================================

(3)redis特殊配置

================================================================

#包含通用配置 
include /data/webserver/redis/conf/redis-common.conf 
#日誌PID
logfile /data/webserver/redis/logs/redis_6380.log
pidfile /data/webserver/redis/pids/redis_6380.pid
#監聽tcp端口 
port 6380
bind 10.161.180.111
#最大可用內存 
maxmemory 2G 
#內存耗盡時採用的淘汰策略: 
# volatile-lru -> remove the key with an expire set using an LRU algorithm 
# allkeys-lru -> remove any key accordingly to the LRU algorithm 
# volatile-random -> remove a random key with an expire set 
# allkeys-random -> remove a random key, any key 
# volatile-ttl -> remove the key with the nearest expire time (minor TTL) 
# noeviction -> don't expire at all, just return an error on write operations 
maxmemory-policy allkeys-lru 
#aof存儲文件 
appendfilename "appendonly-6380.aof" 
#rdb文件,只用於動態添加slave過程 
dbfilename dump-6380.rdb 
#cluster配置文件(啓動自動生成) 
cluster-config-file nodes-6380.conf 
#部署在同一機器的redis實例,把<span style="font-size: 1em; line-height: 1.5;">auto-aof-rewrite搓開,防止瞬間fork全部redis進程作rewrite,佔用大量內存</span> 
auto-aof-rewrite-percentage 80-100

================================================================,

由於咱們要啓動多個 redis 實例,雖然能夠直接經過命令行來啓動,但始終是不怎麼方便的,因此咱們按端口號分別創建實例目錄,在實例目錄裏面建立redis特殊配置文件

(4)初始化並構建集羣

分別啓動實例,./redis-server ./6380/redis-6380.conf

使用自帶的ruby工具(redis-trib.rb)構建集羣   redis-trib.rb create --replicas 0 10.161.180.111:6380 10.161.180.111:6381 10.161.180.111:6382

須要注意的是執行 redis-trib.rb 命令須要 ruby 的支持,若是你沒有安裝能夠先到 https://rubygems.org/gems/redis 下載,而後離線安裝。

sudo gem install redis-3.0.7.gem --local

檢查集羣狀態

  1. #redis-trib.rb的check子命令構建  

  2. #ip:port能夠是集羣的任意節點  

  3. redis-trib.rb check 10.161.180.111 :6380

最後輸出以下信息,沒有任何警告或錯誤,表示集羣啓動成功並處於ok狀態

  1. [OK] All nodes agree about slots configuration.  

  2. >>> Check for open slots...  

  3. >>> Check slots coverage...  

  4. [OK] All 16384 slots covered.

下面咱們用 redis 自帶的客戶端測試一下:

image.png

能夠看到,雖然咱們第一次鏈接的是6380端口,當咱們去獲取 testkey001 的時候,redis cluster 自動幫咱們重定向到 6382 。

當咱們在 6382設置 testkey002 時,redis cluster 又重定向到 6380 。總的來講, redis 集羣部署起來仍是很是方便的.

(5)添加新master節點

redis-trib.rb add-node 10.168.228.78:6383 10.161.180.111:6380

add-node  將一個節點添加到集羣裏面, 第一個是新節點ip:port, 第二個是任意一個已存在節點ip:port

檢查一下新節點是否已經加入:image.png

node:新節點沒有包含任何數據, 由於它沒有包含任何slot。新加入的節點是一個主節點, 當集羣須要將某個從節點升級爲新的主節點時, 這個新節點不會被選中。

所以須要爲新節點分配slot

  1. redis-trib.rb reshard 10.161.180.111:6383  

  2. #根據提示選擇要遷移的slot數量(ps:這裏選擇500)  

  3. How many slots do you want to move (from 1 to 16384)? 500  

  4. #選擇要接受這些slot的node-id  

  5. What is the receiving node ID? f51e26b5d5ff74f85341f06f28f125b7254e61bf  

  6. #選擇slot來源:  

  7. #all表示從全部的master從新分配,  

  8. #或者數據要提取slot的master節點id,最後用done結束  

  9. Please enter all the source node IDs.  

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

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

  12. Source node #1:all  

  13. #打印被移動的slot後,輸入yes開始移動slot以及對應的數據.  

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

  15. #結束  

(6)添加新的slave節點

redis-cli鏈接上新節點shell,輸入命令:cluster replicate 對應master的node-id

或者執行redis-trib.rb命令,以下:

redis-trib.rb add-node --slave 10.168.228.78:7382 10.161.180.111:6382

(7)在線reshard 數據

對於負載/數據均勻的狀況,能夠在線reshard slot來解決,方法與添加新master的reshard同樣,只是須要reshard的master節點是老節點.

redis-trib.rb reshard 10.161.180.111:6380

(8)刪除節點

刪除一個slave節點:

  1. #redis-trib del-node ip:port '<node-id>'  

  2. redis-trib.rb del-node 10.168.228.78:7386 'c7ee2fca17cb79fe3c9822ced1d4f6c5e169e378'  

刪除一個master節點:

刪除master節點以前首先要使用reshard移除master的所有slot,而後再刪除當前節點(目前只能把被刪除master的slot遷移到一個節點上)

  1. #把10.161.180.111:6383當前master遷移到10.161.180.111:6380上  

  2. redis-trib.rb reshard 10.161.180.111:6383  

  3. #根據提示選擇要遷移的slot數量(ps:這裏選擇500)  

  4. How many slots do you want to move (from 1 to 16384)? 500(被刪除master的全部slot數量)  

  5. #選擇要接受這些slot的node-id(10.161.180.111:6380)  

  6. What is the receiving node ID? c4a31c852f81686f6ed8bcd6d1b13accdc947fd2 (ps:10.161.180.111:6380的node-id)  

  7. Please enter all the source node IDs.  

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

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

  10. Source node #1:f51e26b5d5ff74f85341f06f28f125b7254e61bf(被刪除master的node-id)  

  11. Source node #2:done  

  12. #打印被移動的slot後,輸入yes開始移動slot以及對應的數據.  

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

刪除空master節點:

redis-trib.rb del-node 10.161.180.111:6383 'f51e26b5d5ff74f85341f06f28f125b7254e61bf'

目前c#客戶端還不能很好的支持 redis 集羣,下一篇將介紹如何使用代理來實現 redis 集羣。

相關文章
相關標籤/搜索