Redis(5.0) 集羣搭建

一、爲了達到redis數據庫的高可用,因此須要在單機的基礎上創建集羣,首先了解下它的集羣模式,大概有如下幾種:前端

一、主從複製

二、哨兵模式

三、Redis官方提供的Cluster集羣模式(服務端)

四、Jedis sharding集羣(客戶端sharding)

五、利用中間件代理,好比豌豆莢的codis等
複製代碼

二、簡單分析一下原理以及優缺點java

2.一、主從複製(Master-Slave Replication):node

主從複製原理:nginx

  • 從服務器鏈接主服務器,發送SYNC命令;redis

  • 主服務器接收到SYNC命名後,開始執行BGSAVE命令生成RDB文件並使用緩衝區記錄此後執行的全部寫命令;算法

  • 主服務器BGSAVE執行完後,向全部從服務器發送快照文件,並在發送期間繼續記錄被執行的寫命令;數據庫

  • 從服務器收到快照文件後丟棄全部舊數據,載入收到的快照;後端

  • 主服務器快照發送完畢後開始向從服務器發送緩衝區中的寫命令;緩存

  • 從服務器完成對快照的載入,開始接收命令請求,並執行來自主服務器緩衝區的寫命令;(從服務器初始化完成)ruby

  • 主服務器每執行一個寫命令就會向從服務器發送相同的寫命令,從服務器接收並執行收到的寫命令(從服務器初始化完成後的操做)

  • 一個master能夠擁有多個slave,可是一個slave只能對應一個master

優勢:

  • 支持主從複製,主機會自動將數據同步到從機,能夠進行讀寫分離
  • 爲了分載Master的讀操做壓力,Slave服務器能夠爲客戶端提供只讀操做的服務,寫服務仍然必須由Master來完成
  • Slave一樣能夠接受其它Slaves的鏈接和同步請求,這樣能夠有效的分載Master的同步壓力。
  • Master Server是以非阻塞的方式爲Slaves提供服務。因此在Master-Slave同步期間,客戶端仍然能夠提交查詢或修改請求。
  • Slave Server一樣是以非阻塞的方式完成數據同步。在同步期間,若是有客戶端提交查詢請求,Redis則返回同步以前的數據

缺點:

  • Redis不具有自動容錯和恢復功能,主機從機的宕機都會致使前端部分讀寫請求失敗,須要等待機器重啓或者手動切換前端的IP才能恢復。
  • 主機宕機,宕機前有部分數據未能及時同步到從機,切換IP後還會引入數據不一致的問題,下降了系統的可用性。
  • Redis較難支持在線擴容,在集羣容量達到上限時在線擴容會變得很複雜。

2.二、哨兵模式:

當主服務器中斷服務後,能夠將一個從服務器升級爲主服務器,以便繼續提供服務,可是這個過程須要人工手動來操做。 爲此,Redis 2.8中提供了哨兵工具來實現自動化的系統監控和故障恢復功能。

哨兵的做用就是監控Redis系統的運行情況。它的功能包括如下兩個。

(1)監控主服務器和從服務器是否正常運行。 
(2)主服務器出現故障時自動將從服務器轉換爲主服務器。
複製代碼

哨兵的工做方式:

  • 每一個Sentinel(哨兵)進程以每秒鐘一次的頻率向整個集羣中的Master主服務器,Slave從服務器以及其餘Sentinel(哨兵)進程發送一個 PING 命令。
  • 若是一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel(哨兵)進程標記爲主觀下線(SDOWN)
  • 若是一個Master主服務器被標記爲主觀下線(SDOWN),則正在監視這個Master主服務器的全部 Sentinel(哨兵)進程要以每秒一次的頻率確認Master主服務器的確進入了主觀下線狀態
  • 當有足夠數量的 Sentinel(哨兵)進程(大於等於配置文件指定的值)在指定的時間範圍內確認Master主服務器進入了主觀下線狀態(SDOWN), 則Master主服務器會被標記爲客觀下線(ODOWN)
  • 在通常狀況下, 每一個 Sentinel(哨兵)進程會以每 10 秒一次的頻率向集羣中的全部Master主服務器、Slave從服務器發送 INFO 命令。
  • 當Master主服務器被 Sentinel(哨兵)進程標記爲客觀下線(ODOWN)時,Sentinel(哨兵)進程向下線的 Master主服務器的全部 Slave從服務器發送 INFO 命令的頻率會從 10 秒一次改成每秒一次。
  • 若沒有足夠數量的 Sentinel(哨兵)進程贊成 Master主服務器下線, Master主服務器的客觀下線狀態就會被移除。若 Master主服務器從新向 Sentinel(哨兵)進程發送 PING 命令返回有效回覆,Master主服務器的主觀下線狀態就會被移除。

