定製直播軟體,分散式鎖的演進你瞭解多少?
基本原理
我們可以同時去一個地方“佔坑”,如果佔到,就執行邏輯。否則就必須等待,直到釋放鎖。“佔坑”可以去redis,可以去資料庫,可以去任何大家都能訪問的地方。等待可以自旋的方式。
public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() { //階段一 Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111"); //獲取到鎖,執行業務 if (lock) { Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap(); //刪除鎖,如果在此之前報錯或當機會造成死鎖 stringRedisTemplate.delete("lock"); return categoriesDb; }else { //沒獲取到鎖,等待100ms重試 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return getCatalogJsonDbWithRedisLock(); } } public Map<String, List<Catalog2Vo>> getCategoryMap() { ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); String catalogJson = ops.get("catalogJson"); if (StringUtils.isEmpty(catalogJson)) { System.out.println("快取不命中,準備查詢資料庫。。。"); Map<String, List<Catalog2Vo>> categoriesDb= getCategoriesDb(); String toJSONString = JSON.toJSONString(categoriesDb); ops.set("catalogJson", toJSONString); return categoriesDb; } System.out.println("快取命中。。。。"); Map<String, List<Catalog2Vo>> listMap = JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Catalog2Vo>>>() {}); return listMap; }
問題: setnx佔好了位,業務程式碼異常或者程式在頁面過程中當機。沒有執行刪除鎖邏輯,這就造成了死鎖
解決: 設定鎖的自動過期,即使沒有刪除,會自動刪除
public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() { Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "111"); if (lock) { //設定過期時間 stringRedisTemplate.expire("lock", 30, TimeUnit.SECONDS); Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap(); stringRedisTemplate.delete("lock"); return categoriesDb; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return getCatalogJsonDbWithRedisLock(); } }
問題: setnx設定好,正要去設定過期時間,當機。又死鎖了。
解決: 設定過期時間和佔位必須是原子的。redis支援使用setnx ex命令。
public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() { //加鎖的同時設定過期時間,二者是原子性操作 Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", "1111",5, TimeUnit.SECONDS); if (lock) { Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap(); //模擬超長的業務執行時間 try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } stringRedisTemplate.delete("lock"); return categoriesDb; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return getCatalogJsonDbWithRedisLock(); } }
問題: 刪除鎖直接刪除???如果由於業務時間很長,鎖自己過期了,我們直接刪除,有可能把別人正在持有的鎖刪除了。
解決: 佔鎖的時候,值指定為uuid,每個人匹配是自己的鎖才刪除。
public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() { String uuid = UUID.randomUUID().toString(); ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); //為當前鎖設定唯一的uuid,只有當uuid相同時才會進行刪除鎖的操作 Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS); if (lock) { Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap(); String lockValue = ops.get("lock"); if (lockValue.equals(uuid)) { try { Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } stringRedisTemplate.delete("lock"); } return categoriesDb; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return getCatalogJsonDbWithRedisLock(); } }
問題: 如果正好判斷是當前值,正要刪除鎖的時候,鎖已經過期,別人已經設定到了新的值。那麼我們刪除的是別人的鎖
解決: 刪除鎖必須保證原子性。使用redis+Lua指令碼完成
public Map<String, List<Catalog2Vo>> getCatalogJsonDbWithRedisLock() { String uuid = UUID.randomUUID().toString(); ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); Boolean lock = ops.setIfAbsent("lock", uuid,5, TimeUnit.SECONDS); if (lock) { Map<String, List<Catalog2Vo>> categoriesDb = getCategoryMap(); String lockValue = ops.get("lock"); String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" + " return redis.call(\"del\",KEYS[1])\n" + "else\n" + " return 0\n" + "end"; stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), lockValue); return categoriesDb; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return getCatalogJsonDbWithRedisLock(); } }
保證加鎖【佔位+過期時間】和刪除鎖【判斷+刪除】的原子性。更難的事情,鎖的自動續期。
以上就是定製直播軟體,分散式鎖的演進你瞭解多少?, 更多內容歡迎關注之後的文章