Redis——某马点评day02——商铺缓存
什么是缓存
添加Redis缓存
添加商铺缓存
Controller层中
/*** 根据id查询商铺信息* @param id 商铺id* @return 商铺详情数据*/@GetMapping("/{id}")public Result queryShopById(@PathVariable("id") Long id) {return shopService.queryById(id);}
Service层中
*/
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryById(Long id) {String key="cache:shop:" + id;//1.从Redis查询缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isNotBlank(shopJson)) {//3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//4.不存在,根据id查询数据库Shop shop = getById(id);if (shop==null) {//5.不存在,返回错误return Result.fail("店铺不存在");}//6.存在,写入RedisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop));//7.返回return Result.ok(shop);}
}
练习添加店铺类型缓存
Controller层中
@RestController
@RequestMapping("/shop-type")
public class ShopTypeController {@Resourceprivate IShopTypeService typeService;@GetMapping("list")public Result queryTypeList() {return typeService.queryTypeList();}
}
Service层中
@Overridepublic Result queryTypeList() {String key="cache:shopType";//1.从Redis查询缓存String shopType = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isNotBlank(shopType)) {//3.存在,直接返回List<ShopType> typeList = JSONUtil.toList(shopType, ShopType.class);return Result.ok(typeList);}//4.不存在,查询数据库List<ShopType> typeList = query().orderByAsc("sort").list();//5.存在,写入RedisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(typeList));//7.返回return Result.ok(typeList);}
缓存更新策略
通常选择的方案都是第一种
单体系统可以通过@Transactional注解完成事务。
通常是先操作数据库,再删除缓存,出现问题的几率极小。
实现商铺缓存和数据库的双写一致
第一个地方,写入Redis时加上超时时间。
//6.存在,写入RedisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);
第二个地方
controller中
/*** 更新商铺信息* @param shop 商铺数据* @return 无*/@PutMappingpublic Result updateShop(@RequestBody Shop shop) {return shopService.update(shop);}
service中
@Overridepublic Result update(Shop shop) {Long id = shop.getId();if(id==null){return Result.fail("店铺id不能为空");}//1.更新数据库updateById(shop);//2.删除缓存stringRedisTemplate.delete(CACHE_SHOP_KEY+id);return null;}
缓存穿透
布隆过滤器的实现不是真的存储数据,而是用某种Hash算法计算之后用二进制压缩之类的方法保存是否存在。但是,也有可能多个数据hash值相同导致错误结果。
编码解决商铺查询的缓存穿透(缓存空对象做法)
代码修改
@Overridepublic Result queryById(Long id) {String key=CACHE_SHOP_KEY+ id;//1.从Redis查询缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isNotBlank(shopJson)) {//3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//判断命中的是否是空值if(shopJson!=null){//返回一个错误信息return Result.fail("店铺不存在");}//4.不存在,根据id查询数据库Shop shop = getById(id);if (shop==null) {//将空值写入RedisstringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);//5.不存在,返回错误return Result.fail("店铺不存在");}//6.存在,写入RedisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);//7.返回return Result.ok(shop);}
限流可以用sentinel实现.
缓存雪崩
宕机时降级限流也是用sentinel实现。
nginx缓存也是一级缓存.
tmd,一直在说springcloud里面有讲。
缓存击穿
常见解决方案
这里可以参考一下redisson的源码设计思路,设计一个监听通知机制!
逻辑过期解决方案不会设置ttl过期时间,而是新增一个exprie字段,从redis里面查询发现是过期数据时就需要加锁开启一个新线程去更新缓存,然后直接返回旧数据。有别的线程来获取锁失败时说明已经有线程在进行更新,所以就直接返回过期数据,避免了过多线程等待锁。
利用互斥锁解决缓存击穿问题(重点)
这里的锁不能用lock和synchronized进行互斥实现,这两个会一直等待.这里用到Redis的一个命令setnx, 这个是一旦设置之后就不能修改,只能删除,但是如果因为意外原因导致迟迟不能删除会有大问题,所以这里会给锁设置一个有效期.
代码修改
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryById(Long id) {//缓存穿透//Shop shop=queryWithPassThrouh(id);//互斥锁解决缓存击穿Shop shop = queryWithMutex(id);if(shop==null){return Result.fail("店铺不存在!");}//7.返回return Result.ok(shop);}public Shop queryWithMutex(Long id){String key=CACHE_SHOP_KEY+ id;//1.从Redis查询缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isNotBlank(shopJson)) {//3.存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}//判断命中的是否是空值if(shopJson!=null){//返回一个错误信息return null;}//4.实现缓存重建//4.1获取互斥锁String lockkey="lock:shop:"+id;Shop shop = null;try {boolean isLock = tryLock(lockkey);//4.2判断是否获取成功if(!isLock){//4.3失败,休眠并重试Thread.sleep(50);return queryWithMutex(id); //这里有可能会出现栈溢出的情况。}//获取成功之后应该再次检查缓存是否存在,有可能别的线程已经重建完了缓存,所以这里就无需再重建缓存shopJson = stringRedisTemplate.opsForValue().get(key);//再次判断是否存在if (StrUtil.isNotBlank(shopJson)) {//存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}//4.4根据id查询数据库shop = getById(id);//模拟重建的延时Thread.sleep(200);if (shop==null) {//将空值写入RedisstringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);//5.不存在,返回错误return shop;}//6.存在,写入RedisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e) {throw new RuntimeException(e);} finally {//7.释放互斥锁unlock(lockkey);}//8.返回return shop;}public Shop queryWithPassThrouh(Long id){String key=CACHE_SHOP_KEY+ id;//1.从Redis查询缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isNotBlank(shopJson)) {//3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return shop;}//判断命中的是否是空值if(shopJson!=null){//返回一个错误信息return null;}//4.不存在,根据id查询数据库Shop shop = getById(id);if (shop==null) {//将空值写入RedisstringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);//5.不存在,返回错误return shop;}//6.存在,写入RedisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);//7.返回return shop;}private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}private void unlock(String key){stringRedisTemplate.delete(key);}@Overridepublic Result update(Shop shop) {Long id = shop.getId();if(id==null){return Result.fail("店铺id不能为空");}//1.更新数据库updateById(shop);//2.删除缓存stringRedisTemplate.delete(CACHE_SHOP_KEY+id);return null;}
}
这里可以上Jmeter进行压测,上100个线程进行测试
但是最终实际只查询了一次数据库.
利用逻辑过期解决缓存击穿问题(重点)
为了能增加一个逻辑过期时间的字段,新建一个对象
@Data
public class RedisData {private LocalDateTime expireTime;private Object data;
}
代码修改
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result queryById(Long id) {//缓存穿透//Shop shop=queryWithPassThrouh(id);//互斥锁解决缓存击穿
// Shop shop = queryWithMutex(id);//逻辑过期解决缓存击穿问题Shop shop = queryWithLogicalExpire(id);if(shop==null){return Result.fail("店铺不存在!");}//7.返回return Result.ok(shop);}private static final ExecutorService CACHE_REBUILD_EXECUTOR= Executors.newFixedThreadPool(10);public Shop queryWithLogicalExpire(Long id){String key=CACHE_SHOP_KEY+ id;//1.从Redis查询缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isBlank(shopJson)) {//3.存在,直接返回nullreturn null;}//4.命中,需要先把json反序列化为对象RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class);Shop shop = JSONUtil.toBean((JSONObject)redisData.getData(), Shop.class);LocalDateTime expireTime = redisData.getExpireTime();//5.判断是否过期if(expireTime.isAfter(LocalDateTime.now())){//5.1未过期,直接返回店铺信息return shop;}//5.2已过期,需要缓存重建//6.缓存重建//6.1获取互斥锁String lockKey=LOCK_SHOP_KEY+id;boolean isLock = tryLock(lockKey);//6.2判断是否获取锁成功if(isLock){//这里应该再次检测缓存是否过期,做双重判断,如果没过期就不需重建了,因为可能别的线程已经重建了shopJson = stringRedisTemplate.opsForValue().get(key);redisData = JSONUtil.toBean(shopJson, RedisData.class);expireTime = redisData.getExpireTime();if(expireTime.isAfter(LocalDateTime.now())){//返回前先释放锁unlock(lockKey);//5.1未过期,直接返回店铺信息return shop;}//6.3成功,开启独立线程,实现缓存重建CACHE_REBUILD_EXECUTOR.submit(()->{try {//重建缓存this.saveShop2Redis(id,20L);} catch (Exception e) {throw new RuntimeException(e);} finally {//释放锁unlock(lockKey);}});}//6.4失败,返回过期商铺信息。return shop;}public Shop queryWithMutex(Long id){String key=CACHE_SHOP_KEY+ id;//1.从Redis查询缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isNotBlank(shopJson)) {//3.存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}//判断命中的是否是空值if(shopJson!=null){//返回一个错误信息return null;}//4.实现缓存重建//4.1获取互斥锁String lockkey="lock:shop:"+id;Shop shop = null;try {boolean isLock = tryLock(lockkey);//4.2判断是否获取成功if(!isLock){//4.3失败,休眠并重试Thread.sleep(50);return queryWithMutex(id); //这里有可能会出现栈溢出的情况。}//获取成功之后应该再次检查缓存是否存在,有可能别的线程已经重建完了缓存,所以这里就无需再重建缓存shopJson = stringRedisTemplate.opsForValue().get(key);//再次判断是否存在if (StrUtil.isNotBlank(shopJson)) {//存在,直接返回return JSONUtil.toBean(shopJson, Shop.class);}//4.4根据id查询数据库shop = getById(id);//模拟重建的延时//Thread.sleep(200);if (shop==null) {//将空值写入RedisstringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);//5.不存在,返回错误return shop;}//6.存在,写入RedisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e) {throw new RuntimeException(e);} finally {//7.释放互斥锁unlock(lockkey);}//8.返回return shop;}public Shop queryWithPassThrouh(Long id){String key=CACHE_SHOP_KEY+ id;//1.从Redis查询缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isNotBlank(shopJson)) {//3.存在,直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return shop;}//判断命中的是否是空值if(shopJson!=null){//返回一个错误信息return null;}//4.不存在,根据id查询数据库Shop shop = getById(id);if (shop==null) {//将空值写入RedisstringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);//5.不存在,返回错误return shop;}//6.存在,写入RedisstringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),CACHE_SHOP_TTL, TimeUnit.MINUTES);//7.返回return shop;}private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}private void unlock(String key){stringRedisTemplate.delete(key);}public void saveShop2Redis(Long id,Long expireSeconds) throws InterruptedException {//1.查询店铺数据Shop shop = getById(id);//模拟延时
// Thread.sleep(200);//2.封装逻辑过期时间RedisData redisData = new RedisData();redisData.setData(shop);redisData.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));//3.写入RedisstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY+id,JSONUtil.toJsonStr(redisData));}@Overridepublic Result update(Shop shop) {Long id = shop.getId();if(id==null){return Result.fail("店铺id不能为空");}//1.更新数据库updateById(shop);//2.删除缓存stringRedisTemplate.delete(CACHE_SHOP_KEY+id);return null;}
}
缓存工具封装(重点)
封装工具类里用到的实体
@Data
public class RedisData {private LocalDateTime expireTime;private Object data;
}
工具类代码
@Slf4j
@Component
public class CacheClient {@Resourceprivate StringRedisTemplate stringRedisTemplate;String LOCK_SHOP_KEY="lock:shop:";public CacheClient(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}public void set(String key, Object value, Long time, TimeUnit timeUnit){stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value),time,timeUnit);}public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit timeUnit){//设置逻辑过期RedisData redisData = new RedisData();redisData.setData(value);redisData.setExpireTime(LocalDateTime.now().plusSeconds(timeUnit.toSeconds(time)));//写入RedisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));}public <R,ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Function<ID,R>dbFallback, Long time, TimeUnit timeUnit){String key=keyPrefix+id;//1.从Redis查询缓存String json = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isNotBlank(json)) {//3.存在,直接返回return JSONUtil.toBean(json, type);}//判断命中的是否是空值if(json!=null){//返回一个错误信息return null;}//4.不存在,根据id查询数据库R r=dbFallback.apply(id);//5.不存在,返回错误if (r==null) {//将空值写入RedisstringRedisTemplate.opsForValue().set(key,"",2L, TimeUnit.MINUTES);return null;}//6.存在,写入Redisthis.set(key,r,time,timeUnit);//7.返回return r;}private static final ExecutorService CACHE_REBUILD_EXECUTOR= Executors.newFixedThreadPool(10);public <R,ID> R queryWithLogicalExpire(String keyPrefix, ID id, Class<R> type, Function<ID,R>dbFallback, Long time, TimeUnit timeUnit){String key=keyPrefix+ id;//1.从Redis查询缓存String json = stringRedisTemplate.opsForValue().get(key);//2.判断是否存在if (StrUtil.isBlank(json)) {//3.存在,直接返回nullreturn null;}//4.命中,需要先把json反序列化为对象RedisData redisData = JSONUtil.toBean(json, RedisData.class);R r = JSONUtil.toBean((JSONObject)redisData.getData(), type);LocalDateTime expireTime = redisData.getExpireTime();//5.判断是否过期if(expireTime.isAfter(LocalDateTime.now())){//5.1未过期,直接返回店铺信息return r;}//5.2已过期,需要缓存重建//6.缓存重建//6.1获取互斥锁String lockKey=LOCK_SHOP_KEY+id;boolean isLock = tryLock(lockKey);//6.2判断是否获取锁成功if(isLock){//这里应该再次检测缓存是否过期,做双重判断,如果没过期就不需重建了,因为可能别的线程已经重建了json = stringRedisTemplate.opsForValue().get(key);redisData = JSONUtil.toBean(json, RedisData.class);r = JSONUtil.toBean((JSONObject)redisData.getData(), type);expireTime = redisData.getExpireTime();if(expireTime.isAfter(LocalDateTime.now())){//返回前先释放锁unlock(lockKey);//5.1未过期,直接返回店铺信息return r;}//6.3成功,开启独立线程,实现缓存重建CACHE_REBUILD_EXECUTOR.submit(()->{try {//重建缓存//查询数据库R r1 = dbFallback.apply(id);//写入Redisthis.setWithLogicalExpire(key,r1,time,timeUnit);} catch (Exception e) {throw new RuntimeException(e);} finally {//释放锁unlock(lockKey);}});}//6.4失败,返回过期信息。return r;}private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);}private void unlock(String key){stringRedisTemplate.delete(key);}
}
Service层修改后代码
里面有缓存穿透的调用,也有缓存击穿的调用.
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Resourceprivate CacheClient cacheClient;@Overridepublic Result queryById(Long id) {//缓存穿透Shop shop=cacheClient.queryWithPassThrough(CACHE_SHOP_KEY,id, Shop.class,id2->getById(id2),CACHE_SHOP_TTL,TimeUnit.MINUTES);//Shop shop=cacheClient.queryWithPassThrough(CACHE_SHOP_KEY,id, Shop.class,this::getById,,CACHE_SHOP_TTL,TimeUnit.MINUTES);//互斥锁解决缓存击穿//Shop shop = queryWithMutex(id);//逻辑过期解决缓存击穿问题
// Shop shop = cacheClient
// .queryWithLogicalExpire(CACHE_SHOP_KEY,id,Shop.class,this::getById,CACHE_SHOP_TTL,TimeUnit.SECONDS);if(shop==null){return Result.fail("店铺不存在!");}//7.返回return Result.ok(shop);}@Overridepublic Result update(Shop shop) {Long id = shop.getId();if(id==null){return Result.fail("店铺id不能为空");}//1.更新数据库updateById(shop);//2.删除缓存stringRedisTemplate.delete(CACHE_SHOP_KEY+id);return null;}
}
内容总结:
去看文档资料里面xmind文档,那个里面总结的很好。
相关文章:

Redis——某马点评day02——商铺缓存
什么是缓存 添加Redis缓存 添加商铺缓存 Controller层中 /*** 根据id查询商铺信息* param id 商铺id* return 商铺详情数据*/GetMapping("/{id}")public Result queryShopById(PathVariable("id") Long id) {return shopService.queryById(id);} Service…...

prometheus|云原生|轻型日志收集系统loki+promtail的部署说明
一, 日志聚合的概念说明 日志------ 每一个程序,服务都应该有保留日志,日志的作用第一是记录程序运行的情况,在出错的时候能够记录错误情况,简单来说就是审计工作,例如nginx服务的日志,kuber…...

MySQL 临时数据空间不足导致SQL被killed 的问题与扩展
开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题,有需求都可以加群群内,可以解决你的问题。加群请联系 liuaustin3 ,(共1730人左右 1 2 3 4 5࿰…...

文心一言大模型应用开发入门
本文重点介绍百度智能云平台、文心一言、千帆大模型平台的基本使用与接入流程及其详细步骤。 注册文心一言 请登录文心一言官方网站 https://yiyan.baidu.com/welcome 点击登录;图示如下: 请注册文心一言账号并点击登录,图示如下࿱…...

C++新经典模板与泛型编程:SFINAE替换失败并不是一个错误
替换失败并不是一个错误(SFINAE) SFINAE是一个英文简称,全称为Substitution Failure is not an Error,翻译成中文就是“替换失败并不是一个错误”。 SFINAE可以看作C语言的一种特性或模板设计中要遵循的一个重要原则,…...

基于若依的ruoyi-nbcio流程管理系统支持支持定时边界事件和定时捕获事件
更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 1、定时边界事件 <template><div class"panel-tab__content"><!--目前只处理定…...

递归-极其优雅的问题解决方法(Java)
递归的定义 大名鼎鼎的递归,相信你即使没接触过也或多或少听过,例如汉诺塔问题就是运用了递归的思想,对于一些学过c语言的同学来说,它可能就是噩梦,因为我当时就是这么认为的(不接受反驳doge) …...

VSCode搭建STM32开发环境
1、下载安装文件 链接:https://pan.baidu.com/s/1WnpDTgYBobiZaXh80pn5FQ 2、安装VSCodeUserSetup-x64-1.78.2.exe软件 3、 在VSCode中安装必要的插件 3、配置Keil Assistant插件 4、在环境变量中部署mingw64编译环境...

解决CentOS下PHP system命令unoconv转PDF提示“Unable to connect or start own listener“
centos系统下,用php的system命令unoconv把word转pdf时提示Unable to connect or start own listene的解决办法 unoconv -o /foo/bar/public_html/upload/ -f pdf /foo/bar/public_html/upload/test.docx 2>&1 上面这个命令在shell 终端能执行成功,…...

软件测试外包干了2个月,技术进步2年。。。
先说一下自己的情况,本科生,18年通过校招进入北京某软件公司,干了接近2年的功能测试,今年国庆,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…...
Linux-网络服务和端口
域名:便于人们记忆和使用的标识符 www.baidu.com域名解析:将域名转换为与之对应的 IP 地址的过程 nameserver 8.8.8.8ip地址:网络设备的唯一数字标识符 域名ip地址localhost127.0.0.1 网络服务和端口 网络服务端口ftp21ssh22http80https…...
Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)读书笔记 目录
完结状态:未完结 文章目录 前言第1章 Kubernetes入门 11.1 了解Kubernetes 2 附录A Kubernetes核心服务配置详解 915总结 前言 提示:这里可以添加本文要记录的大概内容: Kubernetes权威指南:从Docker到Kubernetes实践全接触&…...

阿里云Arthas使用——通过watch命令查看类的返回值 捞数据出来
前言 Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类…...
Redis中持久化策略RDB与AOF优缺点对比
Redis持久化策略对比 RDBAOF持久化方式定时对整个内存做快照记录每一次执行的命令数据完整性不完整,两次备份之间存在丢失相对完整,取决于刷盘策略文件大小会有压缩,文件体积小记录命令,文件体积较大宕机恢复速度很快慢数据恢复优先级低,数据完整性不如AOF高,记录了执行命令数据…...

通用plantuml 时序图(Sequence Diagram)模板头
通用plantuml文件 startuml participant Admin order 0 #87CEFA // 参与者、顺序、颜色 participant Student order 1 #87CEFA participant Teacher order 2 #87CEFA participant TestPlayer order 3 #87CEFA participant Class order 4 #87CEFA participant Subject order …...

Domino多Web站点托管
大家好,才是真的好。 看到一篇文档,大概讲述的是他在家里架了一台Domino服务器,上面跑了好几个Internet的Web网站(使用Internet站点)。再租了一台云服务器,上面安装Nginx做了反向代理,代理访问…...

防火墙补充NAT
目录 1.iptables保存规则 2.自定义链 3.NAT NAT的实现分为下面类型: SNAT实验操作 DNAT实验操作 1.iptables保存规则 永久保存方法一: iptables -save > /data/iptables_rule //输出重定向备份 iptables -restore < /data/iptables_r…...
配置和管理VLAN
VLAN技术是交换技术的重要组成部分,也是交换机配置的基础。用于把物理上直接相连的网络从逻辑上划分为多个子网。 每一个VLAN 对应一个广播域,处于不同VLAN 上的主机不能通信。 不同VLAN 之间通信需要引入三层交换技术。 对性能局域网的配置和管理主要…...

dtaidistance笔记:dtw_ndim (高维时间序列之间的DTW)
1 数据 第一个维度是sequence的index,每一行是多个元素(表示这一时刻的record) from dtaidistance.dtw_ndim import *s1 np.array([[0, 0],[0, 1],[2, 1],[0, 1],[0, 0]], dtypenp.double) s2 np.array([[0, 0],[2, 1],[0, 1],[0, .5],[0…...

2 文本分类入门:TextCNN
论文链接:https://arxiv.org/pdf/1408.5882.pdf TextCNN 是一种用于文本分类的卷积神经网络模型。它在卷积神经网络的基础上进行了一些修改,以适应文本数据的特点。 TextCNN 的主要思想是使用一维卷积层来提取文本中的局部特征,并通过池化操…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...