如何改變Redis用不好的誤區(qū)?

2021-03-17    分類: 網(wǎng)站建設(shè)

在一個(gè)炎熱的夏天,引爆了埋藏已久的大炸彈。本文作者從實(shí)際案例出發(fā)講解 Redis 使用的誤區(qū)。

1案例一:一個(gè)產(chǎn)品線開發(fā)人員搭建起了一套龐大的價(jià)格存儲(chǔ)系統(tǒng),底層是關(guān)系型數(shù)據(jù)庫(kù),只用來(lái)處理一些事務(wù)性的操作和存放一些基礎(chǔ)數(shù)據(jù)。

在關(guān)系型數(shù)據(jù)庫(kù)的上面還有一套 MongoDB,因?yàn)?MongoDB 的文檔型數(shù)據(jù)結(jié)構(gòu),讓他們用起來(lái)很順手,同時(shí)也可以支撐一定量的并發(fā)。

在大部分的情況下,一次大數(shù)據(jù)量的計(jì)算后結(jié)果可以重用但會(huì)出現(xiàn)細(xì)節(jié)數(shù)據(jù)的頻繁更新,所以他們又在 MongoDB 上搭建了一層 Redis 的緩存。

這樣就形成了數(shù)據(jù)庫(kù)→MongoDB→Redis三級(jí)的方式,方案本身先不評(píng)價(jià)不是本文重點(diǎn),我們來(lái)看 Redis 這層的情況。

由于數(shù)據(jù)量巨大,所以需要 200GB 的 Redis,并且在真實(shí)的調(diào)用過(guò)程中,Redis 是請(qǐng)求量大的點(diǎn)。

當(dāng)然如果 Redis 有故障時(shí),也會(huì)有備用方案,從后面的 MongoDB 和數(shù)據(jù)庫(kù)中重新加載數(shù)據(jù)到 Redis,就是這么一套簡(jiǎn)單的方案上線了。

當(dāng)這個(gè)系統(tǒng)剛開始運(yùn)行的時(shí)候,一切都還安好,只是運(yùn)維同學(xué)有點(diǎn)傻眼了, 200GB 的 Redis 單服務(wù)器去做,它的故障可能性太大了。

所以大家建議將它分片,沒分不知道,一分嚇一跳,各種類型用的太多了,特別是里面還有一些類似消息隊(duì)列使用的場(chǎng)景。

由于開發(fā)同學(xué)對(duì) Redis 使用的注意點(diǎn)關(guān)注不夠,一味的濫用,一錘了事,所以讓事情變的困難了。

有些僥幸不死的想法是會(huì)傳染,這時(shí)的每個(gè)人都心存僥幸,懶惰心理,都想著:“這個(gè)應(yīng)該沒事,以后再說(shuō)吧,先做個(gè)主從,掛了就起從”,這種僥幸也是對(duì) Redis 的虛偽的信心,無(wú)知者無(wú)畏。

可惜事情往往就是怕什么來(lái)什么,在大家快樂的放肆使用時(shí),系統(tǒng)中重要的節(jié)點(diǎn) MongoDB 由于系統(tǒng)內(nèi)核版本的 Bug,造成整個(gè) MongoDB 集群掛了!(這里不多說(shuō) MongoDB 的事情,這也是一個(gè)好玩的哭器)。

當(dāng)然,這個(gè)對(duì)天天與故障為朋友的運(yùn)維同學(xué)來(lái)說(shuō)并沒什么,對(duì)整個(gè)系統(tǒng)來(lái)說(shuō)問題也不大,因?yàn)榇蟛糠终?qǐng)求調(diào)用都是在最上層的 Redis 中完成的,只要做一定降級(jí)就行,等拉起了 MongoDB 集群后自然就會(huì)好了。

但此時(shí)可別忘了那個(gè) Redis,是一個(gè) 200G 大的 Redis,更是帶了個(gè)從機(jī)的 Redis。

所以這時(shí)的 Redis 是絕對(duì)不能出任何問題的,一旦有故障,所有請(qǐng)求會(huì)立即全部打向最低層的關(guān)系型數(shù)據(jù)庫(kù),在如此大量的壓力下,數(shù)據(jù)庫(kù)瞬間就會(huì)癱瘓。

但是,怕什么來(lái)什么,還是出了狀況:主從 Redis 之間的網(wǎng)絡(luò)出現(xiàn)了一點(diǎn)小動(dòng)蕩,想想這么大的一個(gè)東西在主從同步,一旦網(wǎng)絡(luò)動(dòng)蕩了一下下,會(huì)怎么樣呢?

主從同步失敗,同步失敗,就直接開啟全同步,于是 200GB 的 Redis 瞬間開始全同步,網(wǎng)卡瞬間打滿。

