当前位置: 首页 > news >正文

组织建设情况怎么写网站优化入门免费教程

组织建设情况怎么写,网站优化入门免费教程,孝义网站开发公司,闲鱼上面给人做网站造退款集群分布式场景高并发 1.negix配置代理和路由 高并发场景超卖问题 1.使用原生redis控制超卖时(若是商品,则可以将商品id作为锁对象),会遇到的问题 问题一:若直接使用:将获取锁的对象和设置的超时的时间分开,则不能控…

集群分布式场景高并发

1.negix配置代理和路由

高并发场景超卖问题

1.使用原生redis控制超卖时(若是商品,则可以将商品id作为锁对象),会遇到的问题

问题一:若直接使用:将获取锁的对象和设置的超时的时间分开,则不能控制原子性,如下所示

         Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "zhuge");
        stringRedisTemplate.expire(lockKey, 10, TimeUnit.SECONDS);

 问题二:若直接使用:将获取锁的对象和设置的超时的时间放在一个原子操作里执行时,在临界条件下,当程序执行到最后准备释放锁时候,锁的超时时间已到,则此时的锁成为已过期,则释放不了锁而当下一个线程也来执行任务时,前一个任务将这个任务所拿的所给释放掉了(释放掉不属于自己的锁对象);则引入redisson分布式锁来解决当前的问题,redisson具有锁续命机制

@RestController
public class IndexController {@Autowiredprivate Redisson redisson;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/deduct_stock")public String deductStock() {String lockKey = "lock:product_101";//Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "zhuge");//stringRedisTemplate.expire(lockKey, 10, TimeUnit.SECONDS);String clientId = UUID.randomUUID().toString();Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS); //jedis.setnx(k,v)if (!result) {return "error_code";}try {int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock")if (stock > 0) {int realStock = stock - 1;stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value)System.out.println("扣减成功,剩余库存:" + realStock);} else {System.out.println("扣减失败,库存不足");}} finally {if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {stringRedisTemplate.delete(lockKey);}}return "end";}

使用分布式锁redisson

redisson使用

引入对应的redission的jar包

        <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.6.5</version></dependency>

 设置redission配置


@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}@Beanpublic Redisson redisson() {// 此为单机模式Config config = new Config();config.useSingleServer().setAddress("redis://localhost:6379").setDatabase(0);return (Redisson) Redisson.create(config);}}

 redission的基本使用


@RestController
public class IndexController {@Autowiredprivate Redisson redisson;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/deduct_stock")public String deductStock() {String lockKey = "lock:product_101";//Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "zhuge");//stringRedisTemplate.expire(lockKey, 10, TimeUnit.SECONDS);/*String clientId = UUID.randomUUID().toString();Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS); //jedis.setnx(k,v)if (!result) {return "error_code";}*///获取锁对象RLock redissonLock = redisson.getLock(lockKey);//加分布式锁redissonLock.lock();  //  .setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS);try {int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock")if (stock > 0) {int realStock = stock - 1;stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value)System.out.println("扣减成功,剩余库存:" + realStock);} else {System.out.println("扣减失败,库存不足");}} finally {/*if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {stringRedisTemplate.delete(lockKey);}*///解锁redissonLock.unlock();}return "end";}

Redission执行的逻辑流程

 Redission分布式锁加锁源码分析

        redissonLock.lock(); 

加锁 

 @Overridepublic void lockInterruptibly() throws InterruptedException {lockInterruptibly(-1, null);}

执行 lockInterruptibly加锁逻辑

@Overridepublic void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException {long threadId = Thread.currentThread().getId();Long ttl = tryAcquire(leaseTime, unit, threadId); //尝试去加锁,返回的时加锁后的过期时间// lock acquiredif (ttl == null) {  //若ttl为null ,则表示加锁成功 ;若ttl不为null ,则往下走return;}RFuture<RedissonLockEntry> future = subscribe(threadId); //发布订阅,订阅前者执行的任务若提前执行完,则唤醒机制,去重新获取锁commandExecutor.syncSubscription(future);try {while (true) { //进入循环ttl = tryAcquire(leaseTime, unit, threadId); //再次尝试获取锁,返回加锁成功后的过期时间// lock acquiredif (ttl == null) {  //若ttl为null ,则表示加锁成功 ;若ttl不为null ,则往下走break;}// waiting for messageif (ttl >= 0) { 若ttl大于ogetEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
//进行间歇性锁自旋逻辑,不占用cpu资源} else {getEntry(threadId).getLatch().acquire();}}} finally {unsubscribe(future, threadId);}
//        get(lockAsync(leaseTime, unit));}

执行tryAcquire(leaseTime, unit, threadId)尝试加锁逻辑

 private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, final long threadId) {if (leaseTime != -1) {return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);}
//leaseTime 默认设置为-1RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
//执行加锁逻辑ttlRemainingFuture.addListener(new FutureListener<Long>() { //异步执行,锁续命逻辑@Overridepublic void operationComplete(Future<Long> future) throws Exception {if (!future.isSuccess()) { //若加锁不成功,则退出return;}Long ttlRemaining = future.getNow(); //若加锁成功,则ttlRemaining 为null// lock acquiredif (ttlRemaining == null) {scheduleExpirationRenewal(threadId); //加锁成功,则执行锁续命逻辑}}});return ttlRemainingFuture;}

执行tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG); 加锁逻辑

  <T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
