紅鎖的實現


      對redisson不熟悉的,請看官網或者github上面的

      在Redisson框架中,實現了紅鎖的機制,Redisson的RedissonRedLock對象實現了Redlock介紹的加鎖算法。該對象也可以用來將多個RLock對象關聯為一個紅鎖,

每個RLock對象實例可以來自於不同的Redisson實例。當紅鎖中超過半數的RLock加鎖成功后,才會認為加鎖是成功的,這就提高了分布式鎖的高可用。

我們可以使用Redisson框架來實現紅鎖。

public void testRedLock(RedissonClient redisson1,RedissonClient redisson2, RedissonClient redisson3){
    RLock lock1 = redisson1.getLock("lock1");
    RLock lock2 = redisson2.getLock("lock2");
    RLock lock3 = redisson3.getLock("lock3");
    RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
    try {
        // 同時加鎖:lock1 lock2 lock3, 紅鎖在大部分節點上加鎖成功就算成功。
        lock.lock();
        // 嘗試加鎖,最多等待100秒,上鎖以后10秒自動解鎖
        boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}

其實,在實際場景中,紅鎖是很少使用的。這是因為使用了紅鎖后會影響高並發環境下的性能,使得程序的體驗更差。所以,在實際場景中,我們一般都是要保證Redis集群的可靠性。同時,使用紅鎖后,當加鎖成功的RLock個數不超過總數的一半時,會返回加鎖失敗,即使在業務層面任務加鎖成功了,但是紅鎖也會返回加鎖失敗的結果。另外,使用紅鎖時,需要提供多套Redis的主從部署架構,同時,這多套Redis主從架構中的Master節點必須都是獨立的,相互之間沒有任何數據交互。

高並發“黑科技”與致勝奇招

假設,我們就是使用Redis來實現分布式鎖,假設Redis的讀寫並發量在5萬左右。我們的商城業務需要支持的並發量在100萬左右。如果這100萬的並發全部打入Redis中,Redis很可能就會掛掉,那么,我們如何解決這個問題呢?接下來,我們就一起來探討這個問題。

 在高並發的商城系統中,如果采用Redis緩存數據,則Redis緩存的並發處理能力是關鍵,因為很多的前綴操作都需要訪問Redis。而異步削峰只是基本的操作,關鍵還是要保證Redis的並發處理能力。 

解決這個問題的關鍵思想就是:分而治之,將商品庫存分開放。

暗度陳倉

我們在Redis中存儲商品的庫存數量時,可以將商品的庫存進行“分割”存儲來提升Redis的讀寫並發量。

例如,原來的商品的id為10001,庫存為1000件,在Redis中的存儲為(10001, 1000),我們將原有的庫存分割為5份,則每份的庫存為200件,此時,我們在Redia中存儲的信息為(10001_0, 200),(10001_1, 200),(10001_2, 200),(10001_3, 200),(10001_4, 200)。

此時,我們將庫存進行分割后,每個分割后的庫存使用商品id加上一個數字標識來存儲,這樣,在對存儲商品庫存的每個Key進行Hash運算時,得出的Hash結果是不同的,這就說明,存儲商品庫存的Key有很大概率不在Redis的同一個槽位中,這就能夠提升Redis處理請求的性能和並發量。

分割庫存后,我們還需要在Redis中存儲一份商品id和分割庫存后的Key的映射關系,此時映射關系的Key為商品的id,也就是10001,Value為分割庫存后存儲庫存信息的Key,也就是10001_0,10001_1,10001_2,10001_3,10001_4。在Redis中我們可以使用List來存儲這些值。

在真正處理庫存信息時,我們可以先從Redis中查詢出商品對應的分割庫存后的所有Key,同時使用AtomicLong來記錄當前的請求數量,使用請求數量對從Redia中查詢出的商品對應的分割庫存后的所有Key的長度進行求模運算,得出的結果為0,1,2,3,4。再在前面拼接上商品id就可以得出真正的庫存緩存的Key。此時,就可以根據這個Key直接到Redis中獲取相應的庫存信息。

同時,我們可以將分隔的不同的庫存數據分別存儲到不同的Redis服務器中,進一步提升Redis的並發量。

移花接木

在高並發業務場景中,我們可以直接使用Lua腳本庫(OpenResty)從負載均衡層直接訪問緩存。

這里,我們思考一個場景:如果在高並發業務場景中,商品被瞬間搶購一空。此時,用戶再發起請求時,如果系統由負載均衡層請求應用層的各個服務,再由應用層的各個服務訪問緩存和數據庫,其實,本質上已經沒有任何意義了,因為商品已經賣完了,再通過系統的應用層進行層層校驗已經沒有太多意義了!!而應用層的並發訪問量是以百為單位的,這又在一定程度上會降低系統的並發度。

為了解決這個問題,此時,我們可以在系統的負載均衡層取出用戶發送請求時攜帶的用戶id,商品id和活動id等信息,直接通過Lua腳本等技術來訪問緩存中的庫存信息。如果商品的庫存小於或者等於0,則直接返回用戶商品已售完的提示信息,而不用再經過應用層的層層校驗了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM