国产精品免费嫩草研究院|无遮羞动漫在线观看AV|国产麻豆精品传媒AV国产在线|村在线观看|寂寞情人1正版|韩国床震韩国床震古|精品系列专区久久

Redis高并發分布式鎖詳解

為什么需要分布式鎖1.為了解決Java共享內存模型帶來的線程安全問題 , 我們可以通過加鎖來保證資源訪問的單一 , 如JVM內置鎖synchronized , 類級別的鎖ReentrantLock 。
2.但是隨著業務的發展 , 單機服務畢竟存在著限制 , 故會往多臺組合形成集群架構 , 面對集群架構 , 我們同樣存在則資源共享問題 , 而每臺服務器有著自己的JVM , 這時候我們對于鎖的實現不得不考慮分布式的實現 。
分布式鎖應該具備哪些條件1.在分布式系統環境下 , 一個方法在同一時間只能被一個機器的一個線程執行
2.高可用的獲取鎖與釋放鎖
3.高性能的獲取鎖與釋放鎖
4.具備可重入特性(可理解為重新進入 , 由多于一個任務并發使用 , 而不必擔心數據錯誤)
5.具備鎖失效機制 , 即自動解鎖 , 防止死鎖
6.具備非阻塞鎖特性 , 即沒有獲取到鎖將直接返回獲取鎖失敗
秒殺搶購場景模擬(模擬并發問題:其實就是指每一步如果存在間隔時間 , 那么當某一線程間隔時間拉長 , 會對其余線程造成什么影響)0.如果要在本機測試的話
1)配置Nginx實現負載均衡
http {upstream testfuzai {server 127.0.0.1:8080 weight=1;server 127.0.0.1:8090 weight=1;}server {listen 80;server_name localhost;location / {//proxy_pass:設置后端代理服務器的地址 。這個地址(address)可以是一個域名或ip地址和端口 , 或者一個 unix-domain socket路徑 。proxy_pass http://testfuzai;proxy_set_header Host $proxy_host;}}}2)啟動redis設置好參數與數量
3)啟動項目并分別配置不同端口(要與Nginx里面的一致)
4)進行壓測 , 通過jmeter的Thread Group里面編輯好HTTP Request , 設置參數 線程數 Number of Threads 【設置為200】  , 請求的重復次數 Loop count 【設置為5】  , Ramp-up period(seconds)線程啟動開始運行的時間間隔(單位是秒)【設置為1】 。則 , 一秒內會有1000個請求打過去 。
1.不加鎖進行庫存扣減的情況:
代碼示例
@RequestMapping("/deduct_stock")public String deductStock() {//從redis取出庫存int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));if (stock > 0) {int realStock = stock - 1;//往redis寫入庫存stringRedisTemplate.opsForValue().set("stock", realStock + "");System.out.println("扣減成功 , 剩余庫存:" + realStock);} else {System.out.println("扣減失敗 , 庫存不足");}return "end";}發現說明
1)通過打印輸出 , 我們會發現兩臺機器上會出現重復的值(即出現了超賣現象) 。甚至會出現另一臺服務器的數據覆蓋本服務器的數據 。
2)原因在于讀取數據和寫入數據存在時間差 , 如兩個服務器Q1和Q1 , Q1有請求 , 獲取庫存【假設300】 , 在庫存判斷大小之后進行扣減庫存如果慢了【假設需要3秒】 , 那么Q2有5次請求 , 獲取到庫存 , 扣減完后設置 , 依次5次 , 則庫存為【295】 。但是此時Q1完成自身請求又會把庫存設置為【299】 。故不合理 。所以應該改為使用stringRedisTemplate.boundValueOps("stock").increment(-1); 改為采用redis內部扣除 , 減少了超賣的個數 。但是就算改了也只是避免了覆蓋問題 , 仍然沒有解決超賣問題 。如果有6臺服務器 , 庫存剩下1個的時候六個請求同時進入到扣減庫存這一步 , 那么就會出現超賣5個的現象(這也是超賣個數最多的現象) 。

經驗總結擴展閱讀