日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

redis分布式锁小试

發布時間:2025/3/8 编程问答 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis分布式锁小试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、場景

  項目A監聽mq中的其他項目的部署消息(包括push_seq, status, environment,timestamp等),然后將部署消息同步到數據庫中(項目X在對應環境[environment]上部署的push_seq[項目X的版本])。那么問題來了,mq中加入包含了兩個部署消息 dm1 和 dm2,dm2的push_seq > dm1的push_seq,在分布式的情況下,dm1 和 dm2可能會分別被消費(也就是并行),那么在同步數據庫的時候可能會發生 dm1 的數據保存 后于 dm2的數據保存,導致保存項目的部署信息發生異常。

二、解決思路

  將mq消息的并行消費變成串行消費,這里借助redis分布式鎖來完成。同一個服務在分布式的狀態下,監聽到mq消息后,觸發方法的執行,執行之前(通過spring aop around來做的)首先獲得redis的一個分布式鎖,獲取鎖成功之后才能執行相關的邏輯以及數據庫的保存,最后釋放鎖。

三、主要代碼

import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/** * @author: hujunzheng * @create: 17/9/29 下午2:49 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface RedisLock {/*** redis的key* @return*/String value();/*** 持鎖時間,單位毫秒,默認一分鐘*/long keepMills() default 60000;/*** 當獲取失敗時候動作*/LockFailAction action() default LockFailAction.GIVEUP;public enum LockFailAction{/*** 放棄*/GIVEUP,/*** 繼續*/CONTINUE;}/*** 睡眠時間,設置GIVEUP忽略此項* @return*/long sleepMills() default 500; }

?

