自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

看完這篇文章,別再說(shuō)不會(huì) Redis 的高級(jí)特性了

存儲(chǔ) 存儲(chǔ)軟件 Redis
Redis 作為后端工程師必備的技能,阿粉每次面試的時(shí)候都會(huì)被問(wèn)到,阿粉特意把公號(hào)前面發(fā)過(guò)的 Redis 系列文章整理出來(lái)成一篇,自己學(xué)習(xí)同時(shí)也幫助大家一起學(xué)習(xí)。

[[383277]]

本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。   

Redis 作為后端工程師必備的技能,阿粉每次面試的時(shí)候都會(huì)被問(wèn)到,阿粉特意把公號(hào)前面發(fā)過(guò)的 Redis 系列文章整理出來(lái)成一篇,自己學(xué)習(xí)同時(shí)也幫助大家一起學(xué)習(xí)。

文章較長(zhǎng),建議先收藏再觀看。

Redis 的數(shù)據(jù)類(lèi)型有哪些?

Redis 五種數(shù)據(jù)類(lèi)型,每種數(shù)據(jù)類(lèi)型都有相關(guān)的命令,幾種類(lèi)型分別如下:

  1. String(字符串)
  2. List(列表)
  3. Hash(字典)
  4. Set(集合)
  5. Sorted Set(有序集合)

Redis 有五種常見(jiàn)的數(shù)據(jù)類(lèi)型,每種數(shù)據(jù)類(lèi)型都有各自的使用場(chǎng)景,通用的字符串類(lèi)型使用最為廣泛,普通的 Key/Value 都是這種類(lèi)型;列表類(lèi)型使用的場(chǎng)景經(jīng)常有粉絲列表,關(guān)注列表的場(chǎng)景;字典類(lèi)型即哈希表結(jié)構(gòu),這個(gè)類(lèi)型的使用場(chǎng)景也很廣泛,在各種系統(tǒng)里面都會(huì)用到,可以用來(lái)存放用戶(hù)或者設(shè)備的信息,類(lèi)似于 HashMap 的結(jié)構(gòu);Redis set 提供的功能與列表類(lèi)型類(lèi)似也是一個(gè)列表的功能,區(qū)別是 Set 是去重的;有序集合功能與 Set 一樣,只不過(guò)是有順序的。

Redis 的內(nèi)存回收與Key 的過(guò)期策略

Redis 內(nèi)存過(guò)期策略

過(guò)期策略的配置

Redis 隨著使用的時(shí)間越來(lái)越長(zhǎng),占用的內(nèi)存會(huì)越來(lái)越大,那么當(dāng) Redis 內(nèi)存不夠的時(shí)候,我們要知道 Redis 是根據(jù)什么策略來(lái)淘汰數(shù)據(jù)的,在配置文件中我們使用 maxmemory-policy 來(lái)配置策略,如下圖

我們可以看到策略的值由如下幾種:

  • volatile-lru: 在所有帶有過(guò)期時(shí)間的 key 中使用 LRU 算法淘汰數(shù)據(jù);
  • alkeys-lru: 在所有的 key 中使用最近最少被使用 LRU 算法淘汰數(shù)據(jù),保證新加入的數(shù)據(jù)正常;
  • volatile-random: 在所有帶有過(guò)期時(shí)間的 key 中隨機(jī)淘汰數(shù)據(jù);
  • allkeys-random: 在所有的 key 中隨機(jī)淘汰數(shù)據(jù);
  • volatile-ttl: 在所有帶有過(guò)期時(shí)間的 key 中,淘汰最早會(huì)過(guò)期的數(shù)據(jù);
  • noeviction: 不回收,當(dāng)達(dá)到最大內(nèi)存的時(shí)候,在增加新數(shù)據(jù)的時(shí)候會(huì)返回 error,不會(huì)清除舊數(shù)據(jù),這是 Redis 的默認(rèn)策略;

volatile-lru, volatile-random, volatile-ttl 這幾種情況在 Redis 中沒(méi)有帶有過(guò)期 Key 的時(shí)候跟 noeviction 策略是一樣的。淘汰策略是可以動(dòng)態(tài)調(diào)整的,調(diào)整的時(shí)候是不需要重啟的,原文是這樣說(shuō)的,我們可以根據(jù)自己 Redis 的模式來(lái)動(dòng)態(tài)調(diào)整策略。”To pick the right eviction policy is important depending on the access pattern of your application, however you can reconfigure the policy at runtime while the application is running, and monitor the number of cache misses and hits using the Redis INFO output in order to tune your setup.“

策略的執(zhí)行過(guò)程

  1. 客戶(hù)端運(yùn)行命令,添加數(shù)據(jù)申請(qǐng)內(nèi)存;
  2. Redis 會(huì)檢查內(nèi)存的使用情況,如果已經(jīng)超過(guò)的最大限制,就是根據(jù)配置的內(nèi)存淘汰策略去淘汰相應(yīng)的 key,從而保證新數(shù)據(jù)正常添加;
  3. 繼續(xù)執(zhí)行命令。

近似的 LRU 算法

Redis 中的 LRU 算法不是精確的 LRU 算法,而是一種經(jīng)過(guò)采樣的LRU,我們可以通過(guò)在配置文件中設(shè)置 maxmemory-samples 5 來(lái)設(shè)置采樣的大小,默認(rèn)值為 5,我們可以自行調(diào)整。官方提供的采用對(duì)比如下,我們可以看到當(dāng)采用數(shù)設(shè)置為 10 的時(shí)候已經(jīng)很接近真實(shí)的 LRU 算法了。

在 Redis 3.x 以上的版本的中做過(guò)優(yōu)化,目前的近似 LRU 算法以及提升了很大的效率,Redis 之所以不采樣實(shí)際的 LRU 算法,是因?yàn)闀?huì)耗費(fèi)很多的內(nèi)存,原文是這樣說(shuō)的

The reason why Redis does not use a true LRU implementation is because it costs more memory.

Key 的過(guò)期策略

設(shè)置帶有過(guò)期時(shí)間的 key

前面介紹了 Redis 的內(nèi)存回收策略,下面我們看看 Key 的過(guò)期策略,提到 Key 的過(guò)期策略,我們說(shuō)的當(dāng)然是帶有 expire 時(shí)間的 key,如下

通過(guò) redis> set name ziyouu ex 100 命令我們?cè)?Redis 中設(shè)置一個(gè) key 為 name,值為 ziyouu 的數(shù)據(jù),從上面的截圖中我們可以看到右下角有個(gè) TTL,并且每次刷新都是在減少的,說(shuō)明我們?cè)O(shè)置帶有過(guò)期時(shí)間的 key 成功了。

Redis 如何清除帶有過(guò)期時(shí)間的 key

對(duì)于如何清除過(guò)期的 key 通常我們很自然的可以想到就是我們可以給每個(gè) key 加一個(gè)定時(shí)器,這樣當(dāng)時(shí)間到達(dá)過(guò)期時(shí)間的時(shí)候就自動(dòng)刪除 key,這種策略我們叫定時(shí)策略。這種方式對(duì)內(nèi)存是友好的,因?yàn)榭梢约皶r(shí)清理過(guò)期的可以,但是由于每個(gè)帶有過(guò)期時(shí)間的 key 都需要一個(gè)定時(shí)器,所以這種方式對(duì) CPU 是不友好的,會(huì)占用很多的 CPU,另外這種方式是一種主動(dòng)的行為。

有主動(dòng)也有被動(dòng),我們可以不用定時(shí)器,而是在每次訪問(wèn)一個(gè) key 的時(shí)候再去判斷這個(gè) key 是否到達(dá)過(guò)期時(shí)間了,過(guò)期了就刪除掉。這種方式我們叫做惰性策略,這種方式對(duì) CPU 是友好的,但是對(duì)應(yīng)的也有一個(gè)問(wèn)題,就是如果這些過(guò)期的 key 我們?cè)僖膊粫?huì)訪問(wèn),那么永遠(yuǎn)就不會(huì)刪除了。

Redis 服務(wù)器在真正實(shí)現(xiàn)的時(shí)候上面的兩種方式都會(huì)用到,這樣就可以得到一種折中的方式。另外在定時(shí)策略中,從官網(wǎng)我們可以看到如下說(shuō)明

Specifically this is what Redis does 10 times per second:

  1. Test 20 random keys from the set of keys with an associated expire.
  2. Delete all the keys found expired.
  3. If more than 25% of keys were expired, start again from step 1.

意思是說(shuō) Redis 會(huì)在有過(guò)期時(shí)間的 Key 集合中隨機(jī) 20 個(gè)出來(lái),刪掉已經(jīng)過(guò)期的 Key,如果比例超過(guò) 25%,再重新執(zhí)行操作。每秒鐘會(huì)執(zhí)行 10 個(gè)這樣的操作。

Redis 的發(fā)布訂閱功能你知道嗎?

發(fā)布訂閱系統(tǒng)在我們?nèi)粘5墓ぷ髦薪?jīng)常會(huì)使用到,這種場(chǎng)景大部分情況我們都是使用消息隊(duì)列的,常用的消息隊(duì)列有 Kafka,RocketMQ,RabbitMQ,每一種消息隊(duì)列都有其特性。其實(shí)在很多時(shí)候我們可能不需要獨(dú)立部署相應(yīng)的消息隊(duì)列,只是簡(jiǎn)單的使用,而且數(shù)據(jù)量也不會(huì)太大,這種情況下,我們就可以考慮使用 Redis 的 Pub/Sub 模型。

使用方式

發(fā)布與訂閱

Redis 的發(fā)布訂閱功能主要由 PUBLISH,SUBSCRIBE,PSUBSCRIBE 命令組成,一個(gè)或者多個(gè)客戶(hù)端訂閱某個(gè)或者多個(gè)頻道,當(dāng)其他客戶(hù)端向該頻道發(fā)送消息的時(shí)候,訂閱了該頻道的客戶(hù)端都會(huì)收到對(duì)應(yīng)的消息。

上圖中有四個(gè)客戶(hù)端,Client 02,Client 03,Client 04 訂閱了同一個(gè)Sport 頻道(Channel),這時(shí)當(dāng) Client 01 向 Sport Channel 發(fā)送消息 “basketball” 的時(shí)候,02-04 這三個(gè)客戶(hù)端都同時(shí)收到了這條消息。

整個(gè)過(guò)程的執(zhí)行命令如下:

首先開(kāi)四個(gè) Redis 的客戶(hù)端,然后在 Client 02,Client 03,Client 04 中輸入subscribe sport 命令,表示訂閱 sport 這個(gè)頻道

然后在 Client 01 的客戶(hù)端中輸入publish sport basketball 表示向 sport 頻道發(fā)送消息 "basketball"

這個(gè)時(shí)候我們?cè)谌タ聪翪lient 02-04 的客戶(hù)端,可以看到已經(jīng)收到了消息了,每個(gè)訂閱了這個(gè)頻道的客戶(hù)端都是一樣的。

這里 Client 02-Client 04 三個(gè)客戶(hù)端訂閱了 Sport 頻道,我們叫做訂閱者(subscriber),Client 01 發(fā)布消息,我們叫做發(fā)布者(publisher),發(fā)送的消息就是 message。

模式訂閱

前面我們看到的是一個(gè)客戶(hù)端訂閱了一個(gè) Channel,事實(shí)上單個(gè)客戶(hù)端也可以同時(shí)訂閱多個(gè) Channel,采用模式匹配的方式,一個(gè)客戶(hù)端可以同時(shí)訂閱多個(gè) Channel。

如上圖 Client 05 通過(guò)命令subscribe run 訂閱了 run 頻道,Client 06 通過(guò)命令psubscribe run* 訂閱了 run* 匹配的頻道。當(dāng) Client 07 向 run 頻道發(fā)送消息 666 的時(shí)候,05 和 06 兩個(gè)客戶(hù)端都收到消息了;接下來(lái) Client 07 向 run1 和 run_sport 兩個(gè)頻道發(fā)送消息的時(shí)候,Client 06 依舊可以收到消息,而 Client 05 就收不到了消息了。

Client 05 訂閱run 頻道和接收到消息:

Client 06 訂閱run* 頻道和接收到消息:

image-20191222141458065

Client 07 向多個(gè)頻道發(fā)送消息:

image-20191222141514914

通過(guò)上面的案例,我們學(xué)會(huì)了一個(gè)客戶(hù)端可以訂閱單個(gè)或者多個(gè)頻道,分別通過(guò)subscribe,psubscribe 命令,客戶(hù)端可以通過(guò) publish 發(fā)送相應(yīng)的消息。

在命令行中我們可以用 Ctrl + C 來(lái)取消相關(guān)訂閱,對(duì)應(yīng)的命令時(shí) unsubscribe channelName。

Pub/Sub 底層存儲(chǔ)結(jié)構(gòu)

訂閱 Channel

在 Redis 的底層結(jié)構(gòu)中,客戶(hù)端和頻道的訂閱關(guān)系是通過(guò)一個(gè)字典加鏈表的結(jié)構(gòu)保存的,形式如下:

在 Redis 的底層結(jié)構(gòu)中,Redis 服務(wù)器結(jié)構(gòu)體中定義了一個(gè) pubsub_channels 字典

  1. struct redisServer { 
  2.  //用于保存所有頻道的訂閱關(guān)系 
  3.  dict *pubsub_channels; 

在這個(gè)字典中,key 代表的是頻道名稱(chēng),value 是一個(gè)鏈表,這個(gè)鏈表里面存放的是所有訂閱這個(gè)頻道的客戶(hù)端。

所以當(dāng)有客戶(hù)端執(zhí)行訂閱頻道的動(dòng)作的時(shí)候,服務(wù)器就會(huì)將客戶(hù)端與被訂閱的頻道在 pubsub_channels 字典中進(jìn)行關(guān)聯(lián)。

這個(gè)時(shí)候有兩種情況:

  • 該渠道是首次被訂閱:首次被訂閱說(shuō)明在字典中并不存在該渠道的信息,那么程序首先要?jiǎng)?chuàng)建一個(gè)對(duì)應(yīng)的 key,并且要賦值一個(gè)空鏈表,然后將對(duì)應(yīng)的客戶(hù)端加入到鏈表中。此時(shí)鏈表只有一個(gè)元素。
  • 該渠道已經(jīng)被其他客戶(hù)端訂閱過(guò):這個(gè)時(shí)候就直接將對(duì)應(yīng)的客戶(hù)端信息添加到鏈表的末尾就好了。

比如,如果有一個(gè)新的客戶(hù)端 Client 08 要訂閱 run 渠道,那么上圖就會(huì)變成

如果 Client 08 要訂閱一個(gè)新的渠道 new_sport ,那么就會(huì)變成

image-20191222161558999

整個(gè)訂閱的過(guò)程可以采用下面?zhèn)未a來(lái)實(shí)現(xiàn)

  1. Map<String, List<Object>> pubsub_channels = new HashMap<>(); 
  2.     public void subscribe(String[] subscribeList, Object client) { 
  3.         //遍歷所有訂閱的 channel,檢查是否在 pubsub_channels 中,不在則創(chuàng)建新的 key 和空鏈表 
  4.         for (int i = 0; i < subscribeList.length; i++) { 
  5.             if (!pubsub_channels.containsKey(subscribeList[i])) { 
  6.                 pubsub_channels.put(subscribeList[i], new ArrayList<>()); 
  7.             } 
  8.             pubsub_channels.get(subscribeList[i]).add(client); 
  9.         } 
  10.     } 

取消訂閱

上面介紹的是單個(gè) Channel 的訂閱,相反的如果一個(gè)客戶(hù)端要取消訂閱相關(guān) Channel,則無(wú)非是找到對(duì)應(yīng)的 Channel 的鏈表,從中刪除對(duì)應(yīng)的客戶(hù)端,如果該客戶(hù)端已經(jīng)是最后一個(gè)了,則將對(duì)應(yīng) Channel 也刪除。

  1. public void unSubscribe(String[] subscribeList, Object client) { 
  2.         //遍歷所有訂閱的 channel,依次刪除 
  3.         for (int i = 0; i < subscribeList.length; i++) { 
  4.             pubsub_channels.get(subscribeList[i]).remove(client); 
  5.             //如果長(zhǎng)度為 0 則清楚 channel 
  6.             if (pubsub_channels.get(subscribeList[i]).size() == 0) { 
  7.                 remove(subscribeList[i]); 
  8.             } 
  9.         } 
  10.     } 

模式訂閱結(jié)構(gòu)

模式渠道的訂閱與單個(gè)渠道的訂閱類(lèi)似,不過(guò)服務(wù)器是將所有模式的訂閱關(guān)系都保存在服務(wù)器狀態(tài)的pubsub_patterns 屬性里面。

  1. struct redisServer{ 
  2.  //保存所有模式訂閱關(guān)系 
  3.  list *pubsub_patterns; 

與訂閱單個(gè) Channel 不同的是,pubsub_patterns 屬性是一個(gè)鏈表,不是字典。節(jié)點(diǎn)的結(jié)構(gòu)如下:

  1. struct pubsubPattern{ 
  2.  //訂閱模式的客戶(hù)端 
  3.  redisClient *client; 
  4.  //被訂閱的模式 
  5.  robj *pattern; 
  6. } pubsubPattern; 

其實(shí) client 屬性是用來(lái)存放對(duì)應(yīng)客戶(hù)端信息,pattern 是用來(lái)存放客戶(hù)端對(duì)應(yīng)的匹配模式。

所以對(duì)應(yīng)上面的 Client-06 模式匹配的結(jié)構(gòu)存儲(chǔ)如下

image-20191222174528367

在pubsub_patterns鏈表中有一個(gè)節(jié)點(diǎn),對(duì)應(yīng)的客戶(hù)端是 Client-06,對(duì)應(yīng)的匹配模式是run*。

訂閱模式

當(dāng)某個(gè)客戶(hù)端通過(guò)命令psubscribe 訂閱對(duì)應(yīng)模式的 Channel 時(shí)候,服務(wù)器會(huì)創(chuàng)建一個(gè)節(jié)點(diǎn),并將 Client 屬性設(shè)置為對(duì)應(yīng)的客戶(hù)端,pattern 屬性設(shè)置成對(duì)應(yīng)的模式規(guī)則,然后添加到鏈表尾部。

對(duì)應(yīng)的偽代碼如下:

  1. List<PubSubPattern> pubsub_patterns = new ArrayList<>(); 
  2.     public void psubscribe(String[] subscribeList, Object client) { 
  3.         //遍歷所有訂閱的 channel,創(chuàng)建節(jié)點(diǎn) 
  4.         for (int i = 0; i < subscribeList.length; i++) { 
  5.             PubSubPattern pubSubPattern = new PubSubPattern(); 
  6.             pubSubPattern.client = client; 
  7.             pubSubPattern.pattern = subscribeList[i]; 
  8.             pubsub_patterns.add(pubSubPattern); 
  9.         } 
  10.     } 
  1. 創(chuàng)建新節(jié)點(diǎn);
  2. 給節(jié)點(diǎn)的屬性賦值;
  3. 將節(jié)點(diǎn)添加到鏈表的尾部;

退訂模式

退訂模式的命令是punsubscribe,客戶(hù)端使用這個(gè)命令來(lái)退訂一個(gè)或者多個(gè)模式 Channel。服務(wù)器接收到該命令后,會(huì)遍歷pubsub_patterns鏈表,將匹配到的 client 和 pattern 屬性的節(jié)點(diǎn)給刪掉。這里需要判斷 client 屬性和 pattern 屬性都合法的時(shí)候再進(jìn)行刪除。

偽代碼如下:

  1. public void punsubscribe(String[] subscribeList, Object client) { 
  2.         //遍歷所有訂閱的 channel 相同 client 和 pattern 屬性的節(jié)點(diǎn)會(huì)刪除 
  3.         for (int i = 0; i < subscribeList.length; i++) { 
  4.             for (int j = 0; j < pubsub_patterns.size(); j++) { 
  5.                 if (pubsub_patterns.get(j).client == client 
  6.                 && pubsub_patterns.get(j).pattern == subscribeList[i]) { 
  7.                     remove(pubsub_patterns); 
  8.                 } 
  9.             } 
  10.         } 
  11.     } 

遍歷所有的節(jié)點(diǎn),當(dāng)匹配到相同 client 屬性和 pattern 屬性的時(shí)候就進(jìn)行節(jié)點(diǎn)刪除。

發(fā)布消息

發(fā)布消息比較好容易理解,當(dāng)一個(gè)客戶(hù)端執(zhí)行了publish channelName message 命令的時(shí)候,服務(wù)器會(huì)從pubsub_channels和pubsub_patterns 兩個(gè)結(jié)構(gòu)中找到符合channelName 的所有 Channel,進(jìn)行消息的發(fā)送。在 pubsub_channels 中只要找到對(duì)應(yīng)的 Channel 的 key 然后向?qū)?yīng)的 value 鏈表中的客戶(hù)端發(fā)送消息就好。