為了保證 Redis 能夠繼續(xù)提供服務(wù),運(yùn)維同學(xué)直接關(guān)掉從機(jī),主從同步不存在了,流量也恢復(fù)正常。不過(guò),主從的備份架構(gòu)變成了單機(jī) Redis,心還是懸著的。

俗話說(shuō),福無(wú)雙至,禍不單行。這 Redis 由于下層降級(jí)的原因并發(fā)操作量每秒增加到四萬(wàn)多,AOF 和 RDB 庫(kù)明顯扛不住。

同樣為了保證能持續(xù)地提供服務(wù),運(yùn)維同學(xué)也關(guān)掉了 AOF 和 RDB 的數(shù)據(jù)持久化,連最后的保護(hù)也沒有了(其實(shí)這個(gè)保護(hù)本來(lái)也沒用,200GB 的 Redis 恢復(fù)太大了)。

至此,這個(gè) Redis 變成了完全的單機(jī)內(nèi)存型,除了祈禱它不要掛,已經(jīng)沒有任何方法了。

這事懸著好久,直到修復(fù) MongoDB 集群才了事。如此的僥幸,沒出大事,但心里會(huì)踏實(shí)嗎?回答是不會(huì)。

在這個(gè)案例中主要的問題在于:對(duì) Redis 過(guò)度依賴,Redis 看似為系統(tǒng)帶來(lái)了簡(jiǎn)單又方便的性能提升和穩(wěn)定性,但在使用中缺乏對(duì)不同場(chǎng)景的數(shù)據(jù)的分離造成了一個(gè)邏輯上的單點(diǎn)問題。

當(dāng)然這問題我們可以通過(guò)更合理的應(yīng)用架構(gòu)設(shè)計(jì)來(lái)解決,但是這樣解決不夠優(yōu)雅也不夠徹底,也增加了應(yīng)用層的架構(gòu)設(shè)計(jì)的麻煩。

Redis 的問題就應(yīng)該在基礎(chǔ)緩存層來(lái)解決,這樣即使還有類似的情況也沒有問題。

因?yàn)榛A(chǔ)緩存層已經(jīng)能適應(yīng)這樣的用法,也會(huì)讓應(yīng)用層的設(shè)計(jì)更為簡(jiǎn)單(簡(jiǎn)單一直是架構(gòu)設(shè)計(jì)所追求的,Redis 的大量隨意使用本身就是追求簡(jiǎn)單的副產(chǎn)品,那我們?yōu)槭裁床蛔屵@簡(jiǎn)單變?yōu)檎鎸?shí)呢?)

2案例二:我們?cè)賮?lái)看第二個(gè)案例,有個(gè)部門用自己現(xiàn)有 Redis 服務(wù)器做了一套日志系統(tǒng),將日志數(shù)據(jù)先存儲(chǔ)到 Redis 里面,再通過(guò)其他程序讀取數(shù)據(jù)并進(jìn)行分析和計(jì)算,用來(lái)做數(shù)據(jù)報(bào)表。

當(dāng)他們做完這個(gè)項(xiàng)目之后,這個(gè)日志組件讓他們覺得用的還很過(guò)癮。他們都覺得這個(gè)做法不錯(cuò),可以輕松地記錄日志,分析起來(lái)也挺快,還用什么公司的分布式日志服務(wù)???

隨著時(shí)間的流逝,這個(gè) Redis 上已經(jīng)悄悄地掛載了數(shù)千個(gè)客戶端,每秒的并發(fā)量數(shù)萬(wàn),系統(tǒng)的單核 CPU 使用率也接近 90% 了,此時(shí)這個(gè) Redis 已經(jīng)開始不堪重負(fù)。

