為什么分布式使用redis

絕大部分寫業(yè)務(wù)的程序員协怒,在實(shí)際開發(fā)中使用 Redis 的時候奕删,只會 Set Value 和 Get Value 兩個操作奕坟,對 Redis 整體缺乏一個認(rèn)知。這里對 Redis 常見問題做一個總結(jié)罗侯,解決大家的知識盲點(diǎn)。

1溪猿、為什么使用 Redis

在項(xiàng)目中使用 Redis钩杰,主要考慮兩個角度:性能和并發(fā)。如果只是為了分布式鎖這些其他功能诊县,還有其他中間件 Zookpeer 等代替讲弄,并非一定要使用 Redis。

性能:

如下圖所示依痊,我們在碰到需要執(zhí)行耗時特別久避除,且結(jié)果不頻繁變動的 SQL,就特別適合將運(yùn)行結(jié)果放入緩存胸嘁。這樣瓶摆,后面的請求就去緩存中讀取,使得請求能夠迅速響應(yīng)性宏。

特別是在秒殺系統(tǒng)群井,在同一時間,幾乎所有人都在點(diǎn)毫胜,都在下單书斜。诬辈。。執(zhí)行的是同一操作———向數(shù)據(jù)庫查數(shù)據(jù)荐吉。

為什么我們做分布式使用Redis焙糟?

根據(jù)交互效果的不同,響應(yīng)時間沒有固定標(biāo)準(zhǔn)样屠。在理想狀態(tài)下穿撮,我們的頁面跳轉(zhuǎn)需要在瞬間解決,對于頁內(nèi)操作則需要在剎那間解決瞧哟。

并發(fā):

如下圖所示混巧,在大并發(fā)的情況下,所有的請求直接訪問數(shù)據(jù)庫勤揩,數(shù)據(jù)庫會出現(xiàn)連接異常咧党。這個時候,就需要使用 Redis 做一個緩沖操作陨亡,讓請求先訪問到 Redis傍衡,而不是直接訪問數(shù)據(jù)庫。

為什么我們做分布式使用Redis负蠕?

使用 Redis 的常見問題

  • 緩存和數(shù)據(jù)庫雙寫一致性問題
  • 緩存雪崩問題
  • 緩存擊穿問題
  • 緩存的并發(fā)競爭問題

2蛙埂、單線程的 Redis 為什么這么快

這個問題是對 Redis 內(nèi)部機(jī)制的一個考察。很多人都不知道 Redis 是單線程工作模型遮糖。

原因主要是以下三點(diǎn):

  • 純內(nèi)存操作
  • 單線程操作绣的,避免了頻繁的上下文切換
  • 采用了非阻塞 I/O 多路復(fù)用機(jī)制

仔細(xì)說一說 I/O 多路復(fù)用機(jī)制,打一個比方:小名在 A 城開了一家快餐店店欲账,負(fù)責(zé)同城快餐服務(wù)屡江。小明因?yàn)橘Y金限制,雇傭了一批配送員赛不,然后小曲發(fā)現(xiàn)資金不夠了惩嘉,只夠買一輛車送快遞。加君羊:874811168即可免費(fèi)領(lǐng)取架構(gòu)資料一份踢故。

經(jīng)營方式一

客戶每下一份訂單文黎,小明就讓一個配送員盯著,然后讓人開車去送殿较。慢慢的小曲就發(fā)現(xiàn)了這種經(jīng)營方式存在下述問題:

  • 時間都花在了搶車上了耸峭,大部分配送員都處在閑置狀態(tài),搶到車才能去送斜脂。
  • 隨著下單的增多抓艳,配送員也越來越多,小明發(fā)現(xiàn)快遞店里越來越擠,沒辦法雇傭新的配送員了玷或。
  • 配送員之間的協(xié)調(diào)很花時間儡首。

綜合上述缺點(diǎn),小明痛定思痛偏友,提出了經(jīng)營方式二蔬胯。

經(jīng)營方式二

小明只雇傭一個配送員。當(dāng)客戶下單位他,小明按送達(dá)地點(diǎn)標(biāo)注好氛濒,依次放在一個地方。最后鹅髓,讓配送員依次開著車去送舞竿,送好了就回來拿下一個。上述兩種經(jīng)營方式對比窿冯,很明顯第二種效率更高骗奖。

在上述比喻中:

  • 每個配送員→每個線程
  • 每個訂單→每個 Socket(I/O 流)
  • 訂單的送達(dá)地點(diǎn)→Socket 的不同狀態(tài)
  • 客戶送餐請求→來自客戶端的請求
  • 明曲的經(jīng)營方式→服務(wù)端運(yùn)行的代碼
  • 一輛車→CPU 的核數(shù)

