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

全国房地产网站排名优化工具下载

全国房地产网站,排名优化工具下载,网站建设域名申请,为什么公司的网站打不开前言:此篇文章系本人学习过程中记录下来的笔记,里面难免会有不少欠缺的地方,诚心期待大家多多给予指教。 基础篇: Redis(一)Redis(二)Redis(三)Redis&#x…

 前言:此篇文章系本人学习过程中记录下来的笔记,里面难免会有不少欠缺的地方,诚心期待大家多多给予指教。


基础篇:

  1. Redis(一)
  2. Redis(二)
  3. Redis(三)
  4. Redis(四)
  5. Redis(五)
  6. Redis(六)
  7. Redis(七)
  8. Redis(八)

进阶篇:

  1. Redis(九)
  2. Redis(十)
  3. Redis(十一)
  4. Redis(十二)
  5. Redis(十三)
  6. Redis(十四)

接上期内容:上期完成了手写分布式锁的相关知识学习。下面学习RedLock(红锁)分布式锁(官方推荐),话不多说,直接发车。


一、RedLock定义

(一)、官方说明

官方链接:Distributed Locks with Redis | Docs


(二)、为啥学习?怎么产生

学习原因:假设线程1首先获取锁成功,将键值对写入 redis 的 master 节点,在 redis 将该键值对同步到 slave 节点之前,master 发生了故障;redis 触发故障转移,其中一个 slave 升级为新的 master,此时新上位的master并不包含线程1写入的键值对,因此线程 2 尝试获取锁也可以成功拿到锁,此时相当于有两个线程获取到了锁,可能会导致各种预期之外的情况发生,例如最常见的脏数据。


(三)、RedLock设计理念

假设我们有N个Redis主节点,例如 N = 5这些节点是完全独立的,我们不使用复制或任何其他隐式协调系统,为了取到锁客户端执行以下操作:

1获取当前时间,以毫秒为单位;
2依次尝试从5个实例,使用相同的 key 和随机值(例如 UUID)获取锁。当向Redis 请求获取锁时,客户端应该设置一个超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为 10 秒,则超时时间应该在 5-50 毫秒之间。这样可以防止客户端在试图与一个宕机的 Redis 节点对话时长时间处于阻塞状态。如果一个实例不可用,客户端应该尽快尝试去另外一个 Redis 实例请求获取锁;
3客户端通过当前时间减去步骤 1 记录的时间来计算获取锁使用的时间。当且仅当从大多数(N/2+1,这里是 3 个节点)的 Redis 节点都取到锁,并且获取锁使用的时间小于锁失效时间时,锁才算获取成功;
4如果取到了锁,其真正有效时间等于初始有效时间减去获取锁所使用的时间(步骤 3 计算的结果)。
5如果由于某些原因未能获得锁(无法在至少 N/2 + 1 个 Redis 实例获取锁、或获取锁的时间超过了有效时间),客户端应该在所有的 Redis 实例上进行解锁(即便某些Redis实例根本就没有加锁成功,防止某些节点获取到锁但是客户端没有得到响应而导致接下来的一段时间不能被重新获取锁)。

二、RedLock落地实现(Redisson)

(一)、单机

①、导入依赖

        <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.45.0</version></dependency>

②、编码实现

步骤省略,最终目录图:

SingleRedLockConfig类:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.redisson.Redisson;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class SingleRedLockConfig {@Beanpublic Redisson redisson() {Config config = new Config();// 单机模式config.useSingleServer().setAddress("redis://192.168.40.128:6379").setPassword("root");// 设置 JSON 序列化编解码器config.setCodec(new JsonJacksonCodec(new ObjectMapper()));return (Redisson) Redisson.create(config);}
}

SingleRedLockDemoController类:

import com.nb.redisdemo.RedLockDemo.SinglePlayerDemo.service.SingleRedLockDemoService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class SingleRedLockDemoController {@Resourceprivate SingleRedLockDemoService singleRedLockDemoService;@GetMapping(value = "/inventory/saleByRedisson")public String sale(){return singleRedLockDemoService.saleByRedisson();}
}

SingleRedLockDemoService类:

import jakarta.annotation.Resource;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;@Service
public class SingleRedLockDemoService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Value("${server.port}")private String port;@Resourceprivate Redisson redisson;public String saleByRedisson() {String retMessage = "";String key = "redLock";RLock redissonLock = redisson.getLock(key);redissonLock.lock();try {//1 查询库存信息String result = stringRedisTemplate.opsForValue().get("inventory001");//2 判断库存是否足够int inventoryNumber = result == null ? 0 : Integer.parseInt(result);//3 扣减库存if (inventoryNumber > 0) {stringRedisTemplate.opsForValue().set("inventory001", String.valueOf(--inventoryNumber));retMessage = "成功卖出一个商品,库存剩余: " + inventoryNumber;System.out.println(retMessage);} else {retMessage = "商品卖完了,o(╥﹏╥)o";}} finally {// 如果是本线程且是获取锁成功,才可以解锁if (redissonLock.isHeldByCurrentThread() && redissonLock.isLocked()) {redissonLock.unlock();}}return retMessage + "\t" + "服务端口号:" + port;}
}

③、测试功能

单机测试:访问localhost:8088/inventory/saleByRedisson进行测试,测试结果:

Nginx + Jmeter压测:访问自己Nginx服务器IP+/inventory/saleByRedisson,测试结果:

单机测试通过。


(二)、多机

由于硬件关系,三台存放redis锁的机器部署在同一台服务器上,三台机器互不从属,都是master

①、修改yaml文件

##==========================RedLock分布式锁配置=====================
spring.redis.database=0
spring.redis.password=root
spring.redis.timeout=3000
spring.redis.mode=singlespring.redis.pool.conn-timeout=3000
spring.redis.pool.so-timeout=3000
spring.redis.pool.size=10spring.redis.single.address1=服务器ip:6379
spring.redis.single.address2=服务器ip:6380
spring.redis.single.address3=服务器ip:6381


②、编码实现

由于RedLock这个对象已经被遗弃了,所以使用MultiLock实现

步骤省略,最终项目目录:

MultiMachineRedLockConfig类:

import jakarta.annotation.Resource;
import org.apache.commons.lang.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class MultiMachineRedLockConfig {@ResourceRedisProperties redisProperties;@BeanRedissonClient redissonClient1() {Config config = new Config();String node = redisProperties.getSingle().getAddress1();node = node.startsWith("redis://") ? node : "redis://" + node;SingleServerConfig serverConfig = config.useSingleServer().setAddress(node).setTimeout(redisProperties.getPool().getConnTimeout()).setConnectionPoolSize(redisProperties.getPool().getSize()).setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());if (StringUtils.isNotBlank(redisProperties.getPassword())) {serverConfig.setPassword(redisProperties.getPassword());}return Redisson.create(config);}@BeanRedissonClient redissonClient2() {Config config = new Config();String node = redisProperties.getSingle().getAddress2();node = node.startsWith("redis://") ? node : "redis://" + node;SingleServerConfig serverConfig = config.useSingleServer().setAddress(node).setTimeout(redisProperties.getPool().getConnTimeout()).setConnectionPoolSize(redisProperties.getPool().getSize()).setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());if (StringUtils.isNotBlank(redisProperties.getPassword())) {serverConfig.setPassword(redisProperties.getPassword());}return Redisson.create(config);}@BeanRedissonClient redissonClient3() {Config config = new Config();String node = redisProperties.getSingle().getAddress3();node = node.startsWith("redis://") ? node : "redis://" + node;SingleServerConfig serverConfig = config.useSingleServer().setAddress(node).setTimeout(redisProperties.getPool().getConnTimeout()).setConnectionPoolSize(redisProperties.getPool().getSize()).setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());if (StringUtils.isNotBlank(redisProperties.getPassword())) {serverConfig.setPassword(redisProperties.getPassword());}return Redisson.create(config);}
}

RedisPoolProperties类:

import lombok.Data;@Data
public class RedisPoolProperties {private int maxIdle;private int minIdle;private int maxActive;private int maxWait;private int connTimeout;private int soTimeout;/*** 池大小*/private  int size;}

RedisProperties类:

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "spring.redis", ignoreUnknownFields = false)
@Data
public class RedisProperties {private int database;/*** 等待节点回复命令的时间。该时间从命令发送成功时开始计时*/private int timeout;private String password;private String mode;/*** 池配置*/private RedisPoolProperties pool;/*** 单机信息配置*/private RedisSingleProperties single;}

RedisSingleProperties类:

import lombok.Data;@Data
public class RedisSingleProperties {private  String address1;private  String address2;private  String address3;
}