import java.lang.reflect.Method; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;/** * @author: hujunzheng * @create: 17/9/29 下午2:49 */ @Component @Aspect public class RedisLockAspect {private static final Log log = LogFactory.getLog(RedisLockAspect.class);@Autowiredprivate RedisCacheTemplate.RedisLockOperation redisLockOperation;@Pointcut("execution(* com.hjzgg..StargateDeployMessageConsumer.consumeStargateDeployMessage(..))" +"&& @annotation(me.ele.api.portal.service.redis.RedisLock)")private void lockPoint(){}@Around("lockPoint()")public Object arround(ProceedingJoinPoint pjp) throws Throwable{MethodSignature methodSignature = (MethodSignature) pjp.getSignature();Method method = methodSignature.getMethod();RedisLock lockInfo = method.getAnnotation(RedisLock.class);/*String lockKey = lockInfo.value();if (method.getParameters().length == 1 && pjp.getArgs()[0] instanceof DeployMessage) {DeployMessage deployMessage = (DeployMessage) pjp.getArgs()[0];lockKey += deployMessage.getEnv();System.out.println(lockKey);}*/boolean lock = false;Object obj = null;while(!lock){long timestamp = System.currentTimeMillis()+lockInfo.keepMills();lock = setNX(lockInfo.value(), timestamp);//得到鎖,已過期并且成功設置后舊的時間戳依然是過期的,可以認為獲取到了鎖(成功設置防止鎖競爭)long now = System.currentTimeMillis();if(lock || ((now > getLock(lockInfo.value())) && (now > getSet(lockInfo.value(), timestamp)))){log.info("得到redis分布式鎖...");obj = pjp.proceed();if(lockInfo.action().equals(RedisLock.LockFailAction.CONTINUE)){releaseLock(lockInfo.value());}}else{if(lockInfo.action().equals(RedisLock.LockFailAction.CONTINUE)){log.info("稍后重新請求redis分布式鎖...");Thread.currentThread().sleep(lockInfo.sleepMills());}else{log.info("放棄redis分布式鎖...");break;}}}return obj;}private boolean setNX(String key,Long value){return redisLockOperation.setNX(key, value);}private long getLock(String key){return redisLockOperation.get(key);}private Long getSet(String key,Long value){return redisLockOperation.getSet(key, value);}private void releaseLock(String key){redisLockOperation.delete(key);}@Pointcut(value = "execution(* me.ele..StargateBuildMessageConsumer.consumeStargateBuildMessage(me.ele.api.portal.service.mq.dto.BuildMessage)) && args(buildMessage)" +"&& @annotation(me.ele.api.portal.service.redis.RedisLock)", argNames = "buildMessage")private void buildMessageLockPoint(BuildMessage buildMessage){}@Around(value = "buildMessageLockPoint(buildMessage)", argNames = "pjp,buildMessage")public Object buildMessageAround(ProceedingJoinPoint pjp, BuildMessage buildMessage) throws Throwable {final String LOCK = buildMessage.getAppId() + buildMessage.getPushSequence();Lock lock = redisLockRegistry.obtain(LOCK);try {lock.lock();return pjp.proceed();} finally {try {lock.unlock();} catch (Exception e) {log.error("buildMessage={}, Lock {} unlock failed. {}", buildMessage, lock, e);}}}}

四、遇到的問題

  

?

  

  開始是將鎖加到deploy的方法上的,但是一直aop一直沒有作用,換到consumeStargateDeployMessage方法上就可以了。考慮了一下是因為 @Transactional的原因。這里注意下。

?  在一篇文章中找到了原因:SpringBoot CGLIB AOP解決Spring事務,對象調用自己方法事務失效.

  只要脫離了Spring容器管理的所有對象,對于SpringAOP的注解都會失效,因為他們不是Spring容器的代理類,SpringAOP,就切入不了。也就是說是?@Transactional注解方法的代理對象并不是spring代理對象。

  參考:?關于proxy模式下,@Transactional標簽在創建代理對象時的應用

五、使用spring-redis中的RedisLockRegistry

import java.util.concurrent.locks.Lock; import org.springframework.integration.redis.util.RedisLockRegistry;@Bean public RedisLockRegistry redisLockRegistry(@Value("${xxx.xxxx.registry}") String redisRegistryKey,RedisTemplate redisTemplate) {return new RedisLockRegistry(redisTemplate.getConnectionFactory(), redisRegistryKey, 200000); }Lock lock = redisLockRegistry.obtain(appId);lock.tryLock(180, TimeUnit.SECONDS); .... lock.unlock();  

六、參考

  其他工具類,請參考這里。

七、springboot LockRegistry

  

? ? ??分布式鎖-RedisLockRegistry源碼分析[轉]

?

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.Lock; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.integration.redis.util.RedisLockRegistry; import redis.clients.jedis.JedisShardInfo;@Ignore public class RedisLockTest {private static final Logger LOGGER = LoggerFactory.getLogger(RedisLockTest.class);private static final String LOCK = "xxx.xxx";private RedisLockRegistry redisLockRegistry;@Beforepublic void setUp() {JedisShardInfo shardInfo = new JedisShardInfo("127.0.0.1");JedisConnectionFactory factory = new JedisConnectionFactory(shardInfo);redisLockRegistry = new RedisLockRegistry(factory, "test", 50L);}private class TaskA implements Runnable {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}Lock lock = redisLockRegistry.obtain(LOCK);try {lock.lock();LOGGER.info("Lock {} is obtained", lock);Thread.sleep(10);lock.unlock();LOGGER.info("Lock {} is unlocked", lock);} catch (Exception ex) {LOGGER.error("Lock {} unlock failed", lock, ex);}}}private class TimeoutTask implements Runnable {@Overridepublic void run() {Lock lock = redisLockRegistry.obtain(LOCK);try {lock.lock();LOGGER.info("Lock {} is obtained", lock);Thread.sleep(5000);lock.unlock();LOGGER.info("Lock {} is unlocked", lock);} catch (Exception ex) {LOGGER.error("Lock {} unlock failed", lock, ex);}}}@Testpublic void test() throws InterruptedException, TimeoutException {ExecutorService service = Executors.newFixedThreadPool(2);service.execute(new TimeoutTask());service.execute(new TaskA());service.shutdown();if (!service.awaitTermination(1, TimeUnit.MINUTES)) {throw new TimeoutException();}} }

?

?

?

轉載于:https://www.cnblogs.com/hujunzheng/p/7612264.html

總結

以上是生活随笔為你收集整理的redis分布式锁小试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日本一级黄色 | 亚洲激情视频小说 | 国产黄色大全 | 欧美 日韩 国产在线 | 天堂8在线天堂资源bt | 综合精品久久久 | 国产一区二区三区四区五区在线 | 秋霞自拍| 亚洲一区二区乱码 | av不卡在线观看 | 久久久久999 | 国产精品中文字幕在线观看 | 国产污污视频在线观看 | 俺也去在线视频 | 色妞综合| 黑鬼大战白妞高潮喷白浆 | 亚洲男人天堂2020 | 在线播放www | 欧美三级免费 | 夜夜骚网站| 操干网 | 欧美bbbbbbbbbbbb18av | a级片在线 | 男人的天堂日韩 | 男欢女爱久石 | 精品国产伦一区 | 久久av中文字幕 | 精品久久视频 | 亚洲一本在线观看 | 女同一区 | 伊人久久大香线蕉成人综合网 | 免费看国产一级片 | 欧美日本二区 | 舌奴调教日记 | 久久精品国产精品 | 日日干夜夜操 | 成人免费在线看片 | 影音先锋婷婷 | 国产探花在线观看 | 日韩中文无 | 韩国三级在线视频 | 欧美婷婷六月丁香综合色 | 日本一本在线观看 | 91入囗| 九九资源网 | 蜜桃视频一区二区三区在线观看 | 亚洲欧美日本一区 | 欧美一级不卡 | 国产精品久久国产 | 日本人妻换人妻毛片 | 一级片免费播放 | 成年人的黄色片 | 久久国产乱子伦免费精品 | 精品一区二区免费 | 熟妇人妻中文字幕无码老熟妇 | 日韩中文在线视频 | wwwav视频 | 成人av资源在线 | av免费成人 | 国产视频首页 | 黄色一级大片在线免费看国产 | 丝袜+亚洲+另类+欧美+变态 | 欧美做受高潮中文字幕 | 亚洲精品精品 | 欧美男人的天堂 | 中文字幕 日本 | 亚洲精品少妇一区二区 | 日韩无砖 | 久久高清内射无套 | 欧美日韩免费网站 | 草草色 | 五月婷婷激情综合 | 亚洲精品456 | 尤物视频在线播放 | 草比网站 | 很黄很污的视频网站 | 在线中文天堂 | 一线毛片 | 久草网视频在线观看 | free欧美性69护士呻吟 | 精品少妇一区二区三区 | 午夜av导航 | 黄色一级一片免费播放 | 日韩av女优在线观看 | 我爱av好色| 欧美色综合色 | 午夜天堂网| 亚洲国产精品久久久 | 久热精品视频在线播放 | 国产睡熟迷奷系列精品视频 | 一区国产在线 | 狠狠干2017 | 欧美性受xxx | 帮我拍拍漫画全集免费观看 | 怡春院视频 | 18无码粉嫩小泬无套在线观看 | 中文字幕在线字幕中文 | 精品中文字幕在线 | 日韩欧美国产一区二区在线观看 |