Redis 的持久化你了解嗎

持久化是將程序數(shù)據(jù)在持久狀態(tài)和瞬時(shí)狀態(tài)間轉(zhuǎn)換的機(jī)制。通俗的講,就是瞬時(shí)數(shù)據(jù)(比如內(nèi)存中的數(shù)據(jù),是不能永久保存的)持久化為持久數(shù)據(jù)(比如持久化至數(shù)據(jù)庫(kù)中,能夠長(zhǎng)久保存)。另外我們使用的 Redis 之所以快就是因?yàn)閿?shù)據(jù)都存儲(chǔ)在內(nèi)存當(dāng)中,為了保證在服務(wù)器出現(xiàn)異常過(guò)后還能恢復(fù)數(shù)據(jù),所以就有了 Redis 的持久化,Redis 的持久化有兩種方式,一種是快照形式 RDB,另一種是增量文件 AOF。

RDB

RDB 持久化方式是會(huì)在一個(gè)特定的時(shí)間間隔里面保存某個(gè)時(shí)間點(diǎn)的數(shù)據(jù)快照,我們拿到這個(gè)數(shù)據(jù)快照過(guò)后就可以根據(jù)這個(gè)快照完整的復(fù)制出數(shù)據(jù)。這種方式我們可以用來(lái)備份數(shù)據(jù),把快照文件備份起來(lái),傳送到其他服務(wù)器就可以直接恢復(fù)數(shù)據(jù)。但是這只是某個(gè)時(shí)間點(diǎn)的全部數(shù)據(jù),如果我們想要最新的數(shù)據(jù),就只能定期的去生成快照文件。

RDB 的實(shí)現(xiàn)主要是通過(guò)創(chuàng)建一個(gè)子進(jìn)程來(lái)實(shí)現(xiàn) RDB 文件的快照生成,通過(guò)子進(jìn)程來(lái)實(shí)現(xiàn)備份功能,不會(huì)影響主進(jìn)程的性能。同時(shí)上面也提到 RDB 的快照文件是保存一定時(shí)間間隔的數(shù)據(jù)的,這就會(huì)導(dǎo)致如果時(shí)間間隔過(guò)長(zhǎng),服務(wù)器出現(xiàn)異常還沒(méi)來(lái)得及生成快照的時(shí)候就會(huì)丟失這個(gè)間隔時(shí)間的所有數(shù)據(jù);那有同學(xué)就會(huì)說(shuō),我們可以把時(shí)間間隔設(shè)置的短一點(diǎn),適當(dāng)?shù)目s短是可以的,但是如果間隔時(shí)間段設(shè)置短一點(diǎn)頻繁的生成快照對(duì)系統(tǒng)還是會(huì)有影響的,特別是在數(shù)據(jù)量大的情況下,高性能的環(huán)境下是不允許這種情況出現(xiàn)的。