于是有了如下結(jié)論:

  • 經(jīng)營方式一就是傳統(tǒng)的并發(fā)模型,每個 I/O 流(訂單)都有一個新的線程(配送員)管理醒串。
  • 經(jīng)營方式二就是 I/O 多路復(fù)用执桌。只有單個線程(一個配送員),通過跟蹤每個 I/O 流的狀態(tài)(每個配送員的送達(dá)地點(diǎn))芜赌,來管理多個 I/O 流仰挣。

下面類比到真實(shí)的 Redis 線程模型,如圖所示:

為什么我們做分布式使用Redis缠沈?

Redis-client 在操作的時候膘壶,會產(chǎn)生具有不同事件類型的 Socket。在服務(wù)端洲愤,有一段 I/O 多路復(fù)用程序香椎,將其置入隊(duì)列之中。然后禽篱,文件事件分派器,依次去隊(duì)列中取馍惹,轉(zhuǎn)發(fā)到不同的事件處理器中躺率。

3、Redis 的數(shù)據(jù)類型及使用場景

一個合格的程序員万矾,這五種類型都會用到悼吱。

String

最常規(guī)的 set/get 操作,Value 可以是 String 也可以是數(shù)字良狈。一般做一些復(fù)雜的計(jì)數(shù)功能的緩存后添。

Hash

這里 Value 存放的是結(jié)構(gòu)化的對象,比較方便的就是操作其中的某個字段薪丁。我在做單點(diǎn)登錄的時候遇西,就是用這種數(shù)據(jù)結(jié)構(gòu)存儲用戶信息疟丙,以 CookieId 作為 Key赁项,設(shè)置 30 分鐘為緩存過期時間,能很好的模擬出類似 Session 的效果。

List

使用 List 的數(shù)據(jù)結(jié)構(gòu)锰悼,可以做簡單的消息隊(duì)列的功能。另外镜硕,可以利用 lrange 命令闻妓,做基于 Redis 的分頁功能,性能極佳渗常,用戶體驗(yàn)好壮不。

Set

因?yàn)?Set 堆放的是一堆不重復(fù)值的集合。所以可以做全局去重的功能皱碘。我們的系統(tǒng)一般都是集群部署询一,使用 JVM 自帶的 Set 比較麻煩。另外尸执,就是利用交集家凯、并集、差集等操作如失,可以計(jì)算共同喜好绊诲,全部的喜好,自己獨(dú)有的喜好等功能褪贵。

Sorted Set

Sorted Set 多了一個權(quán)重參數(shù) Score掂之,集合中的元素能夠按 Score 進(jìn)行排列〈喽。可以做排行榜應(yīng)用世舰,取 TOP N 操作。Sorted Set 可以用來做延時任務(wù)槽卫。

4跟压、Redis 的過期策略和內(nèi)存淘汰機(jī)制

Redis 是否用到家,從這就能看出來歼培。比如你 Redis 只能存 5G 數(shù)據(jù)震蒋,可是你寫了 10G,那會刪 5G 的數(shù)據(jù)躲庄。怎么刪的查剖,這個問題思考過么?

正解:Redis 采用的是定期刪除+惰性刪除策略噪窘。

為什么不用定時刪除策略

定時刪除笋庄,用一個定時器來負(fù)責(zé)監(jiān)視 Key,過期則自動刪除。雖然內(nèi)存及時釋放直砂,但是十分消耗 CPU 資源菌仁。在大并發(fā)請求下,CPU 要將時間應(yīng)用在處理請求哆键,而不是刪除 Key掘托,因此沒有采用這一策略。

定期刪除+惰性刪除如何工作

定期刪除籍嘹,Redis 默認(rèn)每個 100ms 檢查闪盔,有過期 Key 則刪除。需要說明的是辱士,Redis 不是每個 100ms 將所有的 Key 檢查一次泪掀,而是隨機(jī)抽取進(jìn)行檢查。如果只采用定期刪除策略颂碘,會導(dǎo)致很多 Key 到時間沒有刪除异赫。于是,惰性刪除派上用場头岔。

采用定期刪除+惰性刪除就沒其他問題了么

不是的塔拳,如果定期刪除沒刪除掉 Key。并且你也沒及時去請求 Key峡竣,也就是說惰性刪除也沒生效靠抑。這樣,Redis 的內(nèi)存會越來越高适掰。那么就應(yīng)該采用內(nèi)存淘汰機(jī)制颂碧。

在 redis.conf 中有一行配置:

maxmemory-policy volatile-lru

該配置就是配內(nèi)存淘汰策略的:

  • noeviction:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,新寫入操作會報(bào)錯类浪。
  • allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時载城,在鍵空間中,移除最近最少使用的 Key费就。(推薦使用诉瓦,目前項(xiàng)目在用這種)(最近最久使用算法)
  • allkeys-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中力细,隨機(jī)移除某個 Key垦搬。(應(yīng)該也沒人用吧,你不刪最少使用 Key艳汽,去隨機(jī)刪)
  • volatile-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中对雪,移除最近最少使用的 Key河狐。這種情況一般是把 Redis 既當(dāng)緩存,又做持久化存儲的時候才用。(不推薦)
  • volatile-random:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時馋艺,在設(shè)置了過期時間的鍵空間中栅干,隨機(jī)移除某個 Key。(依然不推薦)
  • volatile-ttl:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時捐祠,在設(shè)置了過期時間的鍵空間中碱鳞,有更早過期時間的 Key 優(yōu)先移除。(不推薦)

5踱蛀、Redis 和數(shù)據(jù)庫雙寫一致性問題

一致性問題還可以再分為最終一致性和強(qiáng)一致性窿给。數(shù)據(jù)庫和緩存雙寫,就必然會存在不一致的問題率拒。前提是如果對數(shù)據(jù)有強(qiáng)一致性要求崩泡,不能放緩存。我們所做的一切猬膨,只能保證最終一致性角撞。

另外,我們所做的方案從根本上來說勃痴,只能降低不一致發(fā)生的概率谒所。因此,有強(qiáng)一致性要求的數(shù)據(jù)沛申,不能放緩存劣领。首先,采取正確更新策略污它,先更新數(shù)據(jù)庫剖踊,再刪緩存。其次衫贬,因?yàn)榭赡艽嬖趧h除緩存失敗的問題德澈,提供一個補(bǔ)償措施即可,例如利用消息隊(duì)列固惯。

6梆造、如何應(yīng)對緩存穿透和緩存雪崩問題

這兩個問題,一般中小型傳統(tǒng)軟件企業(yè)很難碰到葬毫。如果有大并發(fā)的項(xiàng)目镇辉,流量有幾百萬左右,這兩個問題一定要深刻考慮贴捡。緩存穿透忽肛,即黑客故意去請求緩存中不存在的數(shù)據(jù),導(dǎo)致所有的請求都懟到數(shù)據(jù)庫上烂斋,從而數(shù)據(jù)庫連接異常屹逛。

緩存穿透解決方案:

  • 利用互斥鎖础废,緩存失效的時候,先去獲得鎖罕模,得到鎖了评腺,再去請求數(shù)據(jù)庫。沒得到鎖淑掌,則休眠一段時間重試蒿讥。
  • 采用異步更新策略,無論 Key 是否取到值抛腕,都直接返回芋绸。Value 值中維護(hù)一個緩存失效時間,緩存如果過期兽埃,異步起一個線程去讀數(shù)據(jù)庫侥钳,更新緩存。需要做緩存預(yù)熱(項(xiàng)目啟動前柄错,先加載緩存)操作舷夺。
  • 提供一個能迅速判斷請求是否有效的攔截機(jī)制,比如售貌,利用布隆過濾器给猾,內(nèi)部維護(hù)一系列合法有效的 Key。迅速判斷出颂跨,請求所攜帶的 Key 是否合法有效敢伸。如果不合法,則直接返回恒削。

緩存雪崩池颈,即緩存同一時間大面積的失效,這個時候又來了一波請求钓丰,結(jié)果請求都懟到數(shù)據(jù)庫上躯砰,從而導(dǎo)致數(shù)據(jù)庫連接異常。

緩存雪崩解決方案:

  • 給緩存的失效時間携丁,加上一個隨機(jī)值琢歇,避免集體失效。
  • 使用互斥鎖梦鉴,但是該方案吞吐量明顯下降了李茫。
  • 雙緩存。我們有兩個緩存肥橙,緩存 A 和緩存 B魄宏。緩存 A 的失效時間為 20 分鐘,緩存 B 不設(shè)失效時間存筏。自己做緩存預(yù)熱操作娜庇。
  • 然后細(xì)分以下幾個小點(diǎn):從緩存 A 讀數(shù)據(jù)庫塔次,有則直接返回;A 沒有數(shù)據(jù)名秀,直接從 B 讀數(shù)據(jù),直接返回藕溅,并且異步啟動一個更新線程匕得,更新線程同時更新緩存 A 和緩存 B。

