好湿?好紧?好多水好爽自慰,久久久噜久噜久久综合,成人做爰A片免费看黄冈,机机对机机30分钟无遮挡

主頁 > 知識庫 > Redis 2.8-4.0過期鍵優(yōu)化過程全紀(jì)錄

Redis 2.8-4.0過期鍵優(yōu)化過程全紀(jì)錄

熱門標(biāo)簽:四川穩(wěn)定外呼系統(tǒng)軟件 一個地圖標(biāo)注多少錢 南京手機(jī)外呼系統(tǒng)廠家 b2b外呼系統(tǒng) 高碑店市地圖標(biāo)注app 臺灣電銷 地圖標(biāo)注工廠入駐 400電話辦理的口碑 廊坊外呼系統(tǒng)在哪買

前言

之前 白馨(陌陌-技術(shù)保障部存儲工程師 )在Redis技術(shù)交流群里,總結(jié)了一下Redis從2.8~4.0關(guān)于過期鍵相關(guān)的fix記錄,非常有幫助,但有些東西未盡詳細(xì),本文將進(jìn)行詳細(xì)說明。

先從一個問題來看,運行環(huán)境如下:

Redis: 2.8.19
db0:keys=10000000,expires=10000000
主從結(jié)構(gòu)

從下圖中可以看到,在從節(jié)點get hello非空,在主節(jié)點get hello為空,之后從節(jié)點get hello為空,經(jīng)排查主從同步offset基本正常,但出現(xiàn)了主從不一致。

原因先不說,本文來探討下Redis2.8-4.0版本迭代中,針對過期鍵的fix,看看能不能找到答案。

一、過期功能回顧

當(dāng)你執(zhí)行了一條setex命令后,Redis會向內(nèi)部的dict和expires哈希結(jié)構(gòu)中分別插入數(shù)據(jù):

dict------dict[key]:value
expires---expires[key]:timeout

例如:

127.0.0.1:6379> setex hello 120 world
OK
127.0.0.1:6379> info
# 該數(shù)據(jù)庫中設(shè)置為過期鍵并且未被刪除的總量(如果曾設(shè)置為過期鍵且刪除則不計入)
db0:keys=1,expires=1,avg_ttl=41989
# 歷史上每一次刪除過期鍵就做一次加操作,記錄刪除過期鍵的總數(shù)。
expired_keys:0

二、Redis過期鍵的刪除策略:

當(dāng)鍵值過期后,Redis是如何處理呢?綜合考慮Redis的單線程特性,有兩種策略:惰性刪除和定時刪除。

1.惰性刪除策略:

在每次執(zhí)行key相關(guān)的命令時,都會先從expires中查找key是否過期,下面是3.0.7的源碼(db.c):

下面是讀寫key相關(guān)的入口:

robj *lookupKeyRead(redisDb *db, robj *key) {
 robj *val;

 expireIfNeeded(db,key);
 val = lookupKey(db,key);
 ......
 return val;
}

robj *lookupKeyWrite(redisDb *db, robj *key) {
 expireIfNeeded(db,key);
 return lookupKey(db,key);
}

可以看到每次讀寫key前,所有的Redis命令在執(zhí)行之前都會調(diào)用expireIfNeeded函數(shù):

int expireIfNeeded(redisDb *db, robj *key) {
 mstime_t when = getExpire(db,key);
 mstime_t now;
 if (when  0) return 0; /* No expire for this key */
 now = server.lua_caller ? server.lua_time_start : mstime();
 if (server.masterhost != NULL) return now > when;
 /* Return when this key has not expired */
 if (now = when) return 0;
 /* Delete the key */
 server.stat_expiredkeys++;
 propagateExpire(db,key);
 notifyKeyspaceEvent(NOTIFY_EXPIRED,
  "expired",key,db->id);
 return dbDelete(db,key);
}

從代碼可以看出,主從邏輯略有不同:

(1) 主庫:過期則expireIfNeeded會刪除過期鍵,刪除成功返回1,否則返回0。

(2) 從庫:expireIfNeeded不會刪除key,而會返回一個邏輯刪除的結(jié)果,過期返回1,不過期返回0 。

但是從庫過期鍵刪除由主庫的synthesized DEL operations控制。

2.定時刪除策略:

單單靠惰性刪除,肯定不能刪除所有的過期key,考慮到Redis的單線程特性,Redis使用了定期刪除策略,采用策略是從一定數(shù)量的數(shù)據(jù)庫的過期庫中取出一定數(shù)量的隨機(jī)鍵進(jìn)行檢查,不為空則刪除。不保證實時刪除。有興趣的同學(xué)可以看看activeExpireCycle中具體實現(xiàn),還是挺有意思的,下圖是個示意圖


if (server->masterhost == NULL) activeExpireCycle();

(1)主庫: 會定時刪除過期鍵。