//通过lua脚本来执行加锁逻辑,来保证原子性internalLockLeaseTime = unit.toMillis(leaseTime);return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,//执行加锁逻辑 (key,argv与下面所传参数一一对应)"if (redis.call('exists', KEYS[1]) == 0) then " +      //KEY[1]表示下面的getName(),"redis.call('hset', KEYS[1], ARGV[2], 1); " +    //ARGV[2]表示下面的getLockName(threadId)"redis.call('pexpire', KEYS[1], ARGV[1]); " + //ARGV[1]表示下面的internalLockLeaseTime"return nil; " +"end; " +
//执行锁重入逻辑(一个线程对同一个锁对象进行多次加锁,此为重入锁逻辑)"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +"redis.call('pexpire', KEYS[1], ARGV[1]); " +"return nil; " +"end; " +"return redis.call('pttl', KEYS[1]);", //设置返回过期时间Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));}

执行scheduleExpirationRenewal(threadId);锁续命逻辑

private void scheduleExpirationRenewal(final long threadId) {if (expirationRenewalMap.containsKey(getEntryName())) {return;}Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {@Overridepublic void run(Timeout timeout) throws Exception {//执行锁续命逻辑RFuture<Boolean> future = commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
//KEYS[1]表示getName(),ARGV[2]表示锁对象getLockName(threadId), ARGV[1]表示过期时间
//判断当前锁的对象,为当前的线程对象,那么则当前的锁的对象设置原始的过期时间,以达到续命效果"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +"redis.call('pexpire', KEYS[1], ARGV[1]); " +"return 1; " +"end; " +"return 0;",Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));//异步监听执行        future.addListener(new FutureListener<Boolean>() {@Overridepublic void operationComplete(Future<Boolean> future) throws Exception {expirationRenewalMap.remove(getEntryName());if (!future.isSuccess()) {log.error("Can't update lock " + getName() + " expiration", future.cause());return;}//判断是否任然持有锁,是的话,则getNow()为nullif (future.getNow()) {// reschedule itselfscheduleExpirationRenewal(threadId);//再次执行续命逻辑}}});}}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);if (expirationRenewalMap.putIfAbsent(getEntryName(), task) != null) {task.cancel();}}

在外层未获取到锁的线程  getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);间隙自旋获取锁对象

getLatch()表示信号量,信号量为1,则表示阻塞状态,最终通过发布订阅方式来唤醒当前被阻塞的线程,唤醒后则执行获取锁的逻辑 doAcquireSharedNanos(arg, nanosTimeout);

http://www.hkea.cn/news/742776/

相关文章:

  • 做的网站很卡是什么原因seochan是什么意思
  • 怎么做盗版视频网站吗百度权重1
  • 政府网站 建设 计划品牌推广策划方案案例
  • 临沂网站建设那家好小米市场营销案例分析
  • 德化网站建设企业中层管理人员培训课程
  • 网站怎么通过流量赚钱爱站网能不能挖掘关键词
  • 网站建设课后感营销型网站有哪些平台
  • 哪个网站做生鲜配送厦门seo外包公司
  • 水电行业公司设计logo重庆seo排名扣费
  • 可信赖的南昌网站制作站长工具网站
  • 济南建站公司电话成都关键词自然排名
  • 门户网站开发公司推广网页
  • 如何做网站认证实时军事热点
  • 上海的网站建设公司哪家好企业网站建设
  • 专业b2c电商网站制作网站推广要点
  • 现在的网站用什么程序做百度云官网登录入口
  • vs做网站怎样加数据库新闻小学生摘抄
  • 广州做网站mxszpt小说排行榜
  • 有什么网站是python做的网站营销策划公司
  • 长春有什么好的网站制作公司链接购买
  • 毕设网站佛山网站建设十年乐云seo
  • 北京做网站建设的公司哪家好手机怎么创建网站
  • winforms做网站注册百度账号
  • 玉泉路网站建设营销培训课程有哪些
  • 渭南做网站费用搜索引擎排名优化是什么意思
  • 做网站开发需要学什么软件微信公众平台开发
  • 网站整体营销方案网络营销的特点是什么?
  • 国内知名的网站建设公司有哪些百度指数专业版app
  • 画画外包网站如何推广一个网站
  • 互联网公司响应式网站深圳google推广