Redis TTL 為0

來源:互聯網
上載者:User

標籤:

地址: http://get.jobdeer.com/7297.get一次Redis TTL 為0的問題排查

事情是這樣的,今天中午業務突然RTX上找我,說一個建立的Twemproxy叢集資料查詢的時候出了問題,Redis的TTL返回為0,讓我幫忙看一看:

 當時聽完就覺得問題很詭異,按照之前的經驗來說,Redis的TTL怎麼也不可能為0啊,見:http://redis.io/commands/ttl

 Redis的key,通過TTL命令返回key的到期時間,一般來說有3中:

1.   當前key沒有設定到期時間,所以會返回-1.

2.   當前key有設定到期時間,而且key已經到期,所以會返回-2.

3.   當前key有設定到期時間,且key還沒有到期,故會返回key的正常剩餘時間.

所 以,十分疑惑為何會出現key的TTL為0的情況,當時第一感覺問題會不會出現在Twemproxy裡面,於是讓複雜源碼開發的同事查一下 twemproxy中是否有對ttl命令的二次處理,於此同時登入到那台twemproxy上,ttl查看相關key,確認結果確實為0,如所示:

遇到這種問題,首選懷疑是否是個例,於是自行插入key測試:

 測試過程如所示:

1.   setex a 10 1;設定一個key a,到期時間10s,值為1.

2.   通過TTL命令查看a的剩餘到期時間,結果為6s.

3.   等待一會兒,再次TTL查看,key的到期時間竟然為0。

果然不是個別現象。同時源碼的同事反饋,twemproxy本身並未對ttl命令做過任何處理,故我們通過內部的find_key工具,擷取該key所在的hash環上的real server(一致性hash演算法),到所在的redis再確認一下:

        看來確實是redis本事的問題,我們開始懷疑是Redis的內部出現的bug,於是在其他版本上進行了測試,返回的結果都是正確的,看來版本bug的可能性很高,但是並不能確定。

   我們又在其他的同版本執行個體上, 進行了同樣的測試,但是卻並未發現TTL返回0的情況。看來只能去查看源碼了。

   於是我們查看了redis對於ttl這個命令的原始碼,代碼如下:

    代碼中確實出現了TTL = 0 的情況,理論上對於存在到期時間的key,應該返回-2才對,而這個代碼中,第一個if語句(應該返回-2)並沒有執行,才導致調入了第二個迴圈裡,而理 論上當前的key的到期時間一定小於目前時間戳(且不為-1),所以TTL應該是小於0,而在代碼裡,作者將TTL<0的情況處理成TTL=0,那 問題就在為什麼第一個個if沒有生效上了,既該條件的主要判斷函數lookupKeyRead並沒有返回NULL,再查看該函數的代碼:

從這開始終於看出點端倪了,該函數之所以沒有返回NULL,也是由於第一個if語句並沒有return NULL,從代碼的評論中可以看出,當redis作為slave的時候,是可能不返回NULL的。

從 expireIfNeeded函數的注釋中可以看到,噹噹前的Redis為Slave時,為了保證主從資料的一致性,是並不會將當前key刪除的,觸發這 一句:if (server.masterhost != NULL) return now > when;當前的時間now一定是大於key儲存的到期時間的,故該函數還是返回了1,這樣又回到lookupKeyRead,函數中。下面的這段函數起 到決定性作用:

以下幾個條件滿足的時候,該函數才會Return NULL。

1.   當前連結存在

2.   當前連結不是master

3.   當前連結的命令存在

4.   當前連結的命令flags於REDIS_CMD_READONLY的與為True

前三個比較在測試過程中,一定是為True的,問題在第四個條件上,這裡又引出了Redis Command的flags,在用戶端,通過client list,可以查看到當前連結的flags:

可 以看到,執行ttl命令的flags為N,而在下面的代碼中可以看出flags=N時,表示flags=0,所以在上面的代碼中,flags & REDIS_CMD_READONLY = 0 &2(REDIS_CMD_READONLY = 2,redis.h中定義),故這個if語句也沒有進入,所以並沒有返回NULL,因此導致ttlGenericCommand命令返回了TTL=0的結 果。(至於redis使用這些flags的原理以及上面的if語句的原理,還需要更加深入的分析,這裡就不再闡述了)

所以,這種情況下,我們才知道,如果一個redis作為slave,且將slave-read-only設定為off,並寫入了一個帶有TTL的key時,當key到期後,該key是不會被Redis刪除的,且TTL在到期後永遠為0。

帶 著這樣的判斷,我們在該redis上執行info命令確認了一下,果然該redis是slave,諮詢了相關部署的同事得知,該業務在進行資料移轉過程 中,存在多級複製和雙寫的情況,所以才將redis slave設定為可寫狀態,此時將slave的slaveof 設定成no one,既斷開同步,再次排查所有到期key的TTL都返回-2了。

所以,使用Redis的童鞋們,注意一下,在進行服務遷移等情況所構成多級複製鏈的時候,在relay上進行到期key的讀寫處理的時候需要注意TTL帶來的問題,若以後遇到TTL返回等於0的時候也可以第一時間確定問題所在了。

Redis TTL 為0

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.