久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Redis中key過期如何解決

156次閱讀
沒有評論

共計 3034 個字符,預計需要花費 8 分鐘才能閱讀完成。

這篇文章給大家介紹 Redis 中 key 過期如何解決,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

初步調查

受影響的團隊和緩存團隊開始進行初步的調查。我們發現延遲增加與現在正在發生的 key 清除有關。當 Redis 收到寫入請求但沒有內存來保存寫入時,它將停止正在執行的操作,清除 key 然后保存新 key。但是,我們仍然需要找出導致這些新清除的內存使用量增加的原因。

我們懷疑內存中充滿了過期但尚未刪除的 key。有人建議使用掃描,掃描的方法會讀取所有的 key,并且讓過期的 key 被刪除。

在 Redis 中,key 有兩種過期方式,主動過期和被動過期。掃描將觸發 key 的被動過期,當讀取 key 時,TTL 將會被檢查,如果 TTL 已過期,TTL 會被刪除并且不返回任何內容。Redis 文檔中描述了版本 3.2 中的 key 的主動過期。key 的主動過期以一個名為 activeExpireCycle 的函數開始。它以每秒運行幾次的頻率,運行在一個稱為 cron 的內部計時器上。activeExpireCycle 函數的作用是遍歷每個密鑰空間,檢查具有 TTL 集的隨機 kry,如果滿足過期 kry 的百分比閾值,則重復此過程直到滿足時間限制。

這種掃描所有 kry 的方法是有效的,當掃描完成時,內存使用量也下降了。似乎 Redis 不再有效地使 key 過期了。但是,當時的解決方案是增加集群的大小和更多的硬件,這樣 key 就會分布得更多,就會有更多的可用內存。這是令人失望的,因為前面提到的升級 Redis 的項目通過提高集群的效率降低了運行這些集群的規模和成本。

Redis 版本:有什么改變?

Redis 版本 2.4 和 3.2 之間,activeExpireCycle 的實現發生了變化。在 Redis 2.4 中,每次運行時都會檢查每個數據庫,在 Redis3.2 中,可以檢查的數據庫數量達到了最大值。版本 3.2 還引入了檢查數據庫的快速選項。“Slow”在計時器上運行,“fast”運行在檢查事件循環上的事件之前。快速到期周期將在某些條件下提前返回,并且它還具有較低的超時和退出功能閾值。時間限制也會被更頻繁地檢查。總共有 100 行代碼被添加到此函數中。

進一步調查

最近我們有時間回過頭來重新審視這個內存使用問題。我們想探索為什么會出現 regression,然后看看我們如何才能更好地實現 key expiration。我們的第一個想法是,在 Redis 中有很多的 key,只采樣 20 是遠遠不夠的。我們想研究的另一件事是 Redi 3.2 中引入數據庫限制的影響。

縮放和處理 shard 的方式使得在 Twitter 上運行 Redis 是獨一無二的。我們有包含數百萬個 key 的 key 空間。這對于 Redis 用戶來說并不常見。shard 由 key 空間表示,因此 Redis 的每個實例都可以有多個 shard。我們 Redis 的實例有很多 key 空間。Sharding 與 Twitter 的規模相結合,創建了具有大量 key 和數據庫的密集后端。

過期測試的改進

每個循環上采樣的數字由變量

ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP

配置。我決定測試三個值,并在其中一個有問題的集群中運行這三個值,然后進行掃描,并測量內存使用前后的差異。如果內存使用前后的差異較大,表明有大量過期數據等待收集。這項測試最初在記憶使用方面有積極的結果。

該測試有一個控件和三個測試實例,可以對更多 key 進行采樣。500 和 200 是任意的。值 300 是基于統計樣本大小的計算器的輸出,其中總 key 數是總體大小。在上面的圖表中,即使只看測試實例的初始數量,也可以清楚地看出它們的性能更好。這個與運行掃描的百分比的差異表明,過期 key 的開銷約為 25%。

雖然對更多 key 進行采樣有助于我們找到更多過期 key,但負延遲效應超出了我們的承受能力。

上圖顯示了 99.9%的延遲(以毫秒為單位)。這表明延遲與采樣的 key 的增加相關。橙色代表值 500,綠色代表 300,藍色代表 200,控制為黃色。這些線條與上表中的顏色相匹配。