MultiMachineRedLockDemoController类:代码参考来源:Distributed locks and synchronizers - Redisson Reference Guide

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.RedissonMultiLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.UUID;
import java.util.concurrent.TimeUnit;@RestController
@Slf4j
public class MultiMachineRedLockDemoController {public static final String CACHE_KEY_RED_LOCK = "multiLock";@ResourceRedissonClient redissonClient1;@ResourceRedissonClient redissonClient2;@ResourceRedissonClient redissonClient3;@GetMapping(value = "/multiLock")public String getMultiLock() throws InterruptedException {String uuid = UUID.randomUUID().toString().replaceAll("-", "");String uuidValue = uuid + ":" + Thread.currentThread().getId();RLock lock1 = redissonClient1.getLock(CACHE_KEY_RED_LOCK);RLock lock2 = redissonClient2.getLock(CACHE_KEY_RED_LOCK);RLock lock3 = redissonClient3.getLock(CACHE_KEY_RED_LOCK);RedissonMultiLock redLock = new RedissonMultiLock(lock1, lock2, lock3);redLock.lock();try {System.out.println(uuidValue + "\t" + "---come in biz multiLock");try {TimeUnit.SECONDS.sleep(30);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(uuidValue + "\t" + "---task is over multiLock");} catch (Exception e) {e.printStackTrace();log.error("multiLock exception ", e);} finally {redLock.unlock();log.info("释放分布式锁成功key:{}", CACHE_KEY_RED_LOCK);}return "multiLock task is over  " + uuidValue;}}

 ③、测试功能

访问localhost:8088/multiLock,测试结果:

三台redis客户端以及程序后台都正常,测试通过。


三、Redisson源码分析

参考上章学习手写分布式锁的案例。看看Redisson是如何实现redis分布式锁的。

①、加锁

1、redisson新建锁的默认时间为30秒

2、尝试获取锁

如果锁不存在,则通过hset设置它的值,并设置过期时间

如果锁已存在,并且锁的是当前线程,则通过hincrby给数值递增1。

如果锁已存在,但并非本线程,则返回过期时间。


3、加锁成功后,开启监控(自动续期)

每隔10秒检查一下,如果客户端A还持有锁key,那么就会不断的延长锁key的生存时间,默认每次续命又从30秒新开始。


②、解锁


四、总结

RedLock 作为分布式锁的优秀解决方案,以其独特的设计理念和可靠的实现方式,为分布式系统中的数据一致性和并发控制提供了有力支持。从单机到多机的实现过程,我们看到了其在不同场景下的应用灵活性。通过对 Redisson 源码的分析,进一步了解了如何将 RedLock 的理论落地为高效的代码实践。在实际开发中,合理运用 RedLock 能够有效解决分布式系统中的诸多同步难题,提升系统的稳定性与可靠性,是每一位分布式系统开发者值得深入掌握的关键技术。


ps:努力到底,让持续学习成为贯穿一生的坚守。学习笔记持续更新中。。。。

http://www.dtcms.com/wzjs/31287.html

相关文章:

  • 更换网站后台管理系统百度网站快速排名公司
  • 国家 住房城乡建设信用 网站网站seo优化总结
  • ps怎么做华为网站界面腾讯体育nba
  • 单位网页制作搜索引擎优化的特点
  • 基础很差去公司做网站搭建网站的软件
  • 做网站需要多少钱卖片可以吗seo优化的方法
  • 哪个网站免费做简历郑州网站托管
  • 邯郸医院网站建设口碑营销的主要手段有哪些
  • 营销网站建设评估及分析百度网盘登录入口
  • 长春模板建站系统share群组链接分享
  • 建设什么样的网站月入一万怎样创建一个自己的网站
  • 做房产网站需要注意什么微信引流推广
  • 唐山网站制作工具百度地图打车客服人工电话
  • 电子商务网站的建设目标东莞疫情最新消息今天新增病例
  • 做网站显示不同字体网站排名监控工具
  • 做网站管理员需要哪些知识国内好用的搜索引擎
  • 响应式布局网站尺寸南京最新消息今天
  • 鲜花网站建设规模设想入门seo技术教程
  • 北京建网站开发西地那非片多少钱一盒
  • 做灯箱到哪个网站找业务谷歌浏览器下载安装2021最新版
  • 有哪些好的建站平台浏览器大全网站
  • 好的网站设计制作网红营销
  • 创业计划书(大学生版)seo工具下载
  • 做网站开通手机验证功能百度官网下载安装到桌面上
  • 婚介 东莞网站建设南宁seo服务优化
  • 推广计划标题不允许重复南京百度推广优化排名
  • 南京网站的优化百度链接收录提交入口
  • 做游戏音频下载网站地推是什么
  • 网站设计线框图百度热搜榜小说排名
  • 网站客服系统交互设计重庆seo网页优化