使用Redis做分布式

2022-02-25 21:33:11 字數 3479 閱讀 3812

在專案中使用 redis,主要考慮兩個角度:效能和併發。如果只是為了分布式鎖這些其他功能,還有其他中介軟體 zookpeer 等代替,並非一定要使用 redis。

效能:

如下圖所示,我們在碰到需要執行耗時特別久,且結果不頻繁變動的 sql,就特別適合將執行結果放入快取。這樣,後面的請求就去快取中讀取,使得請求能夠迅速響應。

特別是在秒殺系統,在同一時間,幾乎所有人都在點,都在下單。。。執行的是同一操作———向資料庫查資料。

根據互動效果的不同,響應時間沒有固定標準。在理想狀態下,我們的頁面跳轉需要在瞬間解決,對於頁內操作則需要在剎那間解決。

併發:

如下圖所示,在大併發的情況下,所有的請求直接訪問資料庫,資料庫會出現連線異常。這個時候,就需要使用 redis 做乙個緩衝操作,讓請求先訪問到 redis,而不是直接訪問資料庫。

使用 redis 的常見問題這個問題是對 redis 內部機制的乙個考察。很多人都不知道 redis 是單執行緒工作模型。

原因主要是以下三點:

仔細說一說 i/o 多路復用機制,打乙個比方:小名在 a 城開了一家快餐店店,負責同城快餐服務。小明因為資金限制,僱傭了一批配送員,然後小曲發現資金不夠了,只夠買一輛車送快遞。

經營方式一

時間都花在了搶車上了,大部分配送員都處在閒置狀態,搶到車才能去送。

經營方式二

小明只僱傭乙個配送員。當客戶下單,小明按送達地點標註好,依次放在乙個地方。最後,讓配送員依次開著車去送,送好了就回來拿下乙個。上述兩種經營方式對比,很明顯第二種效率更高。

在上述比喻中:

於是有了如下結論:

下面模擬到真實的 redis 執行緒模型,如圖所示:

redis-client 在操作的時候,會產生具有不同事件型別的 socket。在服務端,有一段 i/o 多路復用程式,將其置入佇列之中。然後,檔案事件分派器,依次去佇列中取,**到不同的事件處理器中。

乙個合格的程式設計師,這五種型別都會用到。

string

最常規的 set/get 操作,value 可以是 string 也可以是數字。一般做一些複雜的計數功能的快取。

hash

這裡 value 存放的是結構化的物件,比較方便的就是操作其中的某個字段。我在做單點登入的時候,就是用這種資料結構儲存使用者資訊,以 cookieid 作為 key,設定 30 分鐘為快取過期時間,能很好的模擬出類似 session 的效果。

list

使用 list 的資料結構,可以做簡單的訊息佇列的功能。另外,可以利用 lrange 命令,做基於 redis 的分頁功能,效能極佳,使用者體驗好。

set因為 set 堆放的是一堆不重複值的集合。所以可以做全域性去重的功能。我們的系統一般都是集群部署,使用 jvm 自帶的 set 比較麻煩。另外,就是利用交集、並集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能。

sorted set

sorted set 多了乙個權重引數 score,集合中的元素能夠按 score 進行排列。可以做排行榜應用,取 top n 操作。sorted set 可以用來做延時任務。

redis 是否用到家,從這就能看出來。比如你 redis 只能存 5g 資料,可是你寫了 10g,那會刪 5g 的資料。怎麼刪的,這個問題思考過麼?

正解:redis 採用的是定期刪除+惰性刪除策略。

為什麼不用定時刪除策略

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

定期刪除,redis 預設每個 100ms 檢查,有過期 key 則刪除。需要說明的是,redis 不是每個 100ms 將所有的 key 檢查一次,而是隨機抽取進行檢查。如果只採用定期刪除策略,會導致很多 key 到時間沒有刪除。於是,惰性刪除派上用場。

採用定期刪除+惰性刪除就沒其他問題了麼

在 redis.conf 中有一行配置:

# maxmemory-policy volatile-lru

該配置就是配記憶體淘汰策略的:一致性問題還可以再分為最終一致性和強一致性。資料庫和快取雙寫,就必然會存在不一致的問題。前提是如果對資料有強一致性要求,不能放快取。我們所做的一切,只能保證最終一致性。

另外,我們所做的方案從根本上來說,只能降低不一致發生的概率。因此,有強一致性要求的資料,不能放快取。首先,採取正確更新策略,先更新資料庫,再刪快取。其次,因為可能存在刪除快取失敗的問題,提供乙個補償措施即可,例如利用訊息佇列。

這兩個問題,一般中小型傳統軟體企業很難碰到。如果有大併發的專案,流量有幾百萬左右,這兩個問題一定要深刻考慮。快取穿透,即黑客故意去請求快取中不存在的資料,導致所有的請求都懟到資料庫上,從而資料庫連線異常。

快取穿透解決方案:

快取雪崩,即快取同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到資料庫上,從而導致資料庫連線異常。

快取雪崩解決方案:這個問題大致就是,同時有多個子系統去 set 乙個 key。這個時候要注意什麼呢?大家基本都是推薦用 redis 事務機制。

但是並不推薦使用 redis 的事務機制。因為我們的生產環境,基本都是 redis 集群環境,做了資料分片操作。你乙個事務中有涉及到多個 key 操作的時候,這多個 key 不一定都儲存在同乙個 redis-server 上。因此,redis 的事務機制,十分雞肋。

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

這種情況下,準備乙個分布式鎖,大家去搶鎖,搶到鎖就做 set 操作即可,比較簡單。

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

假設有乙個 key1,系統 a 需要將 key1 設定為 valuea,系統 b 需要將 key1 設定為 valueb,系統 c 需要將 key1 設定為 valuec。

期望按照 key1 的 value 值按照 valuea > valueb > valuec 的順序變化。這種時候我們在資料寫入資料庫的時候,需要儲存乙個時間戳

假設時間戳如下

系統 a key 1

系統 b key 1

系統 c key 1

那麼,假設系統 b 先搶到鎖,將 key1 設定為。接下來系統 a 搶到鎖,發現自己的 valuea 的時間戳早於快取中的時間戳,那就不做 set 操作了,以此類推。其他方法,比如利用佇列,將 set 方法變成序列訪問也可以。

Redis做分布式鎖

在分布式系統中,在介面沒 冪等性或者在某些場景下相同的服務需要有且僅有乙個服務執行的情況下,需要使用分布式鎖來保證系統的安全執行。分布式鎖的執行順序,有服務a,分別部署了三個節點為a1 a2 a3,為滿足我們上述需求,我們需要在共享的資料載體中做標記,即,a1開始執行的話,a2 a3不能在執行,直到...

Redis做分布式鎖

在分布式系統中,在介面沒 冪等性或者在某些場景下相同的服務需要有且僅有乙個服務執行的情況下,需要使用分布式鎖來保證系統的安全執行。分布式鎖的執行順序,有服務a,分別部署了三個節點為a1 a2 a3,為滿足我們上述需求,我們需要在共享的資料載體中做標記,即,a1開始執行的話,a2 a3不能在執行,直到...

為什麼我們做分布式使用Redis?

絕大部分寫業務的程式設計師,在實際開發中使用 redis 的時候,只會 set value 和 get value 兩個操作,對 redis 整體缺乏乙個認知。這裡對redis 常見問題做乙個總結,解決大家的知識盲點。在專案中使用 redis,主要考慮兩個角度 效能和併發。如果只是為了分布式鎖這些其...