Redis的应用问题

目录

一、缓存穿透

问题描述

解决方案

缓存击穿

问题描述

解决方案

缓存雪崩

问题描述

解决方案

二、分布式锁

问题描述

解/决方案:使用redis实现分布式锁

优化之设置锁的过期时间

优化之UUID防误删

LUA脚本保证删除的原子性

LUA脚本

LUA脚本在Redis中的优势

redisson

使用redissoncheck

锁的分类:

redisson的使用

一、缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

问题描述

key对应的数据在数据库并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据库,从而可能压垮数据库。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

解决方案

一个一定不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

解决方案:

(1) 对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟

(2) 设置可访问的名单(白名单):

使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。

(3) 采用布隆过滤器:(布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。

布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。)

将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。

(4) 进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务

缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

问题描述

key对应的数据存在,但在redis中没有过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案

key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。

解决问题:

(1)预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长

(2)实时调整:现场监控哪些数据热门,实时调整key的过期时长

(3)使用锁:

(1) 就是在缓存失效的时候(判断拿出来的值为空),不是立即去加载数据库。

(2) 先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX)去set一个mutex key

(3) 当操作返回成功时,再进行load db的操作,并回设缓存,最后删除mutex key;

(4) 当操作返回失败,证明有线程在load db,当前线程睡眠一段时间再重试整个get缓存的方法。

setnx 分布式锁

缓存雪崩

缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

问题描述

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,击穿则是某一个key正常访问

缓存失效瞬间

解决方案

缓存失效时的雪崩效应对底层系统的冲击非常可怕!

解决方案:

(1) 构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)

(2) 使用锁或队列:

5000 1000

用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况

(3) 设置过期标志更新缓存:

记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。

(4) 将缓存失效时间分散开:

比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

二、分布式锁

问题描述

随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!

分布式锁主流的实现方案:

1. 基于数据库实现分布式锁

2. 基于缓存(Redis等)

3. 基于Zookeeper

每一种分布式锁解决方案都有各自的优缺点:

1. 性能:redis最高

2. 可靠性:zookeeper最高

这里,我们就基于redis实现分布式锁。

解决方案:使用redis实现分布式锁

redis:命令

# set sku:1:info “OK” NX PX 10000

EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。

PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。

NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。

XX :只在键已经存在时,才对键进行设置操作。

setnx 键不存在的时候 设值

setnx lock test

业务逻辑

del lock

1. 多个客户端同时获取锁(setnx)

2. 获取成功,执行业务逻辑{从db获取数据,放入缓存},执行完成释放锁(del)

3. 其他客户端等待重试

编写代码

@RestController
@RequestMapping("fb")
public class MyRedisController {
    @Resource
    private RedisTemplate redisTemplate;

    @RequestMapping
    public void fblock() throws InterruptedException {
        //创建一个分布式锁lock
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("lock", "MyLock");
        //加锁成功
        if (aBoolean){
            System.out.println("执行业务");
            System.out.println("执行成功");
            //删除锁
            redisTemplate.delete("lock");
        }else {
            //没有抢到锁
            Thread.sleep(300);
            fblock();
        }
    }
}

进行压力测试

问题:setnx刚好获取到锁,业务逻辑出现异常,导致锁无法释放

解决:设置过期时间,自动释放锁。

优化之设置锁的过期时间

设置过期时间有两种方式:

1. 首先想到通过expire设置过期时间(缺乏原子性:如果在setnx和expire之间出现异常,锁也无法释放)

2. 在set时指定过期时间(推荐)

设置过期时间:

代码中设置过期时间

Boolean lock = redisTemplate.opsForValue()

.setIfAbsent("lock", "MyLock",3,TimeUnit.SECONDS);

@RestController
@RequestMapping("fb")
public class MyRedisController {
    @Resource
    private RedisTemplate redisTemplate;

    @RequestMapping
    public void fblock() throws InterruptedException {
        //创建一个分布式锁lock
        //添加过期时间
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent("lock", "MyLock",3,TimeUnit.MILLISECONDS);
        //加锁成功
        if (aBoolean){
            //执行业务的时间
            Thread.sleep(7000);
            System.out.println("执行业务");
            System.out.println("执行成功");
            //删除锁
            redisTemplate.delete("lock");
        }else {
            //没有抢到锁,300毫秒之后再获取
            Thread.sleep(3000);
            fblock();
        }
    }
}

问题:可能会释放其他服务器的锁。

场景:如果业务逻辑的执行时间是7s。执行流程如下

1. index1业务逻辑没执行完,3秒后锁被自动释放。

2. index2获取到锁,执行业务逻辑,3秒后锁被自动释放。

3. index3获取到锁,执行业务逻辑

4. index1业务逻辑执行完成,开始调用del释放锁,这时释放的是index3的锁,导致index3的业务只执行1s就被别人释放。

最终等于没锁的情况。

解决:setnx获取锁时,设置一个指定的唯一值(例如:uuid);释放前获取这个值,判断是否自己的锁

优化之UUID防误删

问题:删除操作缺乏原子性。

场景:

1. index1执行删除时,查询到的lock值确实和uuid相等

uuid=v1

set(lock,uuid);

2. index1执行删除前,lock刚好过期时间已到,被redis自动释放

在redis中没有了lock,没有了锁。

3. index2获取了lock

index2线程获取到了cpu的资源,开始执行方法

uuid=v2

set(lock,uuid);

4. index1执行删除,此时会把index2的lock删除

index1 因为已经在方法中了,所以不需要重新上锁。index1有执行的权限。index1已经比较完成了,这个时候,开始执行

删除的index2的锁!

LUA脚本保证删除的原子性

KEYS[1] 用来表示在redis 中用作键值的参数占位,主要用來传递在redis 中用作keyz值的参数。

ARGV[1] 用来表示在redis 中用作参数的占位,主要用来传递在redis中用做 value值的参数。

@GetMapping("testLockLua")
public void testLockLua() {
    //1 声明一个uuid ,将做为一个value 放入我们的key所对应的值中
    String uuid = UUID.randomUUID().toString();
    //2 定义一个锁:lua 脚本可以使用同一把锁,来实现删除!
    String skuId = "25"; // 访问skuId 为25号的商品 
    String locKey = "lock:" + skuId; // 锁住的是每个商品的数据
    // 3 获取锁
    Boolean lock = redisTemplate.opsForValue().setIfAbsent(locKey, uuid, 3, TimeUnit.SECONDS);
    // 第一种: lock 与过期时间中间不写任何的代码。
    // redisTemplate.expire("lock",10, TimeUnit.SECONDS);//设置过期时间
    // 如果true
    if (lock) {
        // 执行的业务逻辑开始
        // 获取缓存中的num 数据
        Object value = redisTemplate.opsForValue().get("num");
        // 如果是空直接返回
        if (StringUtils.isEmpty(value)) {
            return;
        }
        // 不是空 如果说在这出现了异常! 那么delete 就删除失败! 也就是说锁永远存在!
        int num = Integer.parseInt(value + "");
        // 使num 每次+1 放入缓存
        redisTemplate.opsForValue().set("num", String.valueOf(++num));
        /*使用lua脚本来锁*/
        // 定义lua 脚本
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        // 使用redis执行lua执行
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(script);
        // 设置一下返回值类型 为Long
        // 因为删除判断的时候,返回的0,给其封装为数据类型。如果不封装那么默认返回String 类型,
        // 那么返回字符串与0 会有发生错误。
        redisScript.setResultType(Long.class);
        // 第一个要是script 脚本 ,第二个需要判断的key,第三个就是key所对应的值。
        redisTemplate.execute(redisScript, Arrays.asList(locKey), uuid);
    } else {
        // 其他线程等待 
        try {
            // 睡眠
            Thread.sleep(1000);
            // 睡醒了之后,调用方法。
            testLockLua();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
LUA脚本

Lua 是一个小巧的脚本语言,Lua脚本可以很容易的被C/C++ 代码调用,也可以反过来调用C/C++的函数,Lua并没有提供强大的库,一个完整的Lua解释器不过200k,所以Lua不适合作为开发独立应用程序的语言,而是作为嵌入式脚本语言。

很多应用程序、游戏使用LUA作为自己的嵌入式脚本语言,以此来实现可配置性、可扩展性。

这其中包括魔兽争霸地图、魔兽世界、博德之门、愤怒的小鸟等众多游戏插件或外挂。

Lua 教程_w3cschool

Lua脚本基础入门及其案例_51CTO博客_lua脚本语言入门

LUA脚本在Redis中的优势

将复杂的或者多步的redis操作,写为一个脚本,一次提交给redis执行,减少反复连接redis的次数。提升性能。

LUA脚本是类似redis事务,有一定的原子性,不会被其他命令插队,可以完成一些redis事务性的操作。

但是注意redis的lua脚本功能,只有在Redis 2.6以上的版本才可以使用。

lua脚本示例

redis.call('set',KEYS[1],ARGV[1])
redis.call('set',KEYS[2],ARGV[2])
local n1 = tonumber(redis.call('get',KEYS[1]))
local n2 = tonumber(redis.call('get',KEYS[2]))
if n1 > n2 then
    return 1
end
if n1 == n2 then
    return 0
end
if n1 < n2 then
    return 2
end

 

/usr/local/bin/redis-cli -a lw --eval /usr/myredis/myluatest k1 k2 , 10 20
注意事项: key  和参数之间要用,隔开  并且,前后两端还有空格

 lua脚本示例

local userid=KEYS[1]; 
local prodid=KEYS[2];
local qtkey="sk:"..prodid..":qt";
local usersKey="sk:"..prodid..":usr"; 
local userExists=redis.call("sismember",usersKey,userid);
if tonumber(userExists)==1 then 
  return 2;
end
local num= redis.call("get" ,qtkey);
if tonumber(num)<=0 then 
  return 0; 
else 
  redis.call("decr",qtkey);
  redis.call("sadd",usersKey,userid);
end
return 1;

出错

 

针对如上错误,作如下处理:

1)查看打开文件的上限和redis服务进程,修改上限

输入如下命令,查看其上限:

ulimit -a

设置上限

ulimit -n 10032

重启redis即可

redisson

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。简单说就是redis在分布式系统上工具的集合,Redission提供了分布式锁的多种多样的功能.

使用redissoncheck

自定义redis分布式锁无法自动续期,比如,一个锁设置了1分钟超时释放,如果拿到这个锁的线程在一分钟内没有执行完毕,那么这个锁就会被其他线程拿到,可能会导致严重的线上问题,在秒杀场景下,很容易因为这个缺陷导致的超卖了。

10 2s

1s

redission 超时时间1m 执行逻辑的时候3m

锁的分类:

1 、乐观锁与悲观锁

乐观锁

悲观锁

2 、可重⼊锁和⾮可重⼊锁

可重⼊锁:当在⼀个线程中第⼀次成功获取锁之后,在此线程中就可以再次获取

⾮可重⼊锁

3 、公平锁和⾮公平锁

公平锁:按照线程的先后顺序获取锁

⾮公平锁:多个线程随机获取锁

4 、阻塞锁和⾮阻塞锁

阻塞锁:不断尝试获取锁,直到获取到锁为⽌

⾮阻塞锁:如果获取不到锁就放弃,但可以⽀持在⼀定时间段内的重试

—— 在⼀段时间内如果没有获取到锁就放弃

redisson的使用

1 、获取锁 —— 公平锁和⾮公平锁

    // 获取公平锁
    RLock lock = redissonClient . getFairLock ( skuId );
    // 获取⾮公平锁
    RLock lock = redissonClient . getLock ( skuId );

2 、加锁 —— 阻塞锁和⾮阻塞锁

    // 阻塞锁(如果加锁成功之后,超时时间为 30s ;加锁成功开启看⻔狗,剩 5s 延⻓过期时间)
    lock . lock ();
    // 阻塞锁(如果加锁成功之后,设置⾃定义 20s 的超时时间)
    lock . lock ( 20 , TimeUnit . SECONDS );
    // ⾮阻塞锁(设置等待时间为 3s ;如果加锁成功默认超时间为 30s )
    boolean b = lock . tryLock ( 3 , TimeUnit . SECONDS );
    // ⾮阻塞锁(设置等待时间为 3s ;如果加锁成功设置⾃定义超时间为 20s )
    boolean b = lock . tryLock ( 3 , 20 , TimeUnit . SECONDS );

3 、释放锁

 lock . unlock ();

4 、应⽤示例

    // 公平⾮阻塞锁
    RLock lock = redissonClient . getFairLock ( skuId );
    boolean b = lock . tryLock ( 3 , 20 , TimeUnit . SECONDS );

Redisson 锁加锁流程:线程去获取锁,获取成功则执行lua脚本,保存数据到redis数据库。如果获取失败: 一直通过while循环尝试获取锁(可自定义等待时间,超时后返回失败)。Redisson提供的分布式锁是支持锁自动续期的,也就是说,如果线程仍旧没有执行完,那么redisson会自动给redis中的目标key延长超时时间,这在Redisson中称之为 Watch Dog 机制。

 @Autowired
   private RedissonClient redissonClient;

    public void method1() {
        RLock lock = redissonClient.getLock("lock");
        boolean isLock = lock.tryLock();
        if (!isLock) {
            log.error("获取锁失败,1");
        }
        try {
            log.info("获取锁成功,1");
            method2();
        }finally {
            log.info("释放锁,1");
            lock.unlock();
        }
        
    }
    public void method2() {
        RLock lock = redissonClient.getLock("lock");
        boolean isLock = lock.tryLock();
        if (!isLock) {
            log.error("获取锁失败,2");
        }
        try {
            log.info("获取锁成功,2");
        }finally {
            log.info("释放锁,2");
            lock.unlock();
        }
    }

使用redission

加jar

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!--配置redission-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.12.5</version>
        </dependency>

application文件


# 设置redis的信息
spring.redis.host=192.168.174.72
spring.redis.database=0
spring.redis.password=yyl
spring.redis.port=6379

配置类:


package com.example.bootdemo.aaa.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedissonConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private String port;

    @Value("${spring.redis.password}")
    private String redisPassword;

    @Bean
    public RedissonClient getRedisson(){

        Config config = new Config();
// //多节点config.useClusterServers()
        //单机模式  依次设置redis地址和密码
        config.useSingleServer().
                setAddress("redis://" + host + ":" + port).
                setPassword(redisPassword);
        return Redisson.create(config);
    }
}

controller

package com.example.bootdemo.aaa.controller;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Objects;

@RestController
@RequestMapping("/redisLock")
public class RedisLockController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonClient redisson;

    private static final String REDIS_KEY = "redis_test";

    private static final int MAX_SIZE = 10;

    /**
     * 初始化库存
     */
    @PostMapping("/init")
    public void init() {
        stringRedisTemplate.opsForValue().set(REDIS_KEY, String.valueOf(MAX_SIZE));
    }

    /**
     * 扣库存业务
     */
    @PostMapping("/test")
    public void exportInventory() {

        String lockKey = "product001";
        RLock lock = redisson.getLock(lockKey);
        try {
            lock.lock();
            int s = Integer.parseInt(Objects.requireNonNull(stringRedisTemplate.opsForValue().get(REDIS_KEY)));
            System.out.printf("1号服务:库存当前为:" + s + "\n");
            //stringRedisTemplate.opsForValue().set(REDIS_KEY, String.valueOf(s));
            if(s>0) {
                stringRedisTemplate.opsForValue().decrement(REDIS_KEY);
            }
        } catch (Exception e) {
        } finally {
            lock.unlock();
        }
    }
}

使用jmeter测试:

写两个一模一样的项目 通过jmeter访问 redisLock/test

两个服务中的数据不重复即可

Redisson分布式锁入门使用(可重入锁(lock))_spring boot_人生没有第三次-华为云开发者联盟

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/352802.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Dockerfile入门指南:轻松创建定制化Docker镜像

镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本&#xff0c;用这个脚本来构建、定制镜像&#xff0c;那么无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。 Doc…

(大众金融)SQL server面试题(3)-客户已用额度总和

今天&#xff0c;面试了一家公司&#xff0c;什么也不说先来三道面试题做做&#xff0c;第三题。 那么&#xff0c;我们就开始做题吧&#xff0c;谁叫我们是打工人呢。 题目是这样的&#xff1a; DEALER_INFO经销商授信协议号码经销商名称经销商证件号注册地址员工人数信息维…

Windows上安装Linux系统

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、WSL是什么&#xff1f;二、WSL安装步骤1.开启wsl支持2.安装wsl3.运行wsl4.环境配置 三、WSL删除引用 前言 提示&#xff1a;这里可以添加本文要记录的大概…

故障树分析蒙特卡洛仿真程序(附MATLAB完整代码)

故障树是一种特殊的倒立树状逻辑因果关系图&#xff0c;它用事件符号、逻辑门符号和转移符号描述系统中各种事件之间的因果关系&#xff0c;通过对引起系统故障的各种因素进行逻辑因果分析&#xff0c;确定导致故障发生的各种可能的原因&#xff0c;并通过定性和定量分析找出系…

MybatisPlus二级映射和关联对象ResultMap

文章目录 一、业务背景1. 数据库表结构2. 需求 二、使用映射直接得到指定结构三、其他文件1. Mapper2. Service3. Controller 四、概念理解一级映射二级映射聚合 五、标签使用1. \<collection\> 标签2. \<association\> 标签 在我们的教程中&#xff0c;我们设计了…

三十四岁的程序员转行送外卖的不在少数啊

疫情过后的就业形势&#xff0c;对于很多人来说&#xff0c;真的变得更为严峻。我有很多之前的朋友&#xff0c;他们待业的时间长达半年&#xff0c;这对他们的生活和心理都造成了很大的压力。我是一名程序开发人员&#xff0c;虽然相对于其他行业来说&#xff0c;我们的薪资待…

如何保证接口幂等性

接口幂等性是指对同一操作发起的一次或多次请求结果是一致的&#xff0c;并且不会因为重复请求而产生副作用。 例如前端应用对后端发出请求&#xff0c;可能由于网络原因&#xff0c;前端并未接收到后端响应&#xff0c;前端进行重试&#xff0c;对后端同一接口发出多次请求 假…

Tortoise-tts Better speech synthesis through scaling——TTS论文阅读

笔记地址&#xff1a;https://flowus.cn/share/a79f6286-b48f-42be-8425-2b5d0880c648 【FlowUs 息流】tortoise 论文地址&#xff1a; Better speech synthesis through scaling Abstract: 自回归变换器和DDPM&#xff1a;自回归变换器&#xff08;autoregressive transfo…

SpringBoot中阿里云OSS的使用

目录 1 登录/注册阿里云并进入控制台 2 进入OSS控制台 3 创建bucket 4 查看bucket 5 获取AccessKey 6 查看帮助文档 7 添加Maven依赖 8 获取示例代码并改造成工具类 9 测试 1 登录/注册阿里云并进入控制台 2 进入OSS控制台 3 创建bucket 4 查看bucket 5 获取AccessKe…

套接字的多种可选项(修改IO缓冲区大小及TCP_NODELAY)

标题套接字的多种可选项 我们进行套接字编程时往往只关注数据通信&#xff0c;而忽略了套接字具有的不同特性。但是&#xff0c;理解这些特性并根据实际需要进行更改也十分重要。 从上表可以看出&#xff0c;套接字可选项是分层的。IPPROTOIP层可选项是IP协议相关事项&#x…

全局视角,搞懂“新零售支付”

文章首发于微信公众号:PenguinPay &#xff0c;欢迎关注。 零售业就是商家将商品或服务在场所中卖给消费者。其中的关键词就是 人&#xff0c;货&#xff0c;场。 一、 初始新零售 1.1 传统零售货找人 传统零售业,只能在固定场所销售商品或服务&#xff0c;以商家店为中心只…

探究SpringWeb对于请求的处理过程

探究目的 在路径归一化被提出后&#xff0c;越来越多的未授权漏洞被爆出&#xff0c;而这些未授权多半跟spring自身对路由分发的处理机制有关。今天就来探究一下到底spring处理了什么导致了才导致鉴权被绕过这样严重的问题。 DispatcherServlet介绍 首先在分析spring对请求处…

AI编译器的前端优化策略

背景 工作领域是AI芯片工具链相关&#xff0c;很多相关知识的概念都是跟着项目成长建立起来&#xff0c;但是比较整个技术体系在脑海中都不太系统&#xff0c;比如项目参与中涉及到了很多AI编译器开发相关内容&#xff0c;东西比较零碎&#xff0c;工作中也没有太多时间去做复盘…

上升子序列的最大长度,递归-记忆化搜索-动态规划三步走

题目描述&#xff1a; 小明有一个数组&#xff0c;他想从数组任意元素开始向后遍历&#xff0c;找出所有上升子序列&#xff0c;并计算出最长的上升子序列的长度。 数据范围&#xff1a; 每组数据长度满足 1≤n≤200 1≤n≤200 &#xff0c; 数据大小满足 1≤val≤350 1≤val≤…

C++基础入门

前言&#xff1a;哈喽小伙伴们&#xff0c;从这篇文章开始&#xff0c;博主将开启新篇章的讲解——C语言&#xff0c;那么C是一门怎么样的语言呢&#xff1f;&#xff1f;&#xff1f;它的语法又是怎么样的呢&#xff1f;&#xff1f;&#xff1f;这篇文章将给你一一解答。 目录…

阿里云部署配置幻兽帕鲁Palworld服务器教程

阿里云作为国内领先的云计算服务提供商&#xff0c;为企业和个人提供了丰富的云服务。最近幻兽帕鲁这款游戏挺火&#xff0c;阿里云为游戏开发者和玩家提供了一种高效、便捷的方式来部署配置幻兽帕鲁Palworld联机服务器&#xff0c;无需手动部署配置&#xff0c;3分钟即可完成幻…

Java笔记 --- 四、异常

四、异常 Java.lang.Throwable Error Exception&#xff08;异常&#xff09; 异常的作用 异常的处理方式 JVM默认的处理方式 捕获异常&#xff08;自己处理&#xff09; try里面没有出现异常&#xff0c;就不会运行catch里面的代码 如果出现多个异常&#xff0c;需要多个c…

【PyQt】01-PyQt下载

文章目录 前言静态库 一、PyQt是什么&#xff1f;二、安装1.Windows环境下安装安装PyQt5Designer 2.Liunx环境下安装 总结 前言 拜吾师 PyQt5 快速入门 静态库 补充一点知识&#xff1a; Windows&#xff1a; .lib Linux: .a .so(动态库) 简单描述PyQt就是python调用C的Qt文…

【超简版,代码可用!】【0基础Python爬虫入门——下载歌曲/视频】

安装第三方模块— requests 完成图片操作后输入&#xff1a;pip install requests 科普&#xff1a; get:公开数据 post:加密 &#xff0c;个人信息 进入某音乐网页&#xff0c;打开开发者工具F12 选择网络&#xff0c;再选择—>媒体——>获取URL【先完成刷新页面】 科…

2024年人工智能产业十大发展趋势

2024年人工智能产业十大发展趋势 技术变革1. 多模态预训练大模型将是人工智能产业的标配2. 高质量数据愈发稀缺将倒逼数据智能飞跃3. 智能算力无处不在的计算新范式加速实现 应用创新4. 人工智能生成内容&#xff08;AIGC&#xff09;应用向全场景渗透5. 人工智能驱动科学研究&…