我們可以在 redis.conf 進(jìn)行 RDB 的相關(guān)配置,配置生成快照的策略,以及日志文件的路徑和名稱(chēng)。還有定時(shí)備份規(guī)則,如下圖所示,里面的注釋寫(xiě)的很清楚,簡(jiǎn)單說(shuō)就是在多少時(shí)間以?xún)?nèi)多少個(gè) key 變化了就會(huì)觸發(fā)快照。如save 300 10 表示在 5 分鐘內(nèi)如果有 10 個(gè) key 發(fā)生了變化就會(huì)觸發(fā)生產(chǎn)快照,其他的同理。

除了我們?cè)谂渲梦募信渲米詣?dòng)生成快照文件之外,Redis 本身提供了相關(guān)的命令可以讓我們手動(dòng)生成快照文件,分別是 SAVE 和 BGSAVE ,這兩個(gè)命令功能相同但是方式和效果不一樣,SAVE 命令執(zhí)行完后阻塞服務(wù)器進(jìn)程,阻塞過(guò)后服務(wù)器就不能處理任何請(qǐng)求,所以在生產(chǎn)上不能用,和SAVE 命令直接阻塞服務(wù)器進(jìn)程的做法不同,BGSAVE 命令是生成一個(gè)子進(jìn)程,通過(guò)子進(jìn)程來(lái)創(chuàng)建 RDB 文件,主進(jìn)程依舊可以處理接受到的命令,從而不會(huì)阻塞服務(wù)器,在生產(chǎn)上可以使用。

阿粉在這里測(cè)試一下自動(dòng)生成快照,我們修改一下快照的生成策略為save 10 2,然后在本地啟動(dòng)Redis 服務(wù),并用 redis-cli 鏈接進(jìn)入,依次步驟如下

1.修改配置,如下

2.啟動(dòng) Redis 服務(wù),我們可以從啟動(dòng)日志中看到,默認(rèn)是會(huì)先讀取 RDB 文件進(jìn)行恢復(fù)的

3.

4.鏈接 Redis 服務(wù),并在 10s 內(nèi)設(shè)置 3 個(gè) key

5.這個(gè)時(shí)候我們會(huì)看到 Redis 的日志里面會(huì)輸出下面內(nèi)容,因?yàn)橛|發(fā)了規(guī)則,所以開(kāi)啟子進(jìn)程進(jìn)行數(shù)據(jù)備份,同時(shí)在對(duì)應(yīng)的文件路徑下面,我們也看到了 rdb 文件。

6.

從上面可以看出,我們配置的規(guī)則生效了,也成功的生成了 RDB 文件, 后續(xù)在服務(wù)器出現(xiàn)異常的情況,只要重新啟動(dòng)就會(huì)讀取對(duì)應(yīng)的 RDB 文件進(jìn)行數(shù)據(jù)備份。

AOF

AOF 是一種追加執(zhí)行命令的形式,它跟 RDB 的區(qū)別是,AOF 并不是把數(shù)據(jù)保存下來(lái),而是保存執(zhí)行的動(dòng)作。在開(kāi)啟 AOF 功能的時(shí)候,客戶(hù)端連接后執(zhí)行的每一條命令都會(huì)被記錄下來(lái)。這其實(shí)讓阿粉想起來(lái)的 MySQL 的 binlog 日志,也是記錄操作的命令,后續(xù)可以根據(jù)文件去恢復(fù)數(shù)據(jù)。

AOF 是追加命令格式的文件,同樣的我們可以定義多長(zhǎng)時(shí)間把數(shù)據(jù)同步一次,Redis 本身提供了三種策略來(lái)實(shí)現(xiàn)命令的同步,分別是不進(jìn)行同步,每秒同步一次,以及當(dāng)有查詢(xún)的時(shí)候同步一次。默認(rèn)的策略也是使用最多的策略就是每秒同步一次,這樣我們可以知道,丟失的數(shù)據(jù)最多也就只有一秒鐘的數(shù)據(jù)。有了這種機(jī)制,AOF 會(huì)比 RDB 可靠很多,但是因?yàn)槲募锩娲嬖诘氖菆?zhí)行的命令,所以AOF 的文件一般也會(huì)比 RDB 的文件大點(diǎn)。

