最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis實(shí)現(xiàn)分布式鎖和等待序列的方法示例

 更新時(shí)間:2019年06月18日 08:26:13   作者:小小小LIN子  
這篇文章主要介紹了Redis實(shí)現(xiàn)分布式鎖和等待序列的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

在集群下,經(jīng)常會(huì)因?yàn)橥瑫r(shí)處理發(fā)生資源爭(zhēng)搶和并發(fā)問(wèn)題,但是我們都知道同步鎖 synchronized 、 cas 、 ReentrankLock 這些鎖的作用范圍都是 JVM ,說(shuō)白了在集群下沒啥用。這時(shí)我們就需要能在多臺(tái) JVM 之間決定執(zhí)行順序的鎖了,現(xiàn)在分布式鎖主要有 redis 、 Zookeeper 實(shí)現(xiàn)的,還有數(shù)據(jù)庫(kù)的方式,不過(guò)性能太差,也就是需要一個(gè)第三方的監(jiān)管。

背景

最近在做一個(gè)消費(fèi) Kafka 消息的時(shí)候發(fā)現(xiàn),由于線上的消費(fèi)者過(guò)多,經(jīng)常會(huì)遇到,多個(gè)機(jī)器同時(shí)處理一個(gè)主鍵類型的數(shù)據(jù)的情況發(fā)生,如果最后是執(zhí)行更新操作的話,也就是一個(gè)更新順序的問(wèn)題,但是如果恰好都需要插入數(shù)據(jù)的時(shí)候,會(huì)出現(xiàn)主鍵重復(fù)的問(wèn)題。這是生產(chǎn)上不被允許的(因?yàn)楣居挟惓1O(jiān)管的機(jī)制,扣分啥的),這是就需要個(gè)分布式鎖了,斟酌后用了 Redis 的實(shí)現(xiàn)方式(因?yàn)榫W(wǎng)上例子多)

分析

redis 實(shí)現(xiàn)的分布式鎖,實(shí)現(xiàn)原理是 set 方法,因?yàn)槎鄠€(gè)線程同時(shí)請(qǐng)求的時(shí)候,只有一個(gè)線程可以成功并返回結(jié)果,還可以設(shè)置有效期,來(lái)避免死鎖的發(fā)生,一切都是這么的完美,不過(guò)有個(gè)問(wèn)題,在 set 的時(shí)候,會(huì)直接返回結(jié)果,成功或者失敗,不具有阻塞效果,需要我們自己對(duì)失敗的線程進(jìn)程處理,有兩種方式

  • 丟棄
  • 等待重試 由于我們的系統(tǒng)需要這些數(shù)據(jù),那么只能重新嘗試獲取。這里使用 redis 的 List 類型實(shí)現(xiàn)等待序列的作用

代碼

直接上代碼 其實(shí)直接redis的工具類就可以解決了

package com.test
import redis.clients.jedis.Jedis;

import java.util.Collections;
import java.util.List;

/**
 * @desc redis隊(duì)列實(shí)現(xiàn)方式
 * @anthor 
 * @date 
 **/
public class RedisUcUitl {

  private static final String LOCK_SUCCESS = "OK";
  private static final String SET_IF_NOT_EXIST = "NX";
  private static final String SET_WITH_EXPIRE_TIME = "PX";

  private static final Long RELEASE_SUCCESS = 1L;

  private RedisUcUitl() {

  }
  /**
   * logger
   **/

  /**
   * 存儲(chǔ)redis隊(duì)列順序存儲(chǔ) 在隊(duì)列首部存入
   *
   * @param key  字節(jié)類型
   * @param value 字節(jié)類型
   */
  public static Long lpush(Jedis jedis, final byte[] key, final byte[] value) {

    return jedis.lpush(key, value);
  
  }

  /**
   * 移除列表中最后一個(gè)元素 并將改元素添加入另一個(gè)列表中 ,當(dāng)列表為空時(shí) 將阻塞連接 直到等待超時(shí)
   *
   * @param srckey
   * @param dstkey
   * @param timeout 0 表示永不超時(shí)
   * @return
   */
  public static byte[] brpoplpush(Jedis jedis,final byte[] srckey, final byte[] dstkey, final int timeout) {

    return jedis.brpoplpush(srckey, dstkey, timeout);

  }

