在專案中使用 Redis,主要考慮兩個角度:效能和並發。如果只是為了分散式鎖這些其他功能,還有其他中間件 Zookpeer 等代替,並非一定要使用 Redis。
如下圖所示,我們在碰到需要執行耗時特別久,且結果不頻繁變動的SQL,就特別適合將運行結果放入快取。這樣,後面的請求就去快取中讀取,使得請求能夠快速回應。
特別是在秒殺系統,在同一時間,幾乎所有人都在點,都在下單。 。 。執行的是相同操作———向資料庫查資料。
根據互動效果的不同,回應時間沒有固定標準。在理想狀態下,我們的頁面跳轉需要在瞬間解決,對於頁內操作則需要在剎那間解決。
如下圖所示,在大併發的情況下,所有的請求直接存取資料庫,資料庫會出現連線例外。這個時候,就需要使用 Redis 做一個緩衝操作,讓請求先存取到 Redis,而不是直接存取資料庫。
這個問題是對Redis 內部機制的一個考察。很多人都不知道 Redis 是單執行緒工作模型。
#仔細說一說I/O 多路復用機制,打一個比方:小名在A 城開了一家快餐店店,負責同城快餐服務。小明因為資金限制,僱用了一批配送員,然後小曲發現資金不夠了,只夠買一輛車送快遞。
客戶每下一份訂單,小明就讓一個配送員盯著,然後讓人開車去送。慢慢的小曲發現了這種經營方式存在下述問題:
時間都花在了搶車上了,大部分配送員都處在閒置狀態,搶到車才能去送。
小明只僱用一個配送員。當客戶下單,小明依送達地點標示好,依序放在一個地方。最後,讓配送員依序開車去送,送好了就回來拿下一個。上述兩種經營方式對比,很明顯第二種效率較高。
下面類比到真實的Redis 執行緒模型,如圖所示:
#Redis-client 在操作的時候,會產生具有不同事件類型的Socket。在服務端,有一段 I/O 多重化程序,將其置入佇列之中。然後,檔案事件分派器,依序去佇列中取,轉送到不同的事件處理器。
一個合格的程式設計師,這五種型別都會用到。
最常規的 set/get 運算,Value 可以是 String 也可以是數字。一般做一些複雜的計數功能的快取。
這裡 Value 存放的是結構化的對象,比較方便的就是操作其中的某個欄位。我在做單一登入的時候,就是用這種資料結構儲存使用者訊息,以 CookieId 作為 Key,設定 30 分鐘為快取過期時間,能很好的模擬出類似 Session 的效果。
使用 List 的資料結構,可以做簡單的訊息佇列的功能。另外,可以利用 lrange 指令,做基於 Redis 的分頁功能,效能極佳,使用者體驗好。
因為 Set 堆疊的是一堆不重複值的集合。所以可以做全域去重的功能。我們的系統一般都是叢集部署,使用 JVM 自帶的 Set 比較麻煩。另外,就是利用交集、並集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能。
Sorted Set 多了一個權重參數 Score,集合中的元素能夠依 Score 排列。可以做排行榜套用,取 TOP N 操作。 Sorted Set 可以用來做延時任務。
Redis 是否用到家,從這就能看出來。例如你 Redis 只能存 5G 數據,可是你寫了 10G,那會刪 5G 的數據。怎麼刪的,這個問題思考過?
正解:Redis 採用的是定期刪除 惰性刪除策略。
定時刪除,用計時器來負責監視 Key,過期則會自動刪除。雖然記憶體及時釋放,但十分消耗 CPU 資源。 在大並發請求下,CPU 要將時間應用在處理請求,而不是刪除 Key,因此沒有採用此策略。
定期刪除,Redis 預設每個 100ms 檢查,有過期 Key 則刪除。需要說明的是,Redis 不是每個 100ms 將所有的 Key 檢查一次,而是隨機抽取檢查。如果只採用定期刪除策略,會導致許多 Key 到時間沒有刪除。於是,惰性刪除派上用場。
不是的,如果定期刪除沒刪除掉 Key。而且你也沒及時去請求 Key,也就是說惰性刪除也沒生效。這樣,Redis 的記憶體會越來越高。那就應該採用記憶體淘汰機制。
在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 {valueA 3:00}
系統B key 1 { valueB 3:05}
系統C key 1 {valueC 3:10}
那麼,假設系統B 先搶到鎖,將key1 設為{valueB 3 :05}。接下來系統 A 搶到鎖,發現自己的 valueA 的時間戳早於快取中的時間戳,那就不做 set 操作了,以此類推。其他方法,例如利用隊列,將 set 方法變成串行存取也可以。
更多Redis相關技術文章,請造訪Redis教學欄位學習!
以上是redis分散式怎麼做的詳細內容。更多資訊請關注PHP中文網其他相關文章!