用十條優(yōu)化措施,將Redis費(fèi)用降本46萬/月
共 8095字,需瀏覽 17分鐘
·
2024-07-24 13:00
優(yōu)化成果
2023 年,通過切換低成本的 Redis ESSD 實(shí)例、實(shí)施流量壓縮方案、清理無效數(shù)據(jù)、治理實(shí)例 TTL、下線無用實(shí)例等措施,自研了 Redis 流量復(fù)制 & 流量放大、Redis 數(shù)據(jù)遷移、Redis 數(shù)據(jù)在線壓縮 & 解壓縮、Redis 數(shù)據(jù)定向清理 & 定向指定 TTL、Redis 掃描分析 Key 最后訪問時間等工具輔助方案落地。實(shí)現(xiàn) Redis 費(fèi)用降本 46 萬 / 月。
PS:文中所述 Redis , 均為阿里云的 Redis 相關(guān)產(chǎn)品。
優(yōu)化措施
| 優(yōu)化措施 | 優(yōu)化比例 |
|---|---|
| 1、清理未使用的實(shí)例 | 5% |
| 2、實(shí)例降配:提高內(nèi)存使用率 | 15% |
| 3、使用場景打標(biāo),允許部分場景內(nèi)存用滿 | 1% |
| 4、合理設(shè)置 TTL | 8% |
| 5、清理歷史數(shù)據(jù) | 6% |
| 6、改進(jìn) kv 結(jié)構(gòu) | 1% |
| 7、定期 scan, 釋放已過期的內(nèi)存 | 1% |
| 8、降低可用性 | 3% |
| 9、壓縮 value | 32% |
| 10、遷移到兼容 Redis 協(xié)議的磁盤存儲項(xiàng)目 | 28% |
1、清理未使用的實(shí)例
有的業(yè)務(wù)下線了,實(shí)例還在,需要清理這類實(shí)例。
這個是最容易實(shí)現(xiàn)的,最快能優(yōu)化的,通過采集 Redis Metrics 數(shù)據(jù),篩出長期 QPS 非常低的實(shí)例(集群版本 Redis, 自身也會有 ping 等保活訪問),觀測連接數(shù)據(jù)等,和業(yè)務(wù)確認(rèn)并釋放
2、實(shí)例降配:提高內(nèi)存使用率
各種因素,導(dǎo)致實(shí)際使用的內(nèi)存,和申請的內(nèi)存差別較大,導(dǎo)致使用率上不去,存在內(nèi)存浪費(fèi)。比如:
-
業(yè)務(wù)容量預(yù)估偏差導(dǎo)致的內(nèi)存長期使用率偏低 -
業(yè)務(wù)進(jìn)入穩(wěn)定期,內(nèi)存不在快速增長,內(nèi)存使用率較穩(wěn)定
這些場景需要通過降配,將使用率至少穩(wěn)定在 70% 左右。
降配時,需要注意如下:
3、使用場景打標(biāo),允許部分場景內(nèi)存用滿
使用 Redis,在我司可歸類為【被動緩存】、【非被動緩存】兩類場景。
【被動緩存】
典型的緩存場景,用來擋在 MySQL 前面抗流量(先請求 Redis 拿數(shù)據(jù),沒拿到則到 MySQL 里取數(shù)據(jù),設(shè)置到 Redis),Redis 內(nèi)存用滿時也不用擴(kuò)容,設(shè)置好驅(qū)逐策略即可。
【非被動緩存】
搜廣推場景的特征數(shù)據(jù),Redis 里的數(shù)據(jù)是實(shí)時流、離線等業(yè)務(wù)主動寫入的。如果內(nèi)存到了 90% 告警線,需要及時擴(kuò)容,避免重要數(shù)據(jù)被驅(qū)逐。
通過合理的區(qū)分不同 Redis 實(shí)例的使用場景,制定不一樣的告警策略,允許部分場景 Redis 使用率 100%,可進(jìn)一步提高整個 Redis 的內(nèi)存使用率。
實(shí)施時需要注意如下:
1. 被標(biāo)記為【被動緩存】的實(shí)例,需要明確所有的 key 都設(shè)置了 TTL ,明確允許所有的 key 都允許被驅(qū)逐。否則會導(dǎo)致內(nèi)存用滿,然后寫入被拒的情況。
2. 被標(biāo)記為【被動緩存】的實(shí)例,在主從架構(gòu)中,可關(guān)閉主服務(wù)的 aof(aof 關(guān)閉涉及到 config rewrite 會阻塞主進(jìn)程 100ms ~ 400ms 左右,會對線上集群 rt 產(chǎn)生影響,應(yīng)盡量在業(yè)務(wù)低峰期操作),降低數(shù)據(jù)驅(qū)逐時的性能影響,提高性能。
4、合理設(shè)置 TTL
使用 Redis 時,99% 的場景 Key 是可過期刪除的。
只不過,不同的場景對 TTL 的要求是不一樣的,這個需要業(yè)務(wù)自行判斷。
但是 infra 可以把大實(shí)例的 TTL 比例全部撈出來從大到小依次過一遍。
以上都可以通過設(shè)置合理的 TTL,來優(yōu)化內(nèi)存使用。實(shí)施時需要注意如下:
1. 實(shí)施前需要采集 Redis Metrics 數(shù)據(jù),篩出內(nèi)存規(guī)格大,未設(shè)置 TTL key 占比高的實(shí)例。
2. 大部分場景其實(shí)業(yè)務(wù)也不知道合理的 TTL 是多少。所以需要準(zhǔn)備好 Key 的訪問時間(最后一次訪問)分布情況,這個需要 scan 分析,后文會提到這個工具。提供給業(yè)務(wù)做 TTL 決策。
3. 有了預(yù)期的 TTL 后,需要將所有的數(shù)據(jù)都刷一遍。所以需要一個刷 TTL 的運(yùn)維工具腳本,同時可以指定清理最后一次訪問距今時間的數(shù)據(jù)。
5、清理歷史數(shù)據(jù)
部分業(yè)務(wù)把 Redis 當(dāng)持久化存儲,但是中間數(shù)據(jù)結(jié)構(gòu)發(fā)生過變化,導(dǎo)致歷史無用數(shù)據(jù)占用內(nèi)存空間。
這個場景和和合理設(shè)置 TTL有點(diǎn)類似,同樣需要:
1. 準(zhǔn)備好 Key 的訪問時間(最后一次訪問)分布情況,提供給業(yè)務(wù)做數(shù)據(jù)清理決策。
2. 有了預(yù)期的清理邏輯后,需要一個清理 Key 的運(yùn)維工具腳本,功能包含【指定 key 前綴清理】、【指定清理最后一次訪問距今時間的數(shù)據(jù) Key】。
6、改進(jìn) kv 結(jié)構(gòu)
1. 部分業(yè)務(wù)把整個大的 json 對象一股腦的存到 Redis ,其實(shí)部分字段用不著,可以裁剪 value 的大小,減少內(nèi)存使用。
2. 部分場景,比如判斷用戶設(shè)備是否是新設(shè)備,采用 Bloomfilter 相比 String,相同數(shù)據(jù)規(guī)模,可以節(jié)省 90% 以上的內(nèi)存。
7、定期 scan,釋放已過期的內(nèi)存
因?yàn)?Redis 已過期 key 的清理策略,是惰性刪除的(已經(jīng)過期的 key ,只有被訪問過或者 hz 掃描到才會被刪除),所以通過定期使用 SCAN 命令掃描鍵空間并手動刪除已過期的鍵,可以更精細(xì)地管理 Redis 內(nèi)存,提高系統(tǒng)的穩(wěn)定性和資源利用效率。
實(shí)施時需要注意:
1. 選擇在業(yè)務(wù)低峰期進(jìn)行,控制好 SCAN 的速率,盡量減少對線上業(yè)務(wù)的影響。
8、降低可用性
在 dev、qa 環(huán)境中,可通過如下措施來進(jìn)一步降低成本:
1. 合并小實(shí)例,部分實(shí)例已經(jīng)是最小規(guī)格,但是內(nèi)存使用率只有不到 10% ,這種情況下,可以通過小實(shí)例合并來縮減成本
2. 在 dev、qa 等對可用性要求不高的環(huán)境里,可通過對集群、主備版本,降配到單實(shí)例規(guī)格降低成本。
9、壓縮 value
選擇合適的壓縮算法,對 value 進(jìn)行壓縮后存儲。
在我司的場景里,壓縮率高的可達(dá) 50%~80% ,意味著部分實(shí)例至少可優(yōu)化 50% 左右的內(nèi)存。
因?yàn)檫@個方案實(shí)施比較復(fù)雜,所以盡量挑選 100GB 以上的實(shí)例進(jìn)行優(yōu)化,性價比較高。適合壓縮的特征如下:
value 大(100b 以上),字符重復(fù)度高
我們準(zhǔn)備了 3 個主流的壓縮算法,gzip 、zstd、snappy 。測試下來 ,不同的壓縮算法特點(diǎn)如下:
gzip 、zstd :這兩個壓縮和解壓縮表現(xiàn)都不錯,性能比較均衡。在不同的 value 特征的壓縮 & 解壓縮性能表現(xiàn)差異不大
snappy :壓縮比較耗時,但是解壓縮非常快。
我本地對 852k 的一個 user_profile 數(shù)據(jù)做了一個測試。(不同大小的數(shù)據(jù)性能差異較大,最終應(yīng)該以線上數(shù)據(jù)流量的測試結(jié)果為準(zhǔn))
測試方法:運(yùn)行 100 次取均值
snappy
壓縮耗時:122722us
壓縮率:22.60%
解壓耗時:49us
gzip
壓縮耗時:39821us
壓縮率:15.79%
解壓耗時:3521us
zstd
壓縮耗時:6953us
壓縮率:17.08%
解壓耗時:3153us
最后 snappy 就直接否了,因?yàn)閴嚎s的資延時不符合預(yù)期。
然后不同的實(shí)例都驗(yàn)證下 gzip、zstd 哪個性能好就選擇哪個。具體實(shí)施時需要注意如下:
1. 準(zhǔn)備好 Redis 流量復(fù)制的工具,復(fù)制線上流量進(jìn)行 zstd、gzip 的壓縮、解壓縮性能測試,明確壓縮率、壓縮延時和解壓縮延時數(shù)據(jù)。
2. 定制 Redis 訪問客戶端,無縫兼容各種指令的 gzip 、zstd 壓縮數(shù)據(jù),做到應(yīng)用端不用改代碼,只需要升級客戶端版本就可以完成壓縮、解壓縮兼容。
3. 研發(fā)存量數(shù)據(jù)全量壓縮的運(yùn)維工具,這個工具支持指定壓縮算法、支持指定 Key 前綴壓縮、支持解壓縮等。
4. 注意開啟壓縮后,對應(yīng)用 CPU 等資源消耗的的影響,讀取延時普遍會增加 1~2ms 左右。
5. 刷線上存量的數(shù)據(jù)壓縮前,確保應(yīng)用都更新到兼容壓縮的 Redis 訪問客戶端了,然后對部分 key 灰度壓測,觀測線上情況,沒有問題后在全量刷。發(fā)現(xiàn)問題后及時解壓縮。
10、遷移到兼容 Redis 協(xié)議的磁盤存儲項(xiàng)目
早期,本著性能優(yōu)先的原則,所有的 Redis 實(shí)例都是【內(nèi)存型】。
隨著數(shù)據(jù)規(guī)模增大,內(nèi)存資源占用會隨之遞增,Redis 存儲成本大幅攀升。
另一方面,隨著業(yè)務(wù)的發(fā)展,當(dāng)業(yè)務(wù)進(jìn)入發(fā)展后期,數(shù)據(jù)量已經(jīng)形成一定規(guī)模,而數(shù)據(jù)的訪問頻度則慢慢降下來,資源使用率普遍偏低 。
針對這類問題,可重新從性能、和成本綜合評估業(yè)務(wù)更適合【內(nèi)存型】、【磁盤型】的 Redis 實(shí)例。
內(nèi)存型
優(yōu)點(diǎn):性能好(p99 延時很穩(wěn)定)、擴(kuò)展性好、支持水平伸縮
缺點(diǎn):成本高
磁盤型
基于 RocksDB 實(shí)現(xiàn)的磁盤存儲、兼容 Redis 協(xié)議的產(chǎn)品,在阿里云叫 Tair ESSD 型。社區(qū)里也有 pika 、kvrocks 這類項(xiàng)目。
優(yōu)點(diǎn):成本低,是內(nèi)存型的 16% 。有容量起點(diǎn),相比內(nèi)存型,至少存儲 64GB 以上才有性價比。
缺點(diǎn):性能一般(p99 延時存在波動,突刺效應(yīng)明顯),是內(nèi)存型的 70% 性能。且只支持垂直擴(kuò)容,沒法水平伸縮。
這個優(yōu)化措施涉及到數(shù)據(jù)的遷移,且需要兼顧業(yè)務(wù)穩(wěn)定性。所以實(shí)施起來比【壓縮 Value】還要復(fù)雜,主要注意點(diǎn)如下:
1. 如何篩選遷移到【磁盤型】的 Redis 實(shí)例?寫請求低于 10k/s ,讀請求低于 100k/s, 對 p99 時延要求不敏感,比如可以接受 avg 大于 0.5ms ,p99 5ms 的場景,且存儲容量非常大 100GB 以上 ,而且預(yù)期存儲容量會進(jìn)一步增長
2. 采集好【磁盤型】的 Metrics ,做好監(jiān)控觀測。阿里云只給了基礎(chǔ)的 Metrics,底層的數(shù)據(jù)指標(biāo),比如 RocksDB 層的、以及指令級的延時(對后面判斷指令性能問題非常有幫助)、QPS 等都需要通過 info 指令拿到信息后自己解析采集。
3. 準(zhǔn)備好 Redis 流量復(fù)制工具,復(fù)制線上流量到【磁盤型】Redis 目標(biāo)實(shí)例,對流量進(jìn)行等比,加倍回放,對每個遷移的實(shí)例針對性的進(jìn)行性能壓測驗(yàn)證。確保覆蓋每個指令的性能問題、兼容問題。
4. 對【磁盤型】實(shí)例做好容量規(guī)劃,QPS 增長評估。
5. 使用 DTS 進(jìn)行數(shù)據(jù)遷移時,確保原實(shí)例內(nèi)存至少有 20% 的冗余,否則需要先擴(kuò)容原實(shí)例在遷移。因?yàn)?DTS 是基于【Redis 主從復(fù)制這套邏輯】來進(jìn)行同步的,同步時,緩沖區(qū)需要占用內(nèi)存。
6. 如果原實(shí)例的寫入流量較大,DTS 遷移前,最好先調(diào)整下【client-output-buffer-limit replica】、【repl-backlog-size 】、【DTS 收到 Master 的 RDB 后,立馬回復(fù) ACK 的開關(guān)】這些參數(shù),避免同步反復(fù)失敗。
下面記錄整個項(xiàng)目使用阿里云 Tair 期間發(fā)現(xiàn)的性能問題、Bug,這個項(xiàng)目能夠順利完成,我們幾乎是從小白鼠開始,一路升級。
hash 結(jié)構(gòu)的 hgetall 性能 Bug, 已修復(fù)
全量離線分析不可用 Bug , 已修復(fù)
Cpu 100% 的監(jiān)控問題 ,已修復(fù)
數(shù)據(jù)每天的冷備份 backup 操作會對性能有比較大的影響,預(yù)計會將 backup 操作遷移到從庫執(zhí)行,已修復(fù)
zset 的 zrange 性能慢,用 zscan 可以避免這個問題
lrem 在 list 當(dāng) mq 使用的場景存在嚴(yán)重的性能問題
spop 會隨著 count 數(shù)、set 總數(shù)增加線性增加
也給阿里云提了很多需求(下面所列只是冰山一角),這里非常感謝阿里云的支持,協(xié)助整個項(xiàng)目落地。
Dataworks 支持寫入數(shù)據(jù)到非集群部署模式的 Redis 實(shí)例,也就是支持 Redis ESSD 實(shí)例
Redis ESSD 實(shí)例監(jiān)控指標(biāo)優(yōu)化
ESSD 云盤 IO 瓶頸導(dǎo)致的性能尖刺問題,會限制批量刷盤時的寫入速度(9 月中旬)已上線,需要升級小版本到 2.4.2.2
Redis ESSD 目前指令驗(yàn)證這塊比較繁瑣麻煩,后面能不能在 Redis ESSD 文檔里加上每個指令的算法復(fù)雜度,或者本身性能很糟糕的指令單獨(dú)標(biāo)出來。給選型做參考
優(yōu)化工具
在 Redis 成本優(yōu)化項(xiàng)目落地過程中,我們沉淀了一套輔助項(xiàng)目落地的 Redis 成本優(yōu)化工具,這些工具缺一不可,發(fā)揮了重要的作用。
Redis 工具集已開源:
https://github.com/taptap/redis-tools
Redis 流量復(fù)制 & 流量等比放大
在【遷移到兼容 Redis 協(xié)議的磁盤存儲項(xiàng)目】、【壓縮 value】項(xiàng)目中,都需要用到 Redis 流量復(fù)制工具。該工具實(shí)現(xiàn)了如下功能:
1. 支持只復(fù)制原實(shí)例指令輸出到控制臺,或復(fù)制流量回放到指定目標(biāo)實(shí)例
2. 支持只復(fù)制讀流量、只復(fù)制寫流量、讀寫流量一起復(fù)制
3. 支持流量等比放大回放
4. 支持原實(shí)例是集群模式時(集群模式 mget 訂閱到的是單 key,不符合真實(shí)業(yè)務(wù) mget),指定 mget keys 大小發(fā)送到目標(biāo)實(shí)例,且支持比例設(shè)置,比如 10% mget 的 keys=100, 40% mget 的 keys=30
Redis 數(shù)據(jù)在線壓縮 & 解壓縮
這個工具主要用在【壓縮 value】項(xiàng)目中,用于驗(yàn)證不同的壓縮算法的壓縮性能、解壓縮性能、壓縮率等。
實(shí)現(xiàn)了如下功能:
1. 支持指定壓縮算法 gzip、zstd,進(jìn)行壓縮性能、解壓縮性能、壓縮率等的計算
2. 支持復(fù)制線上流量進(jìn)行壓縮或解壓縮
3. 支持跑存量的數(shù)據(jù)進(jìn)行壓縮或解壓縮
Redis 數(shù)據(jù)定向清理 & 定向指定 TTL
這個工具主要用于【清理歷史數(shù)據(jù)】、【合理設(shè)置 TTL】等項(xiàng)目,主要實(shí)現(xiàn)了如下功能:
1. 支持指定 key 前綴刪除數(shù)據(jù)
2. 支持指定 key 前綴設(shè)置 TTL
3. 支持 dryrun 模式,只輸出操作的日志,實(shí)際上不進(jìn)行刪除或 TTL 設(shè)置。
4. 支持指定 key 的 MaxIdleTime 進(jìn)行刪除或 TTL 設(shè)置
Redis 掃描分析 Key 最后訪問時間
這個工具主要用于【清理歷史數(shù)據(jù)】、【合理設(shè)置 TTL】等項(xiàng)目,主要實(shí)現(xiàn)了如下功能:
支持掃描所有的 key ,打印 idelTime , 通過統(tǒng)計分析得到 key 的訪問時間分布
Redis 磁盤型實(shí)例指標(biāo)采集
通過阿里云的 OpenAPI ,采集獲取到 Redis ESSD(Tair) 實(shí)例列表,然后通過 info 指令拿到實(shí)例運(yùn)行時關(guān)鍵信息,通過解析 info 拿到關(guān)鍵指標(biāo),實(shí)現(xiàn)了:
1. 指令級的 QPS 、RT 、帶寬等數(shù)據(jù)觀測
2. RocksDB 底層的 Compactions、Flush 等事件數(shù)據(jù)觀測
優(yōu)化總結(jié)
工欲善其事必先利其器,在這次 Redis 優(yōu)化項(xiàng)目中,我們通過前期對優(yōu)化工具的研發(fā)和準(zhǔn)備,以及系統(tǒng)化的優(yōu)化措施的實(shí)施,成功降低了 Redis 的運(yùn)行成本,提高了資源利用效率,并且保證了線上系統(tǒng)的穩(wěn)定性。
整個過程中,我們實(shí)現(xiàn)了在不中斷服務(wù)的情況下進(jìn)行優(yōu)化,達(dá)到了零故障的目標(biāo)。
Reference
我們創(chuàng)建了一個高質(zhì)量的技術(shù)交流群,與優(yōu)秀的人在一起,自己也會優(yōu)秀起來,趕緊點(diǎn)擊加群,享受一起成長的快樂。
