redis 实践与扩展

文章目录

  • 前言
  • 一、springboot整合redis
    • 1、jedis
      • 1.1、单点模式
      • 1.2、哨兵模式
      • 1.3 集群模式
      • 1.4、关于jedis线程不安全的验证
    • 2、lettuce(推荐)
      • 2.1、单点模式
      • 2.2、哨兵模式
      • 2.3、集群模式
    • 3、RedisTemplate config
  • 二、redis常用知识点
    • 1、缓存数据一致性
    • 2、缓存雪崩
    • 3、缓存击穿
    • 4、缓存穿透
    • 5、慢查询
    • 6、pipelining


前言

Redis 是一个高性能的键值存储数据库,在许多应用场景中广泛使用,以下是有关 Redis 实践与扩展的一些内容。


一、springboot整合redis

1、jedis

yml

spring:
  redis:
    host: localhost # Redis服务器地址
    port: 6379      # Redis服务器端口
    password: your_password # 如果有密码的话
    timeout: 5000ms # 连接超时时间

1.1、单点模式

	public RedisConnectionFactory standalone() {
        RedisStandaloneConfiguration standalone = new RedisStandaloneConfiguration();
        standalone.setDatabase(this.redisProperties.getDatabase());
        standalone.setHostName(this.redisProperties.getHost());
        standalone.setPort(this.redisProperties.getPort());
        standalone.setPassword(RedisPassword.of(this.redisProperties.getPassword()));

        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
        this.initJedisPoolConfig(jpb);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(standalone, jpb.build());
        return jedisConnectionFactory;
    }
    
    private void initJedisPoolConfig(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb) {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        RedisProperties.Pool pool = this.redisProperties.getJedis().getPool();
        CustomRedisProperties.Pool customPool = this.customRedisProperties.getJedis().getPool();
        jedisPoolConfig.setMaxIdle(pool.getMaxIdle());
        jedisPoolConfig.setMinIdle(pool.getMinIdle());
        jedisPoolConfig.setMaxTotal(pool.getMaxActive());
        jedisPoolConfig.setMaxWaitMillis(pool.getMaxWait().toMillis());
        jedisPoolConfig.setTestOnBorrow(customPool.getTestOnBorrow());
        jedisPoolConfig.setTestOnReturn(customPool.getTestOnReturn());
        jedisPoolConfig.setTestWhileIdle(customPool.getTestWhileIdle());
        jpb.poolConfig(jedisPoolConfig);
        if (!Objects.isNull(pool.getEnabled()) && pool.getEnabled()) {
            jpb.and().usePooling();
        }
    }

1.2、哨兵模式

yml

spring:
  redis:
    password: your_redis_password
    sentinel:
      # 主节点名称
      master: mymaster 
      # 哨兵节点地址列表
      nodes: 
        - 192.168.1.101:26379
        - 192.168.1.102:26379
        - 192.168.1.103:26379 
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 5000ms

config

	public RedisConnectionFactory sentinel() {
        List<String> redisNodes = this.redisProperties.getSentinel().getNodes();
        String master = this.redisProperties.getSentinel().getMaster();
        RedisSentinelConfiguration sentinel = new RedisSentinelConfiguration();
        for (String redisHost : redisNodes) {
            String[] item = redisHost.split(":");
            String ip = item[0];
            String port = item[1];
            sentinel.addSentinel(new RedisNode(ip, Integer.parseInt(port)));
        }

        sentinel.setMaster(master);
        sentinel.setDatabase(this.redisProperties.getDatabase());
        if (!StringUtils.isEmpty(this.redisProperties.getPassword())) {
            sentinel.setPassword(RedisPassword.of(this.redisProperties.getPassword()));
        }

        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
        this.initJedisPoolConfig(jpb);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(sentinel, jpb.build());
        return jedisConnectionFactory;
    }
    
    private void initJedisPoolConfig(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb) {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        RedisProperties.Pool pool = this.redisProperties.getJedis().getPool();
        CustomRedisProperties.Pool customPool = this.customRedisProperties.getJedis().getPool();
        jedisPoolConfig.setMaxIdle(pool.getMaxIdle());
        jedisPoolConfig.setMinIdle(pool.getMinIdle());
        jedisPoolConfig.setMaxTotal(pool.getMaxActive());
        jedisPoolConfig.setMaxWaitMillis(pool.getMaxWait().toMillis());
        jedisPoolConfig.setTestOnBorrow(customPool.getTestOnBorrow());
        jedisPoolConfig.setTestOnReturn(customPool.getTestOnReturn());
        jedisPoolConfig.setTestWhileIdle(customPool.getTestWhileIdle());
        jpb.poolConfig(jedisPoolConfig);
        if (!Objects.isNull(pool.getEnabled()) && pool.getEnabled()) {
            jpb.and().usePooling();
        }
    }

1.3 集群模式

yml

spring:
  redis:
    password: your_redis_password
    sentinel:
      master: mymaster # 主节点名称
      nodes: 
        - 192.168.1.101:26379
        - 192.168.1.102:26379
        - 192.168.1.103:26379 # 哨兵节点地址列表
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 5000ms

config

	public RedisConnectionFactory cluster() {
        RedisClusterConfiguration cluster = new RedisClusterConfiguration(this.redisProperties.getCluster().getNodes());
        if (this.redisProperties.getCluster().getMaxRedirects() != null) {
            cluster.setMaxRedirects(this.redisProperties.getCluster().getMaxRedirects());
        }

        cluster.setUsername(this.redisProperties.getUsername());
        cluster.setPassword(RedisPassword.of(this.redisProperties.getPassword()));

        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
        this.initJedisPoolConfig(jpb);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(cluster, jpb.build());
        return jedisConnectionFactory;
    }
    
     private void initJedisPoolConfig(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb) {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        RedisProperties.Pool pool = this.redisProperties.getJedis().getPool();
        CustomRedisProperties.Pool customPool = this.customRedisProperties.getJedis().getPool();
        jedisPoolConfig.setMaxIdle(pool.getMaxIdle());
        jedisPoolConfig.setMinIdle(pool.getMinIdle());
        jedisPoolConfig.setMaxTotal(pool.getMaxActive());
        jedisPoolConfig.setMaxWaitMillis(pool.getMaxWait().toMillis());
        jedisPoolConfig.setTestOnBorrow(customPool.getTestOnBorrow());
        jedisPoolConfig.setTestOnReturn(customPool.getTestOnReturn());
        jedisPoolConfig.setTestWhileIdle(customPool.getTestWhileIdle());
        jpb.poolConfig(jedisPoolConfig);
        if (!Objects.isNull(pool.getEnabled()) && pool.getEnabled()) {
            jpb.and().usePooling();
        }
    }

1.4、关于jedis线程不安全的验证

public class Test {
     
    public static void main(String[] args) {
        //连接本地的 Redis 服务
        Jedis jedis = new Jedis("localhost");
        //查看服务是否运行
        System.out.println("服务正在运行: "+jedis.ping());
 
        for (int i = 0; i < 2; i++) {
            int finalI = i;
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    jedis.set("a" + finalI, String.valueOf(finalI));
                    System.out.println("a" + finalI + " = " + jedis.get("a" + finalI));
                }
            }).start();
        }
    }
}

运行结果

服务正在运行: PONG
a1 = OK
a1 = OK
a0 = 1
a0 = OK
a1 = 1
a1 = OK
a1 = 1
a0 = OK
a0 = OK
a1 = 0

假设jedis是线程安全的,那么在代码中,输出语句:“System.out.println(“a” + finalI + " = " + jedis.get(“a” + finalI));”的预期输出结果应该是“a0 = 0”或“a1 = 1”。但是实际上控制台中可以看到“a0 = OK”、“a1 = OK” 的错误输出。

jedis的请求流和响应流都是全局变量,当不同的线程在set和get的时候,有可能会出现线程A的set()的响应流,被线程B的get()作为返回了,所以出现了“a0 = OK”,“a1 = OK”的情况

2、lettuce(推荐)

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

2.1、单点模式

yml

spring:
  redis:
    host: localhost # Redis服务器地址
    port: 6379      # Redis服务器端口
    password: your_password # 如果有密码的话
    timeout: 5000ms # 连接超时时间
    lettuce:
      pool:
        max-active: 8 # 连接池最大活跃连接数
        max-idle: 8   # 连接池最大空闲连接数
        min-idle: 0   # 连接池最小空闲连接数
        max-wait: -1ms # 获取连接的最大等待时间

config

@Configuration
public class RedisConfig {

    @Bean
    public LettuceConnectionFactory redisConnectionFactory(@Value("${spring.redis.host}") String host,
                                                             @Value("${spring.redis.port}") int port,
                                                             @Value("${spring.redis.password}") String password) {
        return new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port));
    }
    
}

2.2、哨兵模式

yml

spring:
  redis:
    password: your_redis_password
    sentinel:
      master: mymaster # 主节点名称
      nodes: 
        - 192.168.1.101:26379
        - 192.168.1.102:26379
        - 192.168.1.103:26379 # 哨兵节点地址列表
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 5000ms

config

@Bean
public LettuceConnectionFactory redisConnectionFactory() {
    RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
            .master("mymaster")
            .sentinels(getSentinelNodes());

    return new LettuceConnectionFactory(sentinelConfig);
}

private Set<RedisNode> getSentinelNodes() {
    return Arrays.stream(redisProperties.getSentinel().getNodes())
                 .map(address -> address.split(":"))
                 .map(parts -> new RedisNode(parts[0], Integer.parseInt(parts[1])))
                 .collect(Collectors.toSet());
}

2.3、集群模式

yml

spring:
  redis:
    cluster:
      nodes: 
        - 192.168.1.11:6379
        - 192.168.1.12:6379
        - 192.168.1.13:6379
        - 192.168.1.14:6379
        - 192.168.1.15:6379
        - 192.168.1.16:6379 # 集群节点地址列表
      max-redirects: 3 # 重定向的最大次数
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 5000ms

config

@Bean
public LettuceConnectionFactory redisConnectionFactory() {
    List<String> nodeStrings = redisProperties.getCluster().getNodes();
    Set<RedisNode> nodes = nodeStrings.stream()
                                      .map(address -> address.split(":"))
                                      .map(parts -> new RedisNode(parts[0], Integer.parseInt(parts[1])))
                                      .collect(Collectors.toSet());

    return new LettuceConnectionFactory(new RedisClusterConfiguration(nodes));
}

3、RedisTemplate config

   @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        
        // 使用 Jackson 序列化器处理键值对中的对象
        GenericJackson2JsonRedisSerializer jacksonSerializer = new GenericJackson2JsonRedisSerializer();
        template.setValueSerializer(jacksonSerializer);
        template.setHashValueSerializer(jacksonSerializer);

        // 使用 String 序列化器处理键
        StringRedisSerializer stringSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);

        template.afterPropertiesSet();
        
        return template;
    }

二、redis常用知识点

1、缓存数据一致性

针对读多写少的⾼并发场景,我们可以使⽤缓存来提升查询速度
查询缓存逻辑

  • 我们查询DB之前,先去查询Redis,如果Redis存在,直接返回;
  • 如果Redis不存在,从DB查询,且回写到Redis
    假设场景如下
  • 线程A请求缓存,没有缓存,从DB拿到1。
  • 线程B将1更新为2,并且删除缓存,DB的值为2
  • 线程A更新缓存,redis为1
    我们发现,redis数据为1 ,db数据为2,出现了数据一致性问题。

如何解决一致性问题:

  • 延迟双删:更新DB后,等待一段时间,再进行Redis删除!确保其他的线程拿到的都是最新数据!
  • 分布式锁:避免并发
  • 最终一致性:设置有效期

2、缓存雪崩

缓存雪崩就是Redis的大量热点数据同时过期(失效),因为设置了相同的过期时间,刚好这个时候Redis请求的并发量又很大,就会导致所有的请求落到数据库。

解决办法

  • 保证Redis的高可用,防止由于Redis不可用导致全部打到DB
  • 加互斥锁或者使用队列,针对同一个key只允许一个线程到数据库查询
  • 缓存定时预先更新,避免同时失效
  • 通过加随机数,使key在不同的时间过期,或者永不过期

3、缓存击穿

缓存击穿(Cache Breakdown)是指在分布式系统中,当一个热点数据项的缓存过期或失效时,由于该数据项受到极高的并发访问请求,大量的请求会直接穿透到后端数据库,造成数据库瞬时压力剧增,可能影响数据库性能甚至导致其崩溃的现象。比如电商网站的商品秒杀活动等

解决办法

  • 互斥锁结合双重检查:第一次检查无锁,检查不存在则加锁进行二次检查,如果还是不存在,则查询DB,然后放进缓存,这样就保证了那一瞬间只有一个线程查询数据库
  • 热点数据永不过期或定期异步更新:对于那些非常热门的数据项,可以选择不设置过期时间,或者采用后台任务定期异步更新这些数据项的缓存副本。

4、缓存穿透

缓存穿透(Cache Penetration)是指在分布式系统中,某些恶意请求或者错误的业务逻辑导致查询了大量不存在的数据项。每次这样的请求都会直接打到数据库,造成不必要的压力,并且由于数据不存在,缓存也无法起到应有的作用。

解决办法

  • 布隆过滤器:很大程度避免无效查询
  • 权限验证:参数验证、黑白名单
  • 监控预警系统:监控是否有恶意攻击

布隆过滤器的原理分析
在这里插入图片描述

  • 初始化
    当创建一个布隆过滤器时,首先会初始化一个全为0的位数组(bit array),这个数组的长度通常远大于预期要存储的元素数量。

  • 添加元素

    • 哈希运算:每当向布隆过滤器中添加一个新的元素时,该元素会被多个独立设计的哈希函数处理。每个哈希函数都会根据输入元素计算出一个索引值。
    • 设置位:对于每一个由哈希函数产生的索引值,在位数组中对应的位将被设置为1。如果同一个位置已经被其他元素置为1,则保持不变。

例如,假设我们有三个不同的哈希函数,并且我们要添加一个字符串 “example” 到布隆过滤器中,那么这三个哈希函数可能会分别产生索引值 5、17 和 34。接下来,我们会将位数组中第5位、第17位以及第34位都设为1。

  • 查询元素
    • 哈希运算:当查询某个元素是否存在于布隆过滤器中时,同样使用相同的哈希函数对该元素进行哈希运算,得到一系列索引值。
    • 检查位:然后检查这些索引值所对应的位是否全部为1。如果是,则表示该元素很可能存在于集合中;如果任何一个索引值对应的位置是0,则可以肯定地说该元素不在集合中。

需要注意的是,由于可能存在多个不同元素映射到相同的位置,即使所有指定的位都是1,也不能百分之百确定该元素确实存在于集合中。这种情况下,存在一定的误报率(False Positive Rate),即原本不存在于集合中的元素也被认为可能存在。

  • 删除操作
    传统意义上的布隆过滤器不支持直接删除元素的操作,因为一旦将某一位从1重置回0,就可能会影响到那些也依赖于此位的其他元素的正确性。不过,有一种变种叫做计数布隆过滤器(Counting Bloom Filter),它可以记录每个位被多少个元素引用,从而允许一定程度上的删除操作。

  • 误判率与参数选择

    • 误判率:随着插入到布隆过滤器中的元素增多,位数组中更多的位被设置为1,导致后续插入或查询时发生冲突的可能性增加,进而提高了误判的概率。因此,在实际应用中需要权衡误判率和资源消耗之间的关系。
    • 参数选择:为了最小化误判率并优化性能,开发者需要精心挑选位数组的大小m、哈希函数的数量k以及预计插入的元素数量n。理论上,可以通过数学公式来推导最优的m和k值,以达到预期的误判率。

5、慢查询

在Redis中,慢查询日志用于记录执行时间超过预设阈值的命令,这些信息可以帮助开发和运维人员定位性能问题。每条慢查询日志包含标识ID、发生时间戳、命令耗时及详细信息。需要注意的是,慢查询只记录命令执行的时间,并不包括命令排队和网络传输时间,因此客户端执行命令的时间可能会大于命令实际执行的时间

  • 配置慢查询参数
    Redis通过两个主要配置参数来管理慢查询功能:

    • slowlog-log-slower-than:这个参数定义了什么情况下被认为是“慢”的查询。它的单位是微秒(1秒 = 1000毫秒 = 1000000微秒),默认值为10000微秒(即10毫秒)。如果设置为0,则表示记录所有命令;若设置为负数,则不会记录任何命令。
    • slowlog-max-len:该参数指定了慢查询日志最多可以存储多少条记录。实际上,Redis使用了一个列表来存储慢查询日志,slowlog-max-len就是列表的最大长度。它是一个先进先出队列,当新的命令满足慢查询条件时会被插入到列表中,而当列表已满时,最早的记录将会被移除以腾出空间给新的记录
  • 查看与管理慢查询日志

    • SLOWLOG GET [count]:此命令用来获取指定数量的最新慢查询记录。如果不提供count参数,默认会返回所有的慢查询记录。
    • SLOWLOG LEN:该命令用于查询当前保存在内存中的慢查询日志的数量。
    • SLOWLOG RESET:这个命令用于清空现有的慢查询日志记录。
  • 实际应用中的注意事项
    在实际的应用场景中,使用Redis慢查询日志时还需要注意以下几点:

  • 调整阈值:对于高并发量的环境,建议根据实际情况调整slowlog-log-slower-than的值,例如将其设为1毫秒,以便更敏感地捕捉潜在的问题。

  • 增加日志容量:线上环境中应适当增大slowlog-max-len,以确保更多的慢查询能够被记录下来供后续分析。同时,考虑到日志数据的重要性,还可以考虑定期将慢查询日志持久化到外部存储系统中。

  • 避免误判:由于Redis采用单线程模型处理请求,一个长时间运行的命令会导致其他命令的级联阻塞。因此,当遇到客户端请求超时的情况时,应该检查对应时间点是否有慢查询的存在,从而判断是否是由慢查询引起的延迟。

6、pipelining

客户端发送一个请求给服务端----->客户端等待服务器响应—>服务器收到请求并处理---->返回客户端
例如,五个命令序列是这样的:

SET X 0
INCR X
INCR X
INCR X
INCR X

客户端到服务端是需要时间的,包括网络传输,连接等等,我们将这个时间称为RTT时间(Round Trip Time)。如果每次都做一次这样的操作,那会很大影响到影响我们的性能。
Redis出现了一个pipelining管道技术,目的就是不要每次执行一次指令都经过一次RTT时间,可以使多个指令只需要经历一次RTT时间,这样子性能一般能提升5到10倍。

验证:
1、不用pipelining

public long noPipelining() {
  long start = System.currentTimeMillis();
  for (int i = 0; i < 100000; i++) {
    redisTemplate.opsForValue().set("tes" + i, i);
  }
  long end = System.currentTimeMillis();
  return end - start;
}

测试10W个key,耗时40S左右

@RequestMapping(value = "/noPipelining" , method = RequestMethod.GET)
@ResponseBody
public long noPipelining() {
    return productService.noPipelining();
}

2、用pipelining

public long pipelining() {
  long start = System.currentTimeMillis();
  redisTemplate.executePipelined((RedisCallback<Object>)
          connection ->
          {
            for (int i = 0; i <100000 ; i++) {
              connection.stringCommands().set(("key"+i).getBytes(),Strin
                      g.valueOf(i).getBytes(StandardCharsets.UTF_8));
            }
            return null;
          });
  long end = System.currentTimeMillis();
  return end - start;
}

测试10W个key,耗时1S左右

@RequestMapping(value = "/pipelining" ,method = RequestMethod.GET)
@ResponseBody
public long pipelining() {
  return productService.pipelining();
}

我们发现性能提升了将近40倍,但是也不是任意使用pipelining技术,需要注意一下几点

  • 原子性:Pipelining 并不能保证命令执行的原子性。也就是说,在 Pipelining 执行期间,其他客户端仍可以向 Redis 发送命令,而且如果某个命令失败了,也不会影响到其他命令的成功执行。因此,如果命令之间存在依赖关系,则不适合使用 Pipelining。
  • 错误处理:如果在 Pipelining 过程中发生了错误,Redis 不支持回滚操作。这意味着开发者需要自行设计逻辑来处理可能出现的问题。
  • 命令数量限制:虽然理论上 Pipelining 可以包含任意数量的命令,但实际上由于输入缓存区大小有限制(例如,默认最大为 1GB),所以不应该无限制地增加 Pipelining 中的命令数量。
  • 避免高延迟命令:为了确保良好的性能表现,应当避免在 Pipelining 内部包含那些执行时间较长的命令,因为这可能会阻塞整个队列。

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

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

相关文章

積分方程與簡單的泛函分析7.希爾伯特-施密特定理

1)def函數叫作"由核生成的(有源的)" 定义: 设 是定义在区域上的核函数。 对于函数,若存在函数使得, 则称函数是“由核生成的(有源的)”。 这里的直观理解是: 函数的“来源”可以通过核函数 与另一个函数的积分运算得到。 在积分方程理论中,这种表述常…

RH850F1KM-S4-100Pin_ R7F7016453AFP MCAL PWM 测试

1、PortPin配置 2、PwmChannel配置 4、PwmComplexDriverInit 配置注意事项 此参数指定通道是否初始化并由复杂驱动程序使用。 True:通道将被初始化并由复杂驱动程序使用。False:通道不会被初始化并被复杂驱动程序使用。

Spring Boot Starter介绍

前言 大概10来年以前&#xff0c;当时springboot刚刚出现并没有流行&#xff0c;当时的Java开发者们开发Web应用主要是使用spring整合springmvc或者struts、iBatis、hibernate等开发框架来进行开发。项目里一般有许多xml文件配置&#xff0c;其中配置了很多项目中需要用到的Be…

【科研建模】Pycaret自动机器学习框架使用流程及多分类项目实战案例详解

Pycaret自动机器学习框架使用流程及项目实战案例详解 1 Pycaret介绍2 安装及版本需求3 Pycaret自动机器学习框架使用流程3.1 Setup3.2 Compare Models3.3 Analyze Model3.4 Prediction3.5 Save Model4 多分类项目实战案例详解4.1 ✅ Setup4.2 ✅ Compare Models4.3 ✅ Experime…

CY T 4 BB 5 CEB Q 1 A EE GS MCAL配置 - MCU组件

1、ResourceM 配置 选择芯片信号: 2、MCU 配置 2.1 General配置 1) McuDevErrorDetect: - 启用或禁用MCU驱动程序模块的开发错误通知功能。 - 注意:采用DET错误检测机制作为安全机制(故障检测)时,不能禁用开发错误检测。2) McuGetRamStateApi - enable/disable th…

【论文阅读】RAG-Reward: Optimizing RAG with Reward Modeling and RLHF

研究背景 研究问题&#xff1a;这篇文章要解决的问题是如何优化检索增强生成&#xff08;RAG&#xff09;系统&#xff0c;特别是通过奖励建模和人类反馈强化学习&#xff08;RLHF&#xff09;来提高大型语言模型&#xff08;LLMs&#xff09;在RAG任务中的效果。研究难点&…

关于WPF中ComboBox文本查询功能

一种方法是使用事件&#xff08;包括MVVM的绑定&#xff09; <ComboBox TextBoxBase.TextChanged"ComboBox_TextChanged" /> 然而运行时就会发现&#xff0c;这个事件在疯狂的触发&#xff0c;很频繁 在实际应用中&#xff0c;如果关联查询数据库&#xff0…

java求职学习day15

多线程 1 基本概念 1.1 程序和进程的概念 &#xff08;1&#xff09;程序 - 数据结构 算法&#xff0c;主要指存放在硬盘上的可执行文件。 &#xff08;2&#xff09;进程 - 主要指运行在内存中的可执行文件。 &#xff08;3&#xff09;目前主流的操作系统都支持多进程&a…

2025年数学建模美赛:A题分析(1)Testing Time: The Constant Wear On Stairs

2025年数学建模美赛 A题分析&#xff08;1&#xff09;Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析&#xff08;2&#xff09;楼梯磨损分析模型 2025年数学建模美赛 A题分析&#xff08;3&#xff09;楼梯使用方向偏好模型 2025年数学建模美赛 A题分…