終于,壓死駱駝的最后一根稻草來(lái)了,有程序向這個(gè)日志組件寫入了一條 7MB 的日志(哈哈,這個(gè)容量可以寫一部小說(shuō)了,這是什么日志?。?。

于是 Redis 堵死了,一旦堵死,數(shù)千個(gè)客戶端就全部無(wú)法連接,所有日志記錄的操作全部失敗。

其實(shí)日志記錄失敗本身應(yīng)該不至于影響正常業(yè)務(wù),但是由于這個(gè)日志服務(wù)不是公司標(biāo)準(zhǔn)的分布式日志服務(wù),所以關(guān)注的人很少。

最開始寫它的開發(fā)同學(xué)也不知道會(huì)有這么大的使用量,運(yùn)維同學(xué)更不知有這個(gè)非法的日志服務(wù)存在。

這個(gè)服務(wù)本身也沒有很好地設(shè)計(jì)容錯(cuò),所以在日志記錄的地方就直接拋出異常,結(jié)果全公司相當(dāng)一部分的業(yè)務(wù)系統(tǒng)都出現(xiàn)了故障,監(jiān)控系統(tǒng)中“5XX”的錯(cuò)誤直線上升。

一幫人欲哭無(wú)淚,頂著巨大的壓力排查問題,但是由于受災(zāi)面實(shí)在太廣,排障的壓力是可以想像的。

這個(gè)案例中看似是一個(gè)日志服務(wù)沒做好或者是開發(fā)流程管理不到位,而且很多日志服務(wù)也都用到了 Redis 做收集數(shù)據(jù)的緩沖,好像也沒什么問題。

其實(shí)不然,像這樣大規(guī)模大流量的日志系統(tǒng)從收集到分析要細(xì)細(xì)考慮的技術(shù)點(diǎn)是巨大的,而不只是簡(jiǎn)單的寫入性能的問題。

在這個(gè)案例中 Redis 給程序帶來(lái)的是超簡(jiǎn)單的性能解決方案,但這個(gè)簡(jiǎn)單是相對(duì)的,它是有場(chǎng)景限制的。

在這里,這樣的簡(jiǎn)單就是毒藥,無(wú)知的吃下是要害死自己的,這就像“一條在小河溝里無(wú)所不能傲慢的小魚,那是因?yàn)樗鼪]見過(guò)大海,等到了大?!薄?/p>

在這個(gè)案例的另一問題:一個(gè)非法日志服務(wù)的存在,表面上是管理問題,實(shí)質(zhì)上還是技術(shù)問題。

因?yàn)?Redis 的使用無(wú)法像關(guān)系型數(shù)據(jù)庫(kù)那樣有 DBA 的監(jiān)管,它的運(yùn)維者無(wú)法管理和提前知道里面放的是什么數(shù)據(jù),開發(fā)者也無(wú)需任何申明就可以向 Redis 中寫入數(shù)據(jù)并使用。

所以這里我們發(fā)現(xiàn) Redis 的使用沒這些場(chǎng)景的管理后在長(zhǎng)期的使用中比較容易失控,我們需要一個(gè)對(duì) Redis 使用可治理和管控的透明層。

兩個(gè)小例子中看到在 Redis 亂用的那個(gè)年代里,使用它的兄弟們一定是痛的,承受了各種故障的狂轟濫炸:

  • Redis 被 Keys 命令堵塞了
  • Keepalived 切換虛 IP 失敗,虛IP被釋放了
  • 用 Redis 做計(jì)算了,Redis 的 CPU 占用率成了 100% 了
  • 主從同步失敗了
  • Redis 客戶端連接數(shù)爆了
  • ……

如何改變 Redis 用不好的誤區(qū)?

這樣的亂象一定是不可能繼續(xù)了,最少在同程,這樣的使用方式不可以再繼續(xù)了,使用者也開始從喜歡到痛苦了。

怎么辦?這是一個(gè)很沉重的事情:“一個(gè)被人用亂的系統(tǒng)就像一桌燒壞的菜,讓你重新回爐,還讓人叫好,是很困難的”。

關(guān)鍵是已經(jīng)用的這樣了,總不可能讓所有系統(tǒng)都停下來(lái),等待新系統(tǒng)上線并瞬間切換好吧?這是個(gè)什么活:“高速公路上換輪胎”。

但問題出現(xiàn)了總是要解決的,想了再想,論了再論,總結(jié)以下幾點(diǎn):

  • 必須搭建完善的監(jiān)控系統(tǒng),在這之前要先預(yù)警,不能等到發(fā)生了,我們才發(fā)現(xiàn)問題。
  • 控制和引導(dǎo) Redis 的使用,我們需要有自己研發(fā)的 Redis 客戶端,在使用時(shí)就開始控制和引導(dǎo)。
  • Redis的部分角色要改,將 Redis 由 Storage 角色降低為 Cache 角色。
  • Redis 的持久化方案要重新做,需要自己研發(fā)一個(gè)基于 Redis 協(xié)議的持久化方案讓使用者可以把 Redis 當(dāng) DB 用。
  • Redis 的高可用要按照?qǐng)鼍胺珠_,根據(jù)不同的場(chǎng)景決定采用不同的高可用方案。

留給開發(fā)同學(xué)的時(shí)間并不多,只有兩個(gè)月的時(shí)間來(lái)完成這些事情。這事還是很有挑戰(zhàn)的,考驗(yàn)開發(fā)同學(xué)這個(gè)輪胎到底能不換下來(lái)的時(shí)候到來(lái)了。

同學(xué)們開始研發(fā)我們自己的 Redis 緩存系統(tǒng),下面我們來(lái)看一下這個(gè)代號(hào)為鳳凰的緩存系統(tǒng)第一版方案:

首先是監(jiān)控系統(tǒng)。原有的開源 Redis 監(jiān)控從大面上講只是一些監(jiān)控工具,不能算作一個(gè)完整的監(jiān)控系統(tǒng)。當(dāng)然這個(gè)監(jiān)控是全方位從客戶端開始一直到返回?cái)?shù)據(jù)的全鏈路的監(jiān)控。

其次是改造 Redis 客戶端。廣泛使用的 Redis 客戶端有的太簡(jiǎn)單,有的太重,總之不是我們想要的東西。

比如 .Net 下的 BookSleeve 和 servicestack.Redis(同程還有一點(diǎn)老的 .Net 開發(fā)的應(yīng)用),前者已經(jīng)好久沒人維護(hù)了,后者直接收費(fèi)了。

好吧,我們就開發(fā)一個(gè)客戶端,然后督促全公司的研發(fā)用它來(lái)替換目前正在使用的客戶端。

在這個(gè)客戶端里面,我們植入了日志記錄,記錄了代碼對(duì) Redis 的所有操作事件,例如耗時(shí)、Key、Value 大小、網(wǎng)絡(luò)斷開等。

我們將這些有問題的事件在后臺(tái)進(jìn)行收集,由一個(gè)收集程序進(jìn)行分析和處理,同時(shí)取消了直接的 IP 端口連接方式,通過(guò)一個(gè)配置中心分配 IP 地址和端口。

當(dāng) Redis 發(fā)生問題并需要切換時(shí),直接在配置中心修改,由配置中心推送新的配置到客戶端,這樣就免去了 Redis 切換時(shí)需要業(yè)務(wù)員修改配置文件的麻煩。

另外,把 Redis 的命令操作分拆成兩部分:

  • 安全的命令,對(duì)于安全的命令可以直接使用。
  • 不安全的命令,對(duì)于不安全的命令需要分析和審批后才能打開,這也是由配置中心控制的。

這樣就解決了研發(fā)人員使用 Redis 時(shí)的規(guī)范問題,并且將 Redis 定位為緩存角色,除非有特殊需求,否則一律以緩存角色對(duì)待。

最后,對(duì) Redis 的部署方式也進(jìn)行了修改,以前是 Keepalived 的方式,現(xiàn)在換成了主從+哨兵的模式。

另外,我們自己實(shí)現(xiàn)了 Redis 的分片,如果業(yè)務(wù)需要申請(qǐng)大容量的 Redis 數(shù)據(jù)庫(kù),就會(huì)把 Redis 拆分成多片,通過(guò) Hash 算法均衡每片的大小,這樣的分片對(duì)應(yīng)用層也是無(wú)感知的。

當(dāng)然重客戶端方式不好,并且我們要做的是緩存,不僅僅是單單的 Redis,于是我們會(huì)做一個(gè) Redis 的 Proxy,提供統(tǒng)一的入口點(diǎn)。

Proxy 可以多份部署,客戶端無(wú)論連接的是哪個(gè) Proxy,都能取得完整的集群數(shù)據(jù),這樣就基本完成了按場(chǎng)景選擇不同的部署方式的問題。

這樣的一個(gè) Proxy 也解決了多種開發(fā)語(yǔ)言的問題,例如,運(yùn)維系統(tǒng)是使用 Python 開發(fā)的,也需要用到 Redis,就可以直接連 Proxy,然后接入到統(tǒng)一的 Redis 體系中來(lái)。

做客戶端也好,做 Proxy 也好,不只是為代理請(qǐng)求而是為了統(tǒng)一的治理 Redis 緩存的使用,不讓亂象出現(xiàn)。

讓緩存在一個(gè)可管可控的場(chǎng)景下穩(wěn)定的運(yùn)維,讓開發(fā)者可以安全并肆無(wú)忌憚繼續(xù)亂用 Redis,但這個(gè)“亂”是被虛擬化的亂,因?yàn)樗牡讓邮强梢灾卫淼摹?/p>

系統(tǒng)架構(gòu)圖

當(dāng)然以上這些改造都需要在不影響業(yè)務(wù)的情況下進(jìn)行。實(shí)現(xiàn)這個(gè)還是有不小的挑戰(zhàn),特別是分片。

將一個(gè) Redis 拆分成多個(gè),還能讓客戶端正確找到所需要的 Key,這需要非常小心,因?yàn)樯杂胁簧鳎瑑?nèi)存的數(shù)據(jù)就全部消失了。

在這段時(shí)間里,我們開發(fā)了多種同步工具,幾乎把 Redis 的主從協(xié)議整個(gè)實(shí)現(xiàn)了一遍,終于可以將 Redis 平滑過(guò)渡到新的模式上了。

名稱欄目:如何改變Redis用不好的誤區(qū)?
URL分享:http://www.bm7419.com/news/105336.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、品牌網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì)公司、做網(wǎng)站、全網(wǎng)營(yíng)銷推廣手機(jī)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)