在看到延遲受到樣本大小影響后,我想知道是否可以根據有多少 key 過期來自動調整樣本大小。當有更多的 key 過期時,延遲會受到影響,但是當沒有更多的工作要做時,我們會掃描更少的 key 并更快地執行。

這個想法基本上是可行的,我們可以看到內存使用更低,延遲沒有受到影響,一個度量跟蹤樣本量顯示它隨著時間的推移在增加和減少。但是,我們沒有采用這種解決方案。這種解決方案引入了一些在我們的控件實例中沒有出現的延遲峰值。代碼也有點復雜,難以解釋,也不直觀。我們還必須針對每個不理想的群集進行調整,因為我們希望避免增加操作復雜性。

調查版本之間的擬合

我們還想調查 Redis 版本之間的變化。Redis 新版本引入了一個名為 CRON_DBS_PER_CALL 的變量。這個變量設置了每次運行此 cron 時要檢查的最大數據庫數量。為了測試這種變量的影響,我們簡單地注釋掉了這些行。

//if (dbs_per_call server.dbnum || timelimit_exit)
dbs_per_call = server.dbnum;

這會比較每次運行時具有限制的,和沒有限制的檢查所有數據庫兩個方法之間的效果。我們的基準測試結果十分令人興奮。但是,我們的測試實例只有一個數據庫,從邏輯上講,這行代碼在修改版本和未修改版本之間沒有什么區別。變量始終都會被設置。

99.9% 的以微秒為單位。未修改的 Redis 在上面,修改的 Redis 在下面。

我們開始研究為什么注釋掉這一行會產生如此巨大的差異。由于這是一個 if 語句,我們首先懷疑的是分支預測。我們利用

gcc’s__builtin_expect

來改變代碼的編譯方式。但是,這對性能沒有任何影響。

接下來,我們查看生成的程序集,以了解究竟發生了什么。

我們將 if 語句編譯成三個重要指令 mov、cmp 和 jg。Mov 將加載一些內存到寄存器中,cmp 將比較兩個寄存器并根據結果設置另一個寄存器,jg 將根據另一個寄存器的值執行條件跳轉。跳轉到的代碼將是 if 塊或 else 塊中的代碼。我取出 if 語句并將編譯后的程序集放入 Redis 中。然后我通過注釋不同的行來測試每條指令的效果。我測試了 mov 指令,看看是否存在加載內存或 cpu 緩存方面的性能問題,但沒有發現區別。我測試了 cmp 指令也沒有發現區別。當我使用包含的 jg 指令運行測試時,延遲會回升到未修改的級別。在找到這個之后,我測試了它是否只是一個跳轉,或者是一個特定的 jg 指令。我添加了非條件跳轉指令 jmp,跳轉然后跳回到代碼運行,期間沒有出現性能損失。

我們花了一些時間查看不同的性能指標,并嘗試了 cpu 手冊中列出的一些自定義指標。關于為什么一條指令會導致這樣的性能問題,我們沒有任何結論。當執行跳轉時,我們有一些與指令緩存緩沖區和 cpu 行為相關的想法,但是時間不夠了,可能的話,我們會在將來再回到這一點。

解析度

既然我們已經很好地理解了問題的原因,那么我們需要選擇一個解決這個問題的方法。我們的決定是進行簡單的修改,以便能夠在啟動選項中配置穩定的樣本量。這樣,我們就能夠在延遲和內存使用之間找到一個很好的平衡點。即使刪除 if 語句引起了如此大幅度的改進,如果我們不能解釋清楚其原因,我們也很難做出改變。

關于 Redis 中 key 過期如何解決就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-01發表,共計3034字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 绥棱县| 驻马店市| 固始县| 策勒县| 蒲城县| 乌拉特前旗| 宁南县| 河间市| 扬州市| 高邑县| 行唐县| 天镇县| 麻阳| 石棉县| 孝昌县| 巴马| 商水县| 库车县| 长治县| 麻城市| 佛坪县| 平和县| 开远市| 大丰市| 平陆县| 临泉县| 孝昌县| 仙居县| 江津市| 尖扎县| 丰原市| 普兰店市| 福州市| 蒙城县| 三江| 宜兰县| 凤山市| 犍为县| 始兴县| 吴江市| 梨树县|