(2)從庫: 不執(zhí)行定期刪除。

綜上所述: 

主庫:

(1) 在執(zhí)行所有操作之前調(diào)用expireIfNeeded惰性刪除。

(2) 定期執(zhí)行調(diào)用一次activeExpireCycle,每次隨機(jī)刪除部分鍵(定時刪除)。

從庫:

過期鍵刪除由主庫的synthesized DEL operations控制。

三、過期讀寫問題

Redis過期刪除策略帶來的問題。我們只從用戶操作的角度來討論。

1、過期鍵讀操作

下面是Redis 2.8~4.0過期鍵讀操作的fix記錄

(1) Redis2.8主從不一致

2.8中的讀操作中都先調(diào)用lookupKeyRead函數(shù):

robj *lookupKeyRead(redisDb *db, robs *key) {
  robj *val;
  expireIfNeeded(db,key);
  val = lookupKey(db,key);
  if (val == NULL)
    server.stat_keyspace_misses++;
  else
    server.stat_keyspace_hits++;
  return val;
}

•對于主庫,執(zhí)行expireIfNeeded時,過期會刪除key。lookupKey返回 NULL。

•對于從庫,執(zhí)行expireIfNeeded時,過期不會刪除key。lookupKey返回value。

所以對于過期鍵的讀操作,主從返回就會存在不一致的情況,也就是開篇提到的問題。

(2) Redis 3.2主從除exists之外都一致

https://github.com/antirez/redis/commit/06e76bc3e22dd72a30a8a614d367246b03ff1312

3.2-rc1讀操作中同樣先調(diào)用了lookupKeyRead,實際上調(diào)用的是lookupKeyReadWithFlags函數(shù):

