Redis~分佈式事務和分佈式事務鎖

前話

  • 大家都知道redis是一個可以高速運行在緩存級別的數據庫, 他的高速原因主要有幾個原因
  1. 絕大部分請求是純粹的內存操作(非常快速),避免了與硬盤的接觸
  2. 豐富的特性:可用於緩存,消息,按key設置過期時間,過期後將會自動刪除
  3. 使用大量的hash思想的k v鍵值對, 獲取效率爲O(1)
  4. 依靠非阻塞的IO多路複用原則,使redis形成單線程去執行命令的服務器, 避免了不必要的阻塞和上下文切換和競爭條件

redis採用IO複用實現單線程的方式, 將命令任務分裝在隊列中讓一個線程去串行化執行, 自然避免了線程安全問題, 這也是爲什麼我們常說redis是基於原子操作的原因

跟多線程相比較,線程切換需要切換到內核進行線程切換,需要消耗時間和資源.而I/O多路複用不需要切換線/進程,效率相對較高,特別是對高併發的應用nginx就是用I/O多路複用,故而性能極佳

  • 但是還有一個問題, 上面說redis是單線程的, 那麼就不會有線程安全問題, 那爲什麼還有讓redis支持事務, 還要 要求他使用redis分佈式事務鎖

沒錯,大家所熟知的 Redis 確實是單線程模型,指的是執行 Redis 命令的核心模塊是單線程的,而不是整個 Redis 實例就一個線程,Redis 其他模塊還有各自模塊的線程的

比如socket連接, 這就是一個多線程式的
在redis事務中或有一個watch樂觀鎖去監視者數據是否被改動, 如果真的是完全單線程, 那麼就不需要有這個監視的存在
本質原因就是redis的socket連接是多線程的, 我們在開始redis事務, 往裏面添加命令其實並沒有真正的執行這些命令, 所以需要watch的監視, 防止其他socket連接進行了數據的操作
下面看看redis的真實運行環境


在這裏插入圖片描述

  • 它的組成結構爲4部分:多個套接字、IO多路複用程序、文件事件分派器、事件處理器。
    因爲文件事件分派器隊列的消費是單線程的,所以Redis才叫單線程模型。
  • 所以Redis 不僅僅是單線程, 他需要事務的支持, 就是因爲多客戶端對Redis的連接並不存在競爭關係。
  • 所以在單機服務器,出現資源的競爭,一般使用synchronized 還可以使用前的redis的事務就可以解決,但是在分佈式的服務器上,多個系統或者說多個節點同時訪問你這個redis節點,synchronized 和redis事務就無法解決這個問題,這就需要一個分佈式事務鎖

講分佈式事務鎖前的幾個概念

  • 分佈式:簡單來說就是將業務進行拆分,部署到不同的機器來協調處理。比如用戶在網上買東西,大致分爲:訂單系統、庫存系統、支付系統、、、、這些系統共同來完成用戶買東西這個業務操作。
  • 集羣:同一個業務,通過部署多個實例來完成,保證應用的高可用,如果其中某個實例掛了,業務仍然可以正常進行,通常集羣和分佈式配合使用。來保證系統的高可用、高性能。
  • 分佈式事務:按照傳統的系統架構,下單、扣庫存等等,都是在單機系統中, 這一系列的操作都是一個數據庫中完成的,也就是說保證了事務的ACID特性。如果在分佈式應用中就會涉及到跨應用、跨庫。這樣就涉及到了分佈式事務,就要考慮怎麼保證這一系列的操作要麼都成功要麼都失敗。保證數據的一致性。
  • 分佈式鎖:因爲資源有限,要通過互斥來保持一致性,比如下訂單的數據庫操作和支付的數據庫操作就是一個保證互斥性, 不能同時去執行, 不然那就會出現一旦支付出現失敗, 那麼下訂單也得重新下訂單, 這就不合理了, 所以引入分佈式事務鎖。

Redis分佈式事務鎖原理

  • 分佈式鎖是控制分佈式系統之間同步訪問共享資源的一種方式。如果不同的系統或是同一個系統的不同主機之間共享了一個或一組資源,那麼訪問這些資源的時候,往往需要互斥來防止彼此干擾來保證一致性,在這種情況下,便需要使用到分佈式鎖。
  • 簡單來說就是好幾個節點訪問一個資源, 那我就是使用額外的鎖機制互斥的只讓其中一個能進行訪問

核心思想

  • 在被保護的redis節點加一把鎖, 讓這把鎖和被保護的redis節建立直接映射
  • 在訪問這個redis之前都去看看這把鎖在不在
  • 如果不存在鎖,說明沒有客戶端使用,可以執行任務,執行完畢,解鎖,刪除鎖 (並且要保證判斷有無鎖和加鎖是原子操作)
  • 如果鎖從在則認爲有其他客戶端在使用,等待鎖消失
    在這裏插入圖片描述
  • Redis中可以使用SETNX命令實現分佈式鎖,(因redis執行命令是單線程所以這個命令是院子的, 完全可以放心去使用)。
  • SETNX——SET if Not eXists(如果不存在,則設置):
setnx key value
  • 如果需要解鎖,使用 del key 命令就能釋放鎖

問題一

  • 當一個客戶端上鎖之後服務宕機,由於鎖是他上的只有他可以進行redis訪問的,別人無法訪問,所以導致鎖無法被刪除.

解決思路

  • 給鎖設置一個過期時間,可以通過兩種方法實現:通過命令 “setnx 鍵名 過期時間 “;或者通過設置鎖的expire(失效)時間,讓Redis去刪除鎖。

問題一

  • 當一個客戶端設置了鎖的失效時間, 但是這個客戶端並沒有宕機, 只是真的需要那麼多時間來進行操作
  • 也就是任務執行過長,超過過期時間。

解決思路
這就是上圖那個看門狗的作用可, 這條狗看到時間快到了, 就大喊一聲讓時間倒流~

  • 實際是通過客戶端的一個守護線程,大概時間快到的時間給線程續命.

問題三

  • 任務執行造成死循環,會造成無限續命

解決思路
設置最大續命時間, 或者設置最大續命次數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章