2024年终总结:技术成长与突破之路

文章目录 前言一、技术成长&#xff1a;菜鸟成长之路1. 学习与实践的结合2. 技术分享与社区交流 二、生活与事业的平衡&#xff1a;技术之外的思考1. 时间管理与效率提升2. 技术对生活的积极影响 三、突破与展望&#xff1a;未来之路1. 技术领域的突破2. 未来规划与目标 四、结…

go入门Windows环境搭建

简介 Go 即 Golang&#xff0c;是 Google 公司 2009 年 11 月正式对外公开的一门编程语言。 根据 Go 语言开发者自述&#xff0c;近 10 多年&#xff0c;从单机时代的 C 语言到现在互联网时代的 Java&#xff0c;都没有令人满意的开发语言&#xff0c;而 C往往给人的感觉是&a…

机器学习:支持向量机

支持向量机&#xff08;Support Vector Machine&#xff09;是一种二类分类模型&#xff0c;其基本模型定义为特征空间上的间隔最大的广义线性分类器&#xff0c;其学习策略便是间隔最大化&#xff0c;最终可转化为一个凸二次规划问题的求解。 假设两类数据可以被 H x : w T x…

MyBatis框架基础学习(1)

目录 一、MyBatis框架介绍。 &#xff08;1&#xff09;简化开发。 &#xff08;2&#xff09;持久层&#xff1f; &#xff08;3&#xff09;框架的解释&#xff01; 二、JDBC开发缺点。 &#xff08;1&#xff09;硬编码。 &#xff08;2&#xff09;操作繁琐。 三、MyBatis框…

如何有效进行软件集成测试?常见的集成测试工具分享

在现代软件开发的过程中&#xff0c;集成测试是确保系统各部分有效协同工作的关键步骤。软件集成测试是指在软件开发过程中&#xff0c;将各个模块或组件组合在一起进行测试&#xff0c;以验证它们之间的交互是否符合设计要求和业务逻辑。集成测试的核心目标是发现不同模块互动…

电力场效应晶体管(电力 MOSFET),全控型器件

电力场效应晶体管&#xff08;Power MOSFET&#xff09;属于全控型器件是一种电压触发的电力电子器件&#xff0c;一种载流子导电&#xff08;单极性器件&#xff09;一个器件是由一个个小的mosfet组成以下是相关介绍&#xff1a; 工作原理&#xff08;栅极电压控制漏极电流&a…

【CES2025】超越界限:ThinkAR推出8小时满电可用的超轻AR眼镜AiLens

在2025年国际消费类电子产品展览会(CES 2025)上,日本AR技术开发商ThinkAR携手超低功耗半导体和边缘AI解决方案提供商Ambiq,共同推出了名为AiLens的最新AR眼镜产品。这款设备不仅具备轻便的设计,而且拥有长达8小时的连续使用时间,为用户带来了前所未有的便捷体验。 AiLen…

记交叉编译asio_dtls过程

虽然编译成功了&#xff0c;但是还是有一些不妥的地方&#xff0c;参考一下就行了。 比如库的版本选择就有待商榷&#xff0c;我这里不是按照项目作者的要求严格用对应的版本编译的&#xff0c;这里也可以注意一下。 编译依赖库asio 下载地址, 更正一下&#xff0c;我其实用…

批处理打开msys2 ucrt64版本qemu 从BIOS模式启动u盘

qemu的msys2版本为qemu官网在windows 平台的推荐。 此处以windows x86_64平台的msys2版本为例子。 一、安装msys2 x86_64版本 官网下载msys2 的x86_64版本安装包安装即可&#xff0c;此处示例安装了支持windows8.1 x86_64和以上的msys2版本。此处示例将msys2安装到windows硬…

windows 安装 mysql 教程

一、下载 点开下面的链接&#xff1a; https://downloads.mysql.com/archives/community/ 点击Download 就可以下载对应的安装包了, 安装包如下: 二、解压 下载完成后我们得到的是一个压缩包&#xff0c;将其解压&#xff0c;我们就可以得到MySQL 8.0.28 的软件本体了(就是…

C语言精粹:深入探索字符串函数

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文&#xff08;1&#xff09;常见字…