robj *lookupKeyReadWithFlags(redisDb *db, robj *key) {
  robj *val;
  if (expireIfNeeded(db,key) == 1) { 
    if (server.masterhost == NULL) return NULL;
    if (server.current_client  //當(dāng)前客戶端存在
      server.current_client != server.master  //當(dāng)前客戶端不是master請求建立的(用戶請求的客戶端)
      server.current_client->cmd 
      server.current_client->cmd->flags  REDIS_CMD_READONLY) { //讀命令
        return NULL;
       }
  val = lookupKey(db,key,flags);
  if (val == NULL)
    server.stat_keyspace_misses++;
  else
    server.stat_keyspace_hits++;
  return val;
  }

可以看到,相對于2.8,增加了對expireIfNeeded返回結(jié)果的判斷:

•對于主庫,執(zhí)行expireIfNeeded時,過期會刪除key,返回1。masterhost為空返回NULL。

•對于從庫,執(zhí)行expireIfNeeded時,過期不會刪除key,返回1。滿足當(dāng)前客戶端不為 master且為讀命令時返回NULL。

除非程序異常。正常情況下對于過期鍵的讀操作,主從返回一致。

(2) Redis 4.0.11解決exists不一致的情況

https://github.com/antirez/redis/commit/32a7a2c88a8b8cca8119b849eee7976b8ada8936

3.2并未解決exists這個命令的問題,雖然它也是個讀操作。之后的4.0.11中問題才得以解決.

2、過期鍵寫操作

在具體說這個問題之前,我們先說一下可寫從庫的使用場景。

(1).主從分離場景中,利用從庫可寫執(zhí)行耗時操作提升性能。

作者在https://redis.io/topics/replication 中提到過:

For example computing slow Set or Sorted set operations and storing them into local keys is an use case for writable slaves that was observed multiple times.

在 https://github.com/antirez/redis/commit/c65dfb436e9a5a28573ec9e763901b2684eadfc4 舉了一個更具體的例子:

For instance imagine having slaves replicating certain Sets keys from the master. When accessing the data on the slave, we want to peform intersections between
such Sets values. However we don't want to intersect each time: to cache the intersection for some time often is a good idea.

也就是說在讀寫分離的場景中,可以使用過期鍵的機(jī)制將從庫作為一個緩存,去緩存從庫上耗時操作的結(jié)果,提升整體性能。

(2). 遷移數(shù)據(jù)時,需要先將從庫設(shè)置為可寫。

比如下列場景:線上Redis服務(wù)正常,但可能遇到一些硬件的情況,需要對該機(jī)器上的Redis主從集群遷移。遷數(shù)據(jù)的方式就是搭建一個新的主從集群,讓新主成為舊主的從。

進(jìn)行如下操作:

•(1)主(舊主)從(新主)同步,rdb傳輸完畢90s之后,設(shè)置從庫(新主)可寫。

•(2)在主庫(舊主)完全沒有業(yè)務(wù)連接后,從庫(新主)執(zhí)行slaveof no one。

這種場景下,為了保證數(shù)據(jù)完全同步,并且盡量減少對業(yè)務(wù)的影響,就會先設(shè)置從庫可寫。

接著我們來做一個測試:

3.2版本主庫執(zhí)行的操作,主庫的過期鍵正常過期。

3.2版本可寫從庫執(zhí)行以下操作,從庫的過期鍵并不會過期。

4.0rc3版本可寫從庫執(zhí)行以下操作,從庫的過期鍵卻能夠過期。

其實可寫從庫過期鍵問題包含兩個問題:

•(1)從庫中的過期鍵由主庫同步過來的,過期操作由主庫執(zhí)行(未變更過)。

•(2)從庫中的過期鍵的設(shè)置是從庫上操作的。

redis4.0rc3之前,存在過期鍵泄露的問題。當(dāng)expire直接在從庫上操作,這個key是不會過期的。作者也在https://redis.io/topics/replication 提到過:

However note that writable slaves before version 4.0 were incapable of expiring keys with a time to live set. This means that if you use EXPIRE or other commands that set a maximum TTL for a key, the key will leak, and while you may no longer see it while accessing it with read commands, you will see it in the count of keys and it will still use memory. So in general mixing writable slaves (previous version 4.0) and keys with TTL is going to create issues.

過期鍵泄露問題在https://github.com/antirez/redis/commit/c65dfb436e9a5a28573ec9e763901b2684eadfc4中得到了解決。

四.總結(jié)

1、針對過期鍵讀操作

(1) Redis2.8主從不一致 

(2) Redis3.2-rc1主從除exists之外都一致: https://github.com/antirez/redis/commit/06e76bc3e22dd72a30a8a614d367246b03ff1312

(3) Redis4.0.11主從一致:

https://github.com/antirez/redis/commit/32a7a2c88a8b8cca8119b849eee7976b8ada8936

2、針對過期鍵的寫操作:

Redis2.8~4.0都只返回物理結(jié)果。

3、從庫中對key執(zhí)行expire操作,key不會過期。

Redis4.0 rc3解決從庫中設(shè)置的過期鍵不過期問題 https://github.com/antirez/redis/commit/c65dfb436e9a5a28573ec9e763901b2684eadfc4

4、如果slave非讀寫分離、上述遷移使用,基本本文問題不會出現(xiàn)。還有就是Redis 4非常靠譜,后面也會有文章介紹相關(guān)內(nèi)容。(付磊)

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • redis學(xué)習(xí)之RDB、AOF與復(fù)制時對過期鍵的處理教程
  • 大家都應(yīng)該知道的Redis過期鍵與過期策略
  • redis鍵空間通知使用實現(xiàn)
  • Redis開啟鍵空間通知實現(xiàn)超時通知的步驟詳解
  • 使用redis實現(xiàn)延遲通知功能(Redis過期鍵通知)

標(biāo)簽:定州 拉薩 甘南 泰州 南寧 伊春 畢節(jié) 河源

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Redis 2.8-4.0過期鍵優(yōu)化過程全紀(jì)錄》,本文關(guān)鍵詞  Redis,2.8-4.0,過期,鍵,優(yōu)化,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Redis 2.8-4.0過期鍵優(yōu)化過程全紀(jì)錄》相關(guān)的同類信息!
  • 本頁收集關(guān)于Redis 2.8-4.0過期鍵優(yōu)化過程全紀(jì)錄的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    主站蜘蛛池模板: 九九精品视频99精品视频| 肉色超薄丝袜脚交一区二区| 国产又湿又黄又硬又刺激| 无遮挡无遮挡91桃色在线观看| 阿娇陈冠希露双奶头被删视频| 717午夜理伦电影| 精品区在线观看| 瞬息全宇宙1080p下载| 用牛奶灌进女人屁股眼的视频| 親子亂子倫XXXX 0路舒淇| 樱花影院高清电影好看的| 污软件下载网站| 日本护士xxxx| 久久久精品波多野结衣| 国产一级恐怖片| 牛牛精品一区二区AV视频| 女生搞鸡视频| 女子住17楼洗澡未穿衣遭偷拍| 张柏芝全套94张未删减版| 欧美精品一区二区在线播放| 重口XXOO凌虐在线观看| 国产亚洲高清在线精品不卡| 欧日韩一区二区三区| 极品尤物一区二区三区| 添奶头添到高潮奶水会喷出来| 亚洲丰满多毛的隂户| 欧美三四级片| 一级毛片**免费观看| 福利精品视频| 日本人妻无码波多野结衣| 德国性A片一区二区| 农村乱人妻一区二区三区| 五月婷六月婷婷| 皇帝调教成禁脔h虐男男| 明明不喜欢电影在线免费观看| 男同桌玩我奶头我j扒我内衣内裤 男同桌手伸进我奶罩揉我胸的经历 | 老妇性放纵小说| 高清乱码????免费女女| 丰满大乳少妇在线观看网站| 最好看的2018中文字幕小说 | 好爽?好紧?老熟妇|