您好,登錄后才能下訂單哦!
今天小編給大家分享一下Redis高可用架構如何搭建的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
在理解集群架構前,先要介紹一下redis的持久化機制,因為在后面的集群中會涉及到持久化。redis持久化是將緩存在內存中的數據根據一些規則進行落盤,以防止在redis服務宕機時可以進行數據恢復或者是集群架構中進行主從節點數據同步。redis持久化的方式有RDB和AOF兩種,在4.0版本后新出了混合持久化模式。
RDB是redis默認開啟的持久化機制,其持久化方式是按照用戶配置的規則"X秒內至少發生過Y次改動"
,生成快照并落盤到dump.rdb二進制文件中。默認情況下,redis配置了三種,分別為900秒內至少發生過1次緩存key的改動,300秒內至少發生過10次緩存key的改動以及60秒內至少發生過10000次改動。
除了redis自動快照持久化數據外,還有兩個命令可以幫助我們手動進行內存數據快照,這兩個命令分別為save
和bgsave
。
save:以同步的方式進行數據快照,當緩存數據量大,會阻塞其他命令的執行,效率不高。
bgsave:以異步的方式進行數據快照,有redis主線程fork出一個子進程來進行數據快照,不會阻塞其他命令的執行,效率較高。由于是采用異步快照的方式,那么就有可能發生在快照的過程中,有其他命令對數據進行了修改。為了避免這個問題reids采用了寫時復制(Cpoy-On-Write)的方式,因為此時進行快照的進程是由主線程fork出來的,所以享有主線程的資源,當快照過程中發生數據改動時,那么該數據會被復制一份并生成副本數據,子進程會將改副本數據寫入到dump.rdb文件中。
RDB快照是以二進制的方式進行存儲的,所以在數據恢復時,速度會比較快,但是它存在數據丟失的風險。假如設置的快照規則為60秒內至少發生100次數據改動,那么在50秒時,redis服務由于某種原因突然宕機了,那在這50秒內的所有數據將會丟失。
AOF是Redis的另一種持久化方式,與RDB不同時是,AOF記錄著每一條更改數據的命令并保存到磁盤下的appendonly.aof文件中,當redis服務重啟時,會加載該文將并再次執行文件中保存的命令,從而達到數據恢復的效果。默認情況下,AOF是關閉的,可以通過修改conf配置文件來進行開啟。
AOF提供了三種方式,可以讓命令保存到磁盤。默認情況下,AOF采用 開啟AOF后需要重新啟動redis服務,當再次執行相關改寫命令時,aof文件中會記錄操作的命令。 # appendonly no 關閉AOF持久化
appendonly yes # 開啟AOF持久化
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof" # 持久化文件名
appendfsync everysec
的方式進行命令持久化。appendfsync always #每次有新的改寫命令時,都會追加到磁盤的aof文件中。數據安全性最高,但效率最慢。
appendfsync everysec # 每一秒,都會將改寫命令追加到磁盤中的aof文件中。如果發生宕機,也只會丟失1秒的數據。
appendfsync no #不會主動進行命令落盤,而是由操作系統決定什么時候寫入到磁盤。數據安全性不高。
相對于RDB,雖然AOF的數據安全性更高,但是隨著服務的持續運行,aof的文件也會越來越大,等到下次恢復數據時,速度會越來越慢。如果RDB和AOF都開啟,在恢復數據時,redis會優先選擇AOF,畢竟AOF丟失的數據更少啊。
RDB | AOF | |
---|---|---|
恢復效率 | 高 | 低 |
數據安全性 | 低 | 高 |
空間占用 | 低 | 高 |
由于RDB持久化方式容易造成數據丟失,AOF持久化方式數據恢復較慢,所以在redis4.0版本后,新出來混合持久化模式。混合持久化將RDB和AOF的優點進行了集成,并而且依賴于AOF,所以在使用混合持久化前,需要開啟AOF。在開啟混合持久化后,當發生AOF重寫時,會將內存中的數據以RDB的數據格式保存到aof文件中,在下一次的重寫之前,混合持久化會追加保存每條改寫命令到aof文件中。當需要恢復數據時,會加載保存的rdb內容數據,然后再繼續同步aof指令。
AOF重寫是指當aof文件越來越大時,redis會自動優化aof文件中無用的命令,從而減少文件體積。比如在處理文章閱讀量時,每查看一次文章就會執行一次Incr命令,但是隨著閱讀量的不斷增加,aof文件中的incr命令也會積累的越來越多。在AOF重寫后,將會刪除這些沒用的Incr命令,將這些命令直接替換為set key value命令。除了redis自動重寫AOF,如果需要,也可以通過 # AOF重寫配置,當aof文件達到60MB并且比上次重寫后的體量多100%時自動觸發AOF重寫 auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes # 開啟混合持久化# aof-use-rdb-preamble no # 關閉混合持久化
bgrewriteaof
命令手動觸發。
在生產環境中,一般不會直接配置單節點的redis服務,這樣壓力太大。為了緩解redis服務壓力,可以搭建主從復制,做讀寫分離。redis主從復制,是有一個主節點Master和多個從節點Slave組成。主從節點間的數據同步只能是單向傳輸的,只能由Master節點傳輸到Slave節點。
準備三臺linux服務器,其中一臺作為redis的主節點,兩臺作為reids的從節點。如果沒有足夠的機器可以在同一臺機器上面將redis文件多復制兩份并更改端口號,這樣可以搭建一個偽集群。
IP | 主/從節點 | 端口 | 版本 |
---|---|---|---|
192.168.36.128 | 主 | 6379 | 5.0.14 |
192.168.36.130 | 從 | 6379 | 5.0.14 |
192.168.36.131 | 從 | 6379 | 5.0.14 |
配置從節點36.130,36.131機器中reids.conf
修改redis.conf文件中的replicaof,配置主節點的ip和端口號,并且開啟從節點只讀。
啟動主節點36.128機器中reids服務
./src/redis-server redis.conf
3. 依次啟動從節點36.130,36.131機器中的redis服務
./src/redis-server redis.conf
啟動成功后可以看到日志中顯示已經與Master節點建立的連接。如果出現與Master節點的連接被拒,那么先檢查Master節點的服務器是否開啟防火墻,如果開啟,可以開放6379端口或者關閉防火墻。如果防火墻被關閉但連接仍然被拒,那么可以修改Master節點服務中的redis.conf文件。將bing 127.0.0.1修改為本機對外的網卡ip或者直接注釋掉即可,然后重啟服務器即可。
查看狀態
全部節點啟動成功后,Master節點可以查看從節點的連接狀態,offset偏移量等信息。
info replication # 主節點查看連接信息
全量數據同步主從節點之間的數據同步是通過建立socket長連接來進行傳輸的。當Slave節點啟動時,會與Master節點建立長連接,并且發送psync同步數據命令。當Master節點收到psync命令時,會執行pgsave進行rdb內存數據快照(這里的rdb快照與conf文件中是否開啟rdb無關),如果在快照過程中有新的改寫命令,那么Master節點會將這些命令保存到repl buffer緩沖區中。當快照結束后,會將rdb傳輸給Slave節點。Slave節點在接收到rdb后,如果存在舊數據,那么會將這些舊數據清除并加載rdb。加載完成后會接受master緩存在repl buffer中的新命令。在這些步驟全部執行完成后,主從節點已經算連接成功了,后續Master節點的命令會不斷的發送到Slave節點。如果在高并發的情況下,可能會存在數據延遲的情況。
部分數據同步
部分數據同步發生在Slave節點發生宕機,并且在短時間內進行了服務恢復。短時間內主從節點之間的數據差額不會太大,如果執行全量數據同步將會比較耗時。部分數據同步時,Slave會向Master節點建立socket長連接并發送帶有一個offset偏移量的數據同步請求,這個offset可以理解數據同步的位置。Master節點在收到數據同步請求后,會根據offset結合buffer緩沖區內新的改寫命令進行位置確定。如果確定了offset的位置,那么就會將這個位置往后的所有改寫命令發送到Slave節點。如果沒有確定offset的位置,那么會再次執行全量數據同步。比如,在Slave節點沒有宕機之前命令已經同步到了offset=11這個位置,當該節點重啟后,向Master節點發送該offset,Master根據offset在緩沖區中進行定位,在定位到11這個位置后,將該位置往后的所有命令發送給Slave。在數據同步完成后,后續Master節點的命令會不斷的發送到該Slave節點
優點
可以實現一主多從,讀寫分離,減輕Master節點讀操作壓力
是哨兵,集群架構的基礎
缺點
不具備自動主從切換功能,當Master節點宕機后,需要手動切換主節點
容易出現數據不一致,當Master節點宕機前,如果有數據未同步,則會造成數據丟失
哨兵模式對主從復制進行了進一步優化,獨立出單獨的哨兵進程用于監控主從架構中的服務器狀態,一旦發生宕機,哨兵會在短時間內選舉出新的Master節點并進行主從切換。不僅如此,在多哨兵的節點下,每個哨兵都會相互進行監控,監控哨兵節點是否宕機。
IP | 主/從節點 | 端口 | 哨兵端口 | 版本 |
---|---|---|---|---|
192.168.36.128 | 主 | 6379 | 26379 | 5.0.14 |
192.168.36.130 | 從 | 6379 | 26379 | 5.0.14 |
192.168.36.131 | 從 | 6379 | 26379 | 5.0.14 |
主從復制是哨兵模式的基礎,所以在搭建哨兵前需要完成主從復制的配置。在搭建完主從后,哨兵的搭建就容易很多。
找到安裝目錄下的sentinel.conf
文件并進行修改。主要修改兩個地方,分別為哨兵端口port和監控的主節點ip地址和端口號。
在配置完成后,可以使用命令啟動各機器的哨兵服務。啟動成功后,可查看redis服務和哨兵服務的進行信息。
搭建成功后,就來通過代碼演示主節點宕機的情況下,哨兵是否會幫助系統自動進行主備切換。在springboot項目中引入對應的pom,并配置對應的redis哨兵信息。
當啟動服務后,通過節后向后端傳遞數據,可以看到輸出的日志,表示redis哨兵集群已經可以正常運行了。那么這個時候kill掉36.128機器上的主節點,模擬服務宕機。通過日志可以知道,服務出現異常了,在過十幾秒發現哨兵已經自動幫系統進行了主從切換,并且服務也可以正常訪問了。<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.2.2.RELEASE</version></dependency><dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version></dependency>
server:
port: 8081spring:
redis:
sentinel:
master: mymaster # 主服務節點
nodes: 192.168.36.128:26379,192.168.36.130:26379,192.168.36.131:26379 #哨兵節點
timeout: 3000 #連接超時時間
@Slf4j
@RestController
public class RedisTest {
@Resource
private StringRedisTemplate stringRedisTemplate;
/*
* 每秒鐘向redis中寫入數據,中途kill掉主節點進程,模擬宕機
*/
@GetMapping("/redis/testSet")
public void test(@RequestParam(name = "key") String key,
@RequestParam(name = "value") String value) throws InterruptedException {
int idx=0;
for(;;){
try {
idx++;
stringRedisTemplate.opsForValue().set(key+idx, value);
log.info("=====存儲成功:{},{}=====",key+idx,value);
}catch (Exception e){
log.error("====連接redis服務器失敗:{}====",e.getMessage());
}
Thread.sleep(1000);
}
}
}
2022-11-14 22:20:23.134 INFO 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : =====存儲成功:test14,123=====
2022-11-14 22:20:24.142 INFO 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : =====存儲成功:test15,123=====
2022-11-14 22:20:24.844 INFO 8764 --- [xecutorLoop-1-1] i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was /192.168.36.128:6379
2022-11-14 22:20:26.909 WARN 8764 --- [ioEventLoop-4-4] i.l.core.protocol.ConnectionWatchdog : Cannot reconnect to [192.168.36.128:6379]: Connection refused: no further information: /192.168.36.128:6379
2022-11-14 22:20:28.165 ERROR 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : ====連接redis服務器失敗:Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 3 second(s)====
2022-11-14 22:20:31.199 INFO 8764 --- [xecutorLoop-1-1] i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was 192.168.36.128:6379
2022-11-14 22:20:52.189 ERROR 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : ====連接redis服務器失敗:Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 3 second(s)====
2022-11-14 22:20:53.819 WARN 8764 --- [ioEventLoop-4-2] i.l.core.protocol.ConnectionWatchdog : Cannot reconnect to [192.168.36.128:6379]: Connection refused: no further information: /192.168.36.128:6379
2022-11-14 22:20:56.194 ERROR 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : ====連接redis服務器失敗:Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 3 second(s)====
2022-11-14 22:20:57.999 INFO 8764 --- [xecutorLoop-1-2] i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was 192.168.36.128:6379
2022-11-14 22:20:58.032 INFO 8764 --- [ioEventLoop-4-4] i.l.core.protocol.ReconnectionHandler : Reconnected to 192.168.36.131:6379
2022-11-14 22:20:58.040 INFO 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : =====存儲成功:test24,123=====
2022-11-14 22:20:59.051 INFO 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : =====存儲成功:test25,123=====
2022-11-14 22:21:00.057 INFO 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : =====存儲成功:test26,123=====
2022-11-14 22:21:01.065 INFO 8764 --- [nio-8081-exec-2] com.gz.redis.RedisTest : =====存儲成功:test27,123=====
在多個哨兵的模式下,每個哨兵都會向redis節點發送心跳包來檢測節點的運行狀態。如果某個哨兵發現主節點連接超時了,沒有收到心跳,那么系統并不會立刻進行故障轉移,這種情況叫做主觀下線
。如果后續的哨兵節點發現,與主節點的心跳也失敗了并且哨兵數量超過2個,那么這個時候就會認為主節點客觀下線
,并且會進行故障轉移,這個客觀下線的數值可以在哨兵的配置文件中進行配置。
登錄后復制sentinel monitor master 192.168.36.128 6378 2
在故障轉移前,需要選舉出一個哨兵leader來進行Master節點的重新選舉。哨兵的選舉過程大致可以分為三步:
當某個的哨兵確定主節點已經下線時,會像其他哨兵發送is-master-down-by-addr命令,要求將自己設為leader,并處理故障轉移工作。
其他哨兵在收到命令后,進行投票選舉
如果票數過半時,那么發送命令的哨兵節點將成為主節點,并進行故障轉移。
當選舉出主哨兵后,那么這個主哨兵就會過濾掉宕機的redis節點,重新選舉出Master節點。首先會根據redis節點的優先級進行選舉(slave-priority),數值越大的從節點將會被選舉為主節點。如果這個優先級相同,那么主哨兵節點就會選擇數據最全的從節點作為新的主節點。如果還是選舉失敗,那么就會選舉出進程id最小的從節點作為主節點。
在集群環境下會由于網絡等原因出現腦裂的情況,所謂的腦裂就是由于主節點和從節點和哨兵處于不同的網絡分區,由于網絡波動等原因,使得哨兵沒有能夠即使接收到主節點的心跳,所以通過選舉的方式選舉了一個從節點為新的主節點,這樣就存在了兩個主節點,就像一個人有兩個大腦一樣,這樣會導致客戶端還在像老的主節點那里寫入數據,新節點無法同步數據,當網絡恢復后,哨兵會將老的主節點降為從節點,這時再從新主節點同步數據,這會導致大量數據丟失。如果需要避免腦裂的問題,可以配置下面兩行信息。
min-replicas-to-write 3 # 最少從節點為3
min-replicas-max-lag 10 # 表示數據復制和同步的延遲不能超過10秒
優點:除了擁有主從復制的優點外,還可以進行故障轉移,主從切換,系統更加可靠。
缺點:故障轉移需要花費一定的時間,在高并發場景下容易出現數據丟失。不容易實現在線擴容。
哨兵模式中雖然在主節點宕機的情況下能夠做到主從切換,但是在切換的過程中需要花費十幾秒或者更久的時間,會造成部分數據的丟失。如果在并發量不高的情況下,可以使用該集群模式,但是在高并發的情況下,這十幾秒的時間可能會造成嚴重的后果,所以,在很多互聯網公司都是采用Cluster集群架構。Cluster集群中由多個redis節點組成,每個redis服務節點都有一個Master節點和多個Slave節點,在進行數據存儲時,redis會對數據的key進行hash運算并根據運算結果分配到不同的槽位。一般情況下,Cluster集群架構要設置6個節點(三主三從)。
由于只有三臺虛擬機,所以需要在每臺服務器上面搭建兩個redis服務,端口分別為6379和6380,這個剛好可以構建6個節點。
IP | 主/從節點 | 端口 | 版本 |
---|---|---|---|
192.168.36.128 | - | 6379 | 5.0.14 |
192.168.36.128 | - | 6380 | 5.0.14 |
192.168.36.130 | - | 6379 | 5.0.14 |
192.168.36.130 | - | 6380 | 5.0.14 |
192.168.36.131 | - | 6379 | 5.0.14 |
192.168.36.131 | - | 6380 | 5.0.14 |
為了看起來不是那么混亂,可以為cluster新建一個文件夾,并將redis的文件拷貝到cluster文件夾中,并修改文件夾名為redis-6379,reids-6380。
新建完成后,修改每個節點的redis.conf配置文件,找到cluster相關的配置位置,將cluster-enable更改為yes,表示開啟集群模式。開啟后,需要修改集群節點連接的超時時間cluster-node-timeout,節點配置文件名cluster-config-file等等,需要注意的是,同一臺機器上面的服務節點記得更改端口號。
在每個節點都配置完成后,可以依次啟動各節點。啟動成功后,可以查看redis的進程信息,后面有明顯的標識為[cluster]。
現在雖然每個節點的redis都已經正常啟動了,但是每個節點之間并沒有任何聯系啊。所以這個時候還需要最后一步,將各節點建立關系。在任意一臺機器上運行下面的命令-- cluster create ip:port,進行集群創建。命令執行成功后,可以看到槽位的分布情況和主從關系。
./src/redis-cli --cluster create 192.168.36.128:6379 192.168.36.128:6380 192.168.36.130:6379 192.168.36.130:6380 192.168.36.131:6379 192.168.36.131:6380 --cluster-replicas 1復制代碼
cluster成功啟動后,可以在代碼中簡單的測試一下,這里的代碼依舊采用哨兵模式中的測試代碼,只是將sentinel相關的信息注釋掉并加上cluster的節點信息即可。
spring:
redis:
cluster:
nodes: 192.168.36.128:6379,192.168.36.128:6380,192.168.36.130:6379,192.168.36.130:6380,192.168.36.131:6379,192.168.36.131:6380# sentinel:# master: mymaster# nodes: 192.168.36.128:26379,192.168.36.130:26379,192.168.36.131:26379
timeout: 3000
lettuce:
pool:
max-active: 80
min-idle: 50
Cluster模式下由于存在多個Master節點,所以在存儲數據時,需要確定將這個數據存儲到哪臺機器上。上面在啟動集群成功后可以看到每臺Master節點都有自己的一個槽位(Slots)范圍,Master[0]的槽位范圍是0 - 5460,Master[1]的槽位范圍是5461 - 10922,Master[2]的槽位范圍是10922 - 16383。redis在存儲前會通過CRC16方法計算出key的hash值,并與16383進行位運算來確定最終的槽位值。所以,可以知道確定槽位的方式就是 CRC16(key) & 16383
。計算出槽位后,此時在java服務端并不知道這個槽位對應到哪一臺redis服務,其實在java服務端啟動服務時會將redis的相關槽位和映射的ip信息進行一個本地緩存,所以知道槽位后,就會知道對應槽位的ip。
cluster模式中的選舉與哨兵中的不同。當某個從節點發現自己的主節點狀態變為fail狀態時,便嘗試進行故障轉移。由于掛掉的主節點可能會有多個從節點,從而存在多個從節點競爭成為新主節點 。其選舉過程大概如下:
從節點將自己記錄的集群currentEpoch加1,并廣播FAILOVER_AUTH_REQUEST信息,通知集群中的所有節點,需要進行重新選舉了。
其他節點收到該信息,但只有master節點會進行響應,判斷請求者的合法性,并發送 FAILOVER_AUTH_ACK,對每一個epoch只發送一次ack。
發送通知的從節點會收集各master主節點返回的FAILOVER_AUTH_ACK。
如果該從節點收到的ack數過半,那么該節點就會被選舉為新的Master主節點。成為主節點后,廣播通知其他小集群節點
優點:
有多個主節點,做到去中心化。
數據可以槽位進行分布存儲
擴展性更高,可用性更高。cluster集群中的節點可以在線添加或刪除,官方推薦節點數不超1000。當部分Master節點不可用時,整個集群任然可以正常工作。
缺點:
數據通過異步復制,不保證數據的強一致性
Slave節點在集群中充當冷備,不能緩解讀壓力
以上就是“Redis高可用架構如何搭建”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。