7巾表、如何解決 Redis 的并發(fā)競爭 Key 問題

這個問題大致就是汁掠,同時有多個子系統(tǒng)去 Set 一個 Key。這個時候要注意什么呢集币?大家基本都是推薦用 Redis 事務(wù)機(jī)制考阱。

但是我并不推薦使用 Redis 的事務(wù)機(jī)制。因?yàn)槲覀兊纳a(chǎn)環(huán)境鞠苟,基本都是 Redis 集群環(huán)境乞榨,做了數(shù)據(jù)分片操作。你一個事務(wù)中有涉及到多個 Key 操作的時候当娱,這多個 Key 不一定都存儲在同一個 redis-server 上吃既。因此,Redis 的事務(wù)機(jī)制跨细,十分雞肋鹦倚。

如果對這個 Key 操作,不要求順序

這種情況下冀惭,準(zhǔn)備一個分布式鎖震叙,大家去搶鎖,搶到鎖就做 set 操作即可散休,比較簡單媒楼。

如果對這個 Key 操作,要求順序

假設(shè)有一個 key1溃槐,系統(tǒng) A 需要將 key1 設(shè)置為 valueA匣砖,系統(tǒng) B 需要將 key1 設(shè)置為 valueB,系統(tǒng) C 需要將 key1 設(shè)置為 valueC昏滴。

期望按照 key1 的 value 值按照 valueA > valueB > valueC 的順序變化猴鲫。這種時候我們在數(shù)據(jù)寫入數(shù)據(jù)庫的時候,需要保存一個時間戳谣殊。

假設(shè)時間戳如下:

系統(tǒng) A key 1 {valueA 3:00}

系統(tǒng) B key 1 {valueB 3:05}

系統(tǒng) C key 1 {valueC 3:10}

那么拂共,假設(shè)系統(tǒng) B 先搶到鎖,將 key1 設(shè)置為{valueB 3:05}姻几。接下來系統(tǒng) A 搶到鎖宜狐,發(fā)現(xiàn)自己的 valueA 的時間戳早于緩存中的時間戳势告,那就不做 set 操作了,以此類推抚恒。其他方法咱台,比如利用隊(duì)列,將 set 方法變成串行訪問也可以俭驮。加君羊:874811168即可免費(fèi)領(lǐng)取架構(gòu)資料一份回溺。

8、總結(jié)

Redis 在國內(nèi)各大公司都能看到其身影混萝,比如我們熟悉的新浪遗遵,阿里,騰訊逸嘀,百度车要,美團(tuán),小米等崭倘。學(xué)習(xí) Redis翼岁,這幾方面尤其重要:Redis 客戶端、Redis 高級功能绳姨、Redis 持久化和開發(fā)運(yùn)維常用問題探討登澜、Redis 復(fù)制的原理和優(yōu)化策略、Redis 分布式解決方案等飘庄。

出處:http://www.cnblogs.com/yaodengyan/p/9717080.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脑蠕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子跪削,更是在濱河造成了極大的恐慌谴仙,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碾盐,死亡現(xiàn)場離奇詭異晃跺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)毫玖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門掀虎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人付枫,你說我怎么就攤上這事烹玉。” “怎么了阐滩?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵二打,是天一觀的道長。 經(jīng)常有香客問我掂榔,道長继效,這世上最難降的妖魔是什么症杏? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮瑞信,結(jié)果婚禮上厉颤,老公的妹妹穿的比我還像新娘。我一直安慰自己凡简,他們只是感情好走芋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潘鲫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪肋杖。 梳的紋絲不亂的頭發(fā)上溉仑,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機(jī)與錄音状植,去河邊找鬼浊竟。 笑死,一個胖子當(dāng)著我的面吹牛津畸,可吹牛的內(nèi)容都是我干的振定。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肉拓,長吁一口氣:“原來是場噩夢啊……” “哼后频!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起暖途,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤卑惜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后驻售,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體露久,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年欺栗,在試婚紗的時候發(fā)現(xiàn)自己被綠了毫痕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡迟几,死狀恐怖消请,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瘤旨,我是刑警寧澤梯啤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站存哲,受9級特大地震影響因宇,放射性物質(zhì)發(fā)生泄漏七婴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一察滑、第九天 我趴在偏房一處隱蔽的房頂上張望打厘。 院中可真熱鬧,春花似錦贺辰、人聲如沸户盯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽莽鸭。三九已至,卻和暖如春吃靠,著一層夾襖步出監(jiān)牢的瞬間硫眨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工巢块, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留礁阁,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓族奢,卻偏偏與公主長得像姥闭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子越走,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容