優勢:

  • 哨兵模式是基於主從模式的,全部主從的優勢,哨兵模式都具備。
  • 主從能夠自動切換,系統更健壯,可用性更高。

缺點:

  • Redis較難支持在線擴容,在集羣容量達到上限時在線擴容會變得很複雜。

2.三、Redis官方 Cluster集羣模式

redis的哨兵模式基本已經能夠實現高可用,讀寫分離 ,可是在這種模式下每臺redis服務器都存儲相同的數據,很浪費內存,因此在redis3.0上加入了cluster模式,實現的redis的分佈式存儲,也就是說每臺redis節點上存儲不一樣的內容。

Redis-Cluster採用無中心結構,它的特色以下:

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

  • 節點的fail是經過集羣中超過半數的節點檢測失效時才生效。

  • 客戶端與redis節點直連,不須要中間代理層.客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可。

工做方式:

在redis的每個節點上,都有這麼兩個東西,一個是插槽(slot),它的的取值範圍是:0-16383。還有一個就是cluster,能夠理解爲是一個集羣管理的插件。當咱們的存取的key到達的時候,redis會根據crc16的算法得出一個結果,而後把結果對 16384 求餘數,這樣每一個 key 都會對應一個編號在 0-16383 之間的哈希槽,經過這個值,去找到對應的插槽所對應的節點,而後直接自動跳轉到這個對應的節點上進行存取操做。

爲了保證高可用,redis-cluster集羣引入了主從模式,一個主節點對應一個或者多個從節點,當主節點宕機的時候,就會啓用從節點。當其它主節點ping一個主節點A時,若是半數以上的主節點與A通訊超時,那麼認爲主節點A宕機了。若是主節點A和它的從節點A1都宕機了,那麼該集羣就沒法再提供服務了。

2.四、Jedis sharding集羣

Redis Sharding能夠說是在Redis cluster出來以前業界廣泛的採用方式,其主要思想是採用hash算法將存儲數據的key進行hash散列,這樣特定的key會被定爲到特定的節點上。

慶幸的是,Java Redis客戶端驅動Jedis已支持Redis Sharding功能,即ShardedJedis以及結合緩存池的ShardedJedisPool

Jedis的Redis Sharding實現具備以下特色:

  • 採用一致性哈希算法,將key和節點name同時hashing,而後進行映射匹配,採用的算法是MURMUR_HASH。採用一致性哈希而不是採用簡單相似哈希求模映射的主要緣由是當增長或減小節點時,不會產生因爲從新匹配形成的rehashing。一致性哈希隻影響相鄰節點key分配,影響量小。
  • 爲了不一致性哈希隻影響相鄰節點形成節點分配壓力,ShardedJedis會對每一個Redis節點根據名字(沒有,Jedis會賦予缺省名字)會虛擬化出160個虛擬節點進行散列。根據權重weight,也可虛擬化出160倍數的虛擬節點。用虛擬節點作映射匹配,能夠在增長或減小Redis節點時,key在各Redis節點移動再分配更均勻,而不是隻有相鄰節點受影響。
  • ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag作sharding,這樣經過合理命名key,能夠將一組相關聯的key放入同一個Redis節點,這在避免跨節點訪問相關數據時很重要。 固然,Redis Sharding這種輕量靈活方式必然在集羣其它能力方面作出妥協。好比擴容,當想要增長Redis節點時,儘管採用一致性哈希,畢竟仍是會有key匹配不到而丟失,這時須要鍵值遷移。 做爲輕量級客戶端sharding,處理Redis鍵值遷移是不現實的,這就要求應用層面容許Redis中數據丟失或從後端數據庫從新加載數據。但有些時候,擊穿緩存層,直接訪問數據庫層,會對系統訪問形成很大壓力。

2.五、利用中間件代理 中間件的做用是將咱們須要存入redis中的數據的key經過一套算法計算得出一個值。而後根據這個值找到對應的redis節點,將這些數據存在這個redis的節點中。

經常使用的中間件有這幾種

  • Twemproxy
  • Codis
  • nginx

三、幾種集羣模式大概有了瞭解,如今搭建開始集羣

因爲我使用了redis5.0, 搭建過程當中也是遇到了一個坑,redis5.0使用redis-cli做爲建立集羣的命令,使用c語言實現,再也不使用ruby語言,redis3.0使用redis-trib.rb建立集羣,且須要安裝ruby。

gcc的環境以前已經安裝過了,如今不須要處理,直接下一步。 3.一、將以前安裝好的redis文件,複製到一個新的文件夾redis-cluster下 ,並在新文件夾下複製成6份。

注意要將.rdb和.aof後綴的持久化文件刪除,若是有的話。

這裏就不考慮3.0 的搭建方式了

3.二、將六個節點的redis.conf配置文件按照以下進行修改

若是是同一臺主機的話,端口必須不一樣。不一樣主機能夠相同。 我這裏使用同一臺主機,端口:7001-7006。

daemonize yes

port **** #配置本身的節點端口

cluster-enabled yes # 開啓集羣
複製代碼

3.3啓動、關閉腳本

啓動腳本:

cd redis1
./src/redis-server redis.conf
cd ..
cd redis2
./src/redis-server redis.conf
cd ..
cd redis3
./src/redis-server redis.conf
cd ..
cd redis4
./src/redis-server redis.conf
cd ..
cd redis5
./src/redis-server redis.conf
cd ..
cd redis6
./src/redis-server redis.conf
cd ..

複製代碼

關閉腳本:

./redis1/redis-cli -p 7001 shutdown
./redis1/redis-cli -p 7002 shutdown
./redis1/redis-cli -p 7003 shutdown
./redis1/redis-cli -p 7004 shutdown
./redis1/redis-cli -p 7005 shutdown
./redis1/redis-cli -p 7006 shutdown

複製代碼

3.四、修改權限

chmod 777 start-all.sh stop-all.sh
複製代碼

3.五、啓動節點

./start-all.sh

# 查看redis進程
ps -aux | grep redis
複製代碼

3.六、建立集羣

redis-cli --cluster create  192.0.0.179:7001 192.0.0.179:7002 192.0.0.179:7003 192.0.0.179:7004 192.0.0.179:7005 192.0.0.179:7006 --cluster-replicas 1
複製代碼

能夠看到6個節點配分配成3個主節點,3個從節點。

3.七、查詢集羣信息

集羣建立成功登錄任意redis結點查詢集羣中的節點狀況。

客戶端以集羣方式登錄:

redis-cli -c -h 192.0.0.179 -p 7001
#其中-c表示以集羣方式鏈接redis,-h指定ip地址,-p指定端口號
複製代碼

查詢集羣結點信息:

cluster nodes
複製代碼

3.八、測試

192.0.0.179:7001> set a 123456
-> Redirected to slot [15495] located at 192.0.0.179:7003
OK
192.0.0.179:7003> get a
"123456"
192.0.0.179:7003> get a
"123456"
192.0.0.179:7003> set b 44444444
-> Redirected to slot [3300] located at 192.0.0.179:7001
OK
192.0.0.179:7001> get b
"44444444"
192.0.0.179:7001> 

複製代碼

能夠看到redis 集羣會根據計算爲咱們分配hash槽,以分配不一樣的節點

3.九、使用jedis鏈接

package com.pc.jedis.test;
 
import java.util.HashSet;
import java.util.Set;
 
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
 

public class JedisClusterTest {
    public static void main(String[] args) {
        // 建立並填充節點信息
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("192.0.0.179", 7001));
        nodes.add(new HostAndPort("192.0.0.179", 7002));
        nodes.add(new HostAndPort("192.0.0.179", 7003));
        nodes.add(new HostAndPort("192.0.0.179", 7004));
        nodes.add(new HostAndPort("192.0.0.179", 7005));
        nodes.add(new HostAndPort("192.0.0.179", 7006));
 
        // 建立JedisCluster對象
        JedisCluster jedisCluster = new JedisCluster(nodes);
 
        // 使用jedisCluster操做redis
        String key = "clusterTest";
        String setResult = jedisCluster.set(key, "redis集羣搭建");
        System.out.println(setResult);
 
        String getResult = jedisCluster.get(key);
        System.out.println(getResult);
 
        // 關閉jedisCluster(程序執行完後才能關閉,內部封裝了鏈接池)
        jedisCluster.close();
    }
}
複製代碼
相關文章
相關標籤/搜索