  /**
   * 返回制定的key,起始位置的redis數(shù)據(jù)
   * @param redisKey
   * @param start
   * @param end -1 表示到最后
   * @return
   */
  public static List<byte[]> lrange(Jedis jedis,final byte[] redisKey, final long start, final long end) {
    
    return jedis.lrange(redisKey, start, end);
  }

  /**
   * 刪除key
   * @param redisKey
   */
  public static void delete(Jedis jedis, final byte[] redisKey) {
    
     return jedis.del(redisKey);
  }

  /**
   * 嘗試加鎖
   * @param lockKey key名稱
   * @param requestId 身份標(biāo)識(shí)
   * @param expireTime 過(guò)期時(shí)間
   * @return
   */
  public static boolean tryGetDistributedLock(Jedis jedis,final String lockKey, final String requestId, final int expireTime) {
    String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
    return LOCK_SUCCESS.equals(result);

  }

  /**
   * 釋放鎖
   * @param lockKey key名稱
   * @param requestId 身份標(biāo)識(shí)
   * @return
   */
  public static boolean releaseDistributedLock(Jedis jedis,final String lockKey, final String requestId) {
    final String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

    return RELEASE_SUCCESS.equals(result);

  }
}

業(yè)務(wù)邏輯主要代碼如下

1.先消耗隊(duì)列中的

while(true){
  // 消費(fèi)隊(duì)列
  try{
    // 被放入redis隊(duì)列的數(shù)據(jù) 序列化后的
    byte[] bytes = RedisUcUitl.brpoplpush(keyStr.getBytes(UTF_8), dstKeyStr.getBytes(UTF_8), 1);
    if(bytes == null || bytes.isEmpty()){
      // 隊(duì)列中沒數(shù)據(jù)時(shí)退出
      break;
    }
    // 反序列化對(duì)象
    Map<String, Object> singleMap = (Map<String, Object>) ObjectSerialUtil.bytesToObject(bytes);
    // 塞入唯一的值 防止被其他線程誤解鎖
    String requestId = UUID.randomUUID().toString();
    boolean lockGetFlag = RedisUcUitl.tryGetDistributedLock(keyStr,requestId, 100);
    if(lockGetFlag){
      // 成功獲取鎖 進(jìn)行業(yè)務(wù)處理
      //TODO
      // 處理完畢釋放鎖 
      boolean freeLock = RedisUcUitl.releaseDistributedLock(keyStr, requestId);

    }else{
      // 未能獲得鎖放入等待隊(duì)列
     RedisUcUitl.lpush(keyStr.getBytes(UTF_8), ObjectSerialUtil.objectToBytes(param));
  
    }
    
  }catch(Exception e){
    break;
  }
  
}

2.處理最新接到的數(shù)據(jù)

同樣是走嘗試獲取鎖,獲取不到放入隊(duì)列的流程

一般序列化用 fastJson 之列的就可以了,這里用的是 JDK 自帶的,工具類如下

public class ObjectSerialUtil {

  private ObjectSerialUtil() {
//    工具類
  }