Redis 的 AOF 功能,默認(rèn)是沒(méi)有開(kāi)啟的,我們可以通過(guò)在配置文件中配置appendonly yes 是功能開(kāi)啟,同時(shí)配置同步策略appendfsync everysec 開(kāi)啟每秒鐘同步一次,我們拿到 AOF 文件過(guò)后,可以根據(jù)這個(gè)文件恢復(fù)數(shù)據(jù)。

同樣的我們?cè)趓edis.conf 中可以看到默認(rèn)是沒(méi)有開(kāi)啟 AOF 功能的,并且我們也可以指定對(duì)應(yīng)的文件名稱(chēng)和路徑。

接下來(lái),我們測(cè)試一下開(kāi)啟 AOF 功能,先修改配置然后重啟 Redis 的服務(wù)器,我們會(huì)發(fā)現(xiàn)已經(jīng)沒(méi)有讀取 RDB 文件的日志了,并且在日志文件路徑下面已經(jīng)生成了一個(gè) aof 文件。需要注意的是,因?yàn)槲覀冎貑⒌姆?wù),并且開(kāi)啟了 AOF,所以現(xiàn)在 Redis 服務(wù)器里面并沒(méi)有我們之前添加的數(shù)據(jù)(說(shuō)明什么問(wèn)題呢?)。

接下來(lái)我們使用客戶(hù)端連接進(jìn)入,設(shè)置如下值,接下來(lái)我們可以看看 aof 文件里面的內(nèi)容

我們可以看到aof 文件里面的內(nèi)容就是執(zhí)行的命令,只不過(guò)是以一種固定的格式存儲(chǔ)的,我們?cè)趥浞莸臅r(shí)候如果不需要哪些數(shù)據(jù),可以手動(dòng)刪掉對(duì)應(yīng)的命令就可以重新備份數(shù)據(jù)。

Redis 的有幾種集群模式

雖然說(shuō)單機(jī) Redis 理論上可以達(dá)到 10 萬(wàn)并發(fā)而且也可以進(jìn)行持久化,但是在生產(chǎn)環(huán)境中真正使用的時(shí)候,我相信沒(méi)有哪個(gè)公司敢這樣使用,當(dāng)數(shù)據(jù)量達(dá)到一定的規(guī)模的時(shí)候肯定是要上 Redis 集群的。

Redis 的模式有主從復(fù)制模式,哨兵模式以及集群模式,這三種模式的涉及到篇幅內(nèi)容會(huì)比較多,阿粉后面會(huì)單獨(dú)寫(xiě)一篇文章來(lái)介紹,感興趣的小伙伴可以先自己學(xué)習(xí)下。

 

責(zé)任編輯:武曉燕 來(lái)源: Java極客技術(shù)
相關(guān)推薦

2017-08-09 15:07:08

大數(shù)據(jù)數(shù)據(jù)分析戶(hù)畫(huà)像

2021-06-16 00:57:16

JVM加載機(jī)制

2020-06-18 10:48:44

Linux 系統(tǒng) 數(shù)據(jù)

2022-12-27 08:01:09

設(shè)計(jì)模式https://mp

2025-03-28 08:53:51

2017-03-07 15:35:26

Android適配 界面

2017-03-10 21:04:04

Android適配

2015-12-02 18:11:06

百度地圖/地圖軟件

2021-11-10 07:47:48

Traefik邊緣網(wǎng)關(guān)

2021-07-13 12:21:34

PythonRPC通信

2019-05-30 09:32:49

2019-08-01 11:04:10

Linux磁盤(pán)I

2024-11-19 18:03:04

2019-07-10 15:15:23

JVM虛擬機(jī)Java

2018-04-23 11:00:44

PythonRedisNoSQL

2022-05-27 21:56:55

索引存儲(chǔ)MySQL 存儲(chǔ)引擎

2020-12-18 09:45:33

DockerLinux命令

2019-11-14 09:55:35

開(kāi)發(fā)技能代碼

2018-09-28 09:32:57

2021-04-27 07:59:11

內(nèi)聯(lián)匯編 C 語(yǔ)言 asm 關(guān)鍵字
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)