  /**
   * 將Object對(duì)象序列化為byte[]
   *
   * @param obj 對(duì)象
   * @return byte數(shù)組
   * @throws Exception
   */
  public static byte[] objectToBytes(Object obj) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(obj);
    byte[] bytes = bos.toByteArray();
    bos.close();
    oos.close();
    return bytes;
  }


  /**
   * 將bytes數(shù)組還原為對(duì)象
   *
   * @param bytes
   * @return
   * @throws Exception
   */
  public static Object bytesToObject(byte[] bytes) {
    try {
      ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
      ObjectInputStream ois = new ObjectInputStream(bin);
      return ois.readObject();
    } catch (Exception e) {
      throw new BaseException("反序列化出錯(cuò)!", e);
    }
  }
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Redis突現(xiàn)拒絕連接問(wèn)題處理方案

    Redis突現(xiàn)拒絕連接問(wèn)題處理方案

    這篇文章主要介紹了Redis突現(xiàn)拒絕連接問(wèn)題處理方案,分析原因是由于redis與業(yè)務(wù)共一個(gè)服務(wù)器,內(nèi)存只有8G,業(yè)務(wù)服務(wù)啟動(dòng)過(guò)多,內(nèi)存不足導(dǎo)致redis拒絕連接,需要的朋友可以參考下
    2024-02-02
  • 詳談redis優(yōu)化配置和redis.conf說(shuō)明(推薦)

    詳談redis優(yōu)化配置和redis.conf說(shuō)明(推薦)

    下面小編就為大家?guī)?lái)一篇詳談redis優(yōu)化配置和redis.conf說(shuō)明(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • 解讀Redis秒殺優(yōu)化方案(阻塞隊(duì)列+基于Stream流的消息隊(duì)列)

    解讀Redis秒殺優(yōu)化方案(阻塞隊(duì)列+基于Stream流的消息隊(duì)列)

    該文章介紹了使用Redis的阻塞隊(duì)列和Stream流的消息隊(duì)列來(lái)優(yōu)化秒殺系統(tǒng)的方案,通過(guò)將秒殺流程拆分為兩條流水線,使用Redis緩存緩解數(shù)據(jù)庫(kù)壓力,并結(jié)合Lua腳本進(jìn)行原子性判斷,使用阻塞隊(duì)列和消息隊(duì)列異步處理訂單,有效提高了系統(tǒng)的并發(fā)處理能力和可用性
    2025-02-02
  • 利用redisson快速實(shí)現(xiàn)自定義限流注解(接口防刷)

    利用redisson快速實(shí)現(xiàn)自定義限流注解(接口防刷)

    利用redis的有序集合即Sorted?Set數(shù)據(jù)結(jié)構(gòu),構(gòu)造一個(gè)令牌桶來(lái)實(shí)施限流,而redisson已經(jīng)幫我們封裝成了RRateLimiter,通過(guò)redisson,即可快速實(shí)現(xiàn)我們的目標(biāo),這篇文章主要介紹了利用redisson快速實(shí)現(xiàn)自定義限流注解,需要的朋友可以參考下
    2024-07-07
  • 淺談RedisTemplate和StringRedisTemplate的區(qū)別

    淺談RedisTemplate和StringRedisTemplate的區(qū)別

    本文主要介紹了RedisTemplate和StringRedisTemplate的區(qū)別及個(gè)人見解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 淺談Redis在秒殺場(chǎng)景的作用

    淺談Redis在秒殺場(chǎng)景的作用

    本文主要介紹了淺談Redis在秒殺場(chǎng)景的作用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • 淺談Redis中的RDB快照

    淺談Redis中的RDB快照

    雖說(shuō)Redis是內(nèi)存數(shù)據(jù)庫(kù),但是它為數(shù)據(jù)的持久化提供了兩個(gè)技術(shù),分別是AOF日志和RDB快照。這兩種技術(shù)都會(huì)用各用一個(gè)日志文件來(lái)記錄信息,但是記錄的內(nèi)容是不同的。AOF 文件的內(nèi)容是操作命令; RDB 文件的內(nèi)容是二進(jìn)制數(shù)據(jù)。本文將討論RDB快照的原理和使用
    2021-06-06
  • Redis和MySQL保證雙寫一致性的問(wèn)題解析

    Redis和MySQL保證雙寫一致性的問(wèn)題解析

    Redis和MySQL的雙寫一致性指的是在同時(shí)使用緩存和數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)的時(shí)候,保證Redis和MySQL中數(shù)據(jù)的一致性,那么如何才能保證他們的一致性呢,下面小編就來(lái)為大家詳細(xì)講講
    2023-11-11
  • redis中使用redis-dump導(dǎo)出、導(dǎo)入、還原數(shù)據(jù)實(shí)例

    redis中使用redis-dump導(dǎo)出、導(dǎo)入、還原數(shù)據(jù)實(shí)例

    這篇文章主要介紹了redis中使用redis-dump導(dǎo)出、導(dǎo)入、還原數(shù)據(jù)實(shí)例,本文直接給出操作命令,并給出注釋加以說(shuō)明,需要的朋友可以參考下
    2014-11-11
  • 使用redis管理用戶登錄會(huì)話的方法

    使用redis管理用戶登錄會(huì)話的方法

    今天小編就為大家分享一篇使用redis管理用戶登錄會(huì)話的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05

最新評(píng)論

肇东市| 东光县| 凭祥市| 澄江县| 祁东县| 精河县| 怀仁县| 民乐县| 澄迈县| 临湘市| 无锡市| 浦城县| 龙游县| 塔城市| 新营市| 固始县| 沁源县| 花垣县| 泸定县| 宁远县| 汨罗市| 洪泽县| 利津县| 蒙阴县| 红河县| 墨竹工卡县| 鹤庆县| 江西省| 汾阳市| 石嘴山市| 呼伦贝尔市| 南郑县| 巫山县| 靖江市| 建平县| 东方市| 安庆市| 广西| 独山县| 凤冈县| 阿合奇县|