05 缓存预热+缓存雪崩+缓存击穿+缓存穿透

news2024/9/20 20:37:55

缓存血崩

发生

  • redis主机挂了,Redis 全盘崩溃
  • 比如缓存中有大量数据同时过期

解决

在这里插入图片描述

  • redis缓存集群实现高可用
    • 主从+哨兵
    • Redis Cluster
  • ehcache本地缓存 + Hystrix或者阿里sentinel限流&降级
  • 开启Redis持久化机制aof/rdb,尽快恢复缓存集群

缓存穿透

  • 是什么

    • 请求去查询一条记录,先redis后mysql发现都查询不到该条记录,但是请求每次都会打到数据库上面去,导致后台数据库压力暴增,这种现象我们称为缓存穿透,这个redis变成了一个摆设。。。。。。
    • 简单说就是本来无一物,既不在Redis缓存中,也不在数据库中
  • 危害

    • 第一次来查询后,一般我们有回写redis机制
    • 第二次来查的时候redis就有了,偶尔出现穿透现象一般情况无关紧要

解决

方案1:空对象缓存或者缺省值

  • 在这里插入图片描述
  • 黑客或者恶意攻击
    • 黑客会对你的系统进行攻击,拿一个不存在的id 去查询数据,会产生大量的请求到数据库去查询。可能会导致你的数据库由于压力过大而宕掉
    • id相同打你系统:第一次打到mysql,空对象缓存后第二次就返回null了,避免mysql被攻击,不用再到数据库中去走一圈了
    • id不同打你系统:由于存在空对象缓存和缓存回写(看自己业务不限死),redis中的无关紧要的key也会越写越多(记得设置redis过期时间)

方案2:Google布隆过滤器Guava解决缓存穿透

  • Guava 中布隆过滤器的实现算是比较权威的,所以实际项目中我们不需要手动实现一个布隆过滤器
  • Guava’s BloomFilter 源码剖析
  • Coding实战
    • 建Module:bloomfilter_demo

    • 改POM

      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <parent>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-parent</artifactId>
              <version>2.3.10.RELEASE</version>
              <relativePath/> <!-- lookup parent from repository -->
          </parent>
      
          <groupId>com.atguigu.redis.bloomfilter</groupId>
          <artifactId>bloomfilter_demo</artifactId>
          <version>0.0.1-SNAPSHOT</version>
      
      
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <maven.compiler.source>1.8</maven.compiler.source>
              <maven.compiler.target>1.8</maven.compiler.target>
              <junit.version>4.12</junit.version>
              <log4j.version>1.2.17</log4j.version>
              <lombok.version>1.16.18</lombok.version>
              <mysql.version>5.1.47</mysql.version>
              <druid.version>1.1.16</druid.version>
              <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
          </properties>
      
          <dependencies>
              <!--guava Google 开源的 Guava 中自带的布隆过滤器-->
              <dependency>
                  <groupId>com.google.guava</groupId>
                  <artifactId>guava</artifactId>
                  <version>23.0</version>
              </dependency>
              <!-- redisson -->
              <dependency>
                  <groupId>org.redisson</groupId>
                  <artifactId>redisson</artifactId>
                  <version>3.13.4</version>
              </dependency>
              <!--web+actuator-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-actuator</artifactId>
              </dependency>
              <!--SpringBoot与Redis整合依赖-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-data-redis</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.apache.commons</groupId>
                  <artifactId>commons-pool2</artifactId>
              </dependency>
              <!-- jedis -->
              <dependency>
                  <groupId>redis.clients</groupId>
                  <artifactId>jedis</artifactId>
                  <version>3.1.0</version>
              </dependency>
              <!-- springboot-aop 技术-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-aop</artifactId>
              </dependency>
              <!--Mysql数据库驱动-->
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>5.1.47</version>
              </dependency>
              <!--集成druid连接池-->
              <dependency>
                  <groupId>com.alibaba</groupId>
                  <artifactId>druid-spring-boot-starter</artifactId>
                  <version>1.1.10</version>
              </dependency>
              <dependency>
                  <groupId>com.alibaba</groupId>
                  <artifactId>druid</artifactId>
                  <version>${druid.version}</version>
              </dependency>
              <dependency>
                  <groupId>com.alibaba</groupId>
                  <artifactId>druid</artifactId>
                  <version>${druid.version}</version>
              </dependency>
              <!--mybatis和springboot整合-->
              <dependency>
                  <groupId>org.mybatis.spring.boot</groupId>
                  <artifactId>mybatis-spring-boot-starter</artifactId>
                  <version>${mybatis.spring.boot.version}</version>
              </dependency>
              <!-- 添加springboot对amqp的支持 -->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-amqp</artifactId>
              </dependency>
              <!--通用基础配置-->
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>${junit.version}</version>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-devtools</artifactId>
                  <scope>runtime</scope>
                  <optional>true</optional>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-test</artifactId>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>log4j</groupId>
                  <artifactId>log4j</artifactId>
                  <version>${log4j.version}</version>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <version>${lombok.version}</version>
                  <optional>true</optional>
              </dependency>
          </dependencies>
      
          <build>
              <plugins>
                  <plugin>
                      <groupId>org.springframework.boot</groupId>
                      <artifactId>spring-boot-maven-plugin</artifactId>
                  </plugin>
              </plugins>
          </build>
      
      </project>
      
    • 写YML

      server.port=6666
      # ========================alibaba.druid相关配置=====================
      spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
      spring.datasource.driver-class-name=com.mysql.jdbc.Driver
      spring.datasource.url=jdbc:mysql://localhost:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
      spring.datasource.username=root
      spring.datasource.password=123456
      spring.datasource.druid.test-while-idle=false
      
      # ========================redis相关配置=====================
      # Redis数据库索引(默认为0)
      spring.redis.database=0
      # Redis服务器地址
      spring.redis.host=192.168.111.147
      # Redis服务器连接端口
      spring.redis.port=6379
      # Redis服务器连接密码(默认为空)
      spring.redis.password=
      # 连接池最大连接数(使用负值表示没有限制) 默认 8
      spring.redis.lettuce.pool.max-active=8
      # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
      spring.redis.lettuce.pool.max-wait=-1
      # 连接池中的最大空闲连接 默认 8
      spring.redis.lettuce.pool.max-idle=8
      # 连接池中的最小空闲连接 默认 0
      spring.redis.lettuce.pool.min-idle=0
      
    • 主启动

    • 业务类

      package com.learn.bloomfilter;
      
      import com.google.common.hash.BloomFilter;
      import com.google.common.hash.Funnels;
      
      import java.util.ArrayList;
      import java.util.List;
      
      /**
       * @author YSK
       * @since 2023/5/31 14:25
       */
      public class GuavaBloomFilterDemo {
          public static final int _1W = 10000;
          //布隆过滤器里预计要插入多少数据
          public static int size = 100 * _1W;
          //误判率,它越小误判的个数也就越少(思考,是不是可以设置的无限小,没有误判岂不更好)
          //默认是0.03
          public static double fpp = 0.01;
      
          /**
           * helloworld入门
           */
          public void bloomFilter() {
              // 创建布隆过滤器对象
              BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(), 100);
              // 判断指定元素是否存在
              System.out.println(filter.mightContain(1));
              System.out.println(filter.mightContain(2));
              // 将元素添加进布隆过滤器
              filter.put(1);
              filter.put(2);
              System.out.println(filter.mightContain(1));
              System.out.println(filter.mightContain(2));
      
          }
      
          /**
           * 误判率演示+源码分析
           */
          public void bloomFilter2() {
              // 构建布隆过滤器
              BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);
      
              //1 先往布隆过滤器里面插入100万的样本数据
              for (int i = 0; i < size; i++) {
                  bloomFilter.put(i);
              }
             /* List<Integer> listSample = new ArrayList<>(size);
              //2 这100万的样本数据,是否都在布隆过滤器里面存在?
              for (int i = 0; i < size; i++)
              {
                  if (bloomFilter.mightContain(i)) {
                      listSample.add(i);
                      continue;
                  }
              }
              System.out.println("存在的数量:" + listSample.size());*/
      
              //3 故意取10万个不在过滤器里的值,看看有多少个会被认为在过滤器里,误判率演示
              List<Integer> list = new ArrayList<>(10 * _1W);
      
              for (int i = size + 1; i < size + 100000; i++) {
                  if (bloomFilter.mightContain(i)) {
                      System.out.println(i + "\t" + "被误判了.");
                      list.add(i);
                  }
              }
              System.out.println("误判的数量:" + list.size());
          }
      
          public static void main(String[] args) {
              new GuavaBloomFilterDemo().bloomFilter();
          }
      }
      
  • 布隆过滤器说明
  • 在这里插入图片描述

方案3:Redis布隆过滤器解决缓存穿透

  • Guava缺点说明:Guava 提供的布隆过滤器的实现还是很不错的 (想要详细了解的可以看一下它的源码实现),但是它有一个重大的缺陷就是只能单机使用 ,而现在互联网一般都是分布式的场景。
案例:白名单过滤器
  • 白名单架构说明
  • 在这里插入图片描述
  • 误判问题,但是概率小可以接受,不能从布隆过滤器删除
  • 全部合法的key都需要放入过滤器+redis里面,不然数据就是返回null
  • code
package com.learn.bloomfilter;

import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author YSK
 * @since 2023/5/31 15:48
 */
public class RedissonBloomFilterDemo {
    public static final int _1W = 10000;

    //布隆过滤器里预计要插入多少数据
    public static int size = 100 * _1W;
    //误判率,它越小误判的个数也就越少
    public static double fpp = 0.03;

    static RedissonClient redissonClient = null;//jedis
    static RBloomFilter rBloomFilter = null;//redis版内置的布隆过滤器

    @Resource
    RedisTemplate redisTemplate;


    static {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.111.147:6379").setDatabase(0);
        //构造redisson
        redissonClient = Redisson.create(config);
        //通过redisson构造rBloomFilter
        rBloomFilter = redissonClient.getBloomFilter("phoneListBloomFilter", new StringCodec());

        rBloomFilter.tryInit(size, fpp);

        // 1测试  布隆过滤器有+redis有
        //rBloomFilter.add("10086");
        //redissonClient.getBucket("10086",new StringCodec()).set("chinamobile10086");

        // 2测试  布隆过滤器有+redis无
        //rBloomFilter.add("10087");

        //3 测试 ,布隆过滤器无+redis无

    }

    private static String getPhoneListById(String IDNumber) {
        String result = null;

        if (IDNumber == null) {
            return null;
        }
        //1 先去布隆过滤器里面查询
        if (rBloomFilter.contains(IDNumber)) {
            //2 布隆过滤器里有,再去redis里面查询
            RBucket<String> rBucket = redissonClient.getBucket(IDNumber, new StringCodec());
            result = rBucket.get();
            if (result != null) {
                return "i come from redis: " + result;
            } else {
                result = getPhoneListByMySQL(IDNumber);
                if (result == null) {
                    return null;
                }
                // 重新将数据更新回redis
                redissonClient.getBucket(IDNumber, new StringCodec()).set(result);
            }
            return "i come from mysql: " + result;
        }
        return result;
    }

    private static String getPhoneListByMySQL(String IDNumber) {
        return "chinamobile" + IDNumber;
    }


    public static void main(String[] args) {
        //String phoneListById = getPhoneListById("10086");
        //String phoneListById = getPhoneListById("10087"); //请测试执行2次
        String phoneListById = getPhoneListById("10088");
        System.out.println("------查询出来的结果: " + phoneListById);

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        redissonClient.shutdown();
    }
}

  • 总结
  • 在这里插入图片描述

缓存击穿

是什么

  • 大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去
  • 简单说就是热点key突然失效了,暴打mysql
  • 危害:会造成某一时刻数据库请求量过大,压力剧增。

解决

  • 对于访问频繁的热点key,干脆就不设置过期时间
  • 互斥独占锁防止击穿
    • 多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。
    • 其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。
    • 在这里插入图片描述

高并发的淘宝聚划算案例落地

分析过程

  1. 100%高并发,绝对不可以用mysql实现
  2. 先把mysql里面参加活动的数据抽取进redis,一般采用定时器扫描来决定上线活动还是下线取消。
  3. 支持分页功能,一页20条记录

redis数据类型选型

在这里插入图片描述

springboot+redis实现高并发的淘宝聚划算业务

 
package com.atguigu.redis.service;

import cn.hutool.core.date.DateUtil;
import com.atguigu.redis.entities.Product;
import com.atguigu.redis.util.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @auther zzyy
 * @create 2021-05-09 14:47
 */
@Service
@Slf4j
public class JHSTaskService
{
    @Autowired
    private RedisTemplate redisTemplate;

    @PostConstruct
    public void initJHS(){
        log.info("启动定时器淘宝聚划算功能模拟.........."+DateUtil.now());
        new Thread(() -> {
            //模拟定时器,定时把数据库的特价商品,刷新到redis中
            while (true){
                //模拟从数据库读取100件特价商品,用于加载到聚划算的页面中
                List<Product> list=this.products();
                //采用redis list数据结构的lpush来实现存储
                this.redisTemplate.delete(Constants.JHS_KEY);
                //lpush命令
                this.redisTemplate.opsForList().leftPushAll(Constants.JHS_KEY,list);
                //间隔一分钟 执行一遍
                try { TimeUnit.MINUTES.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

                log.info("runJhs定时刷新..............");
            }
        },"t1").start();
    }

    /**
     * 模拟从数据库读取100件特价商品,用于加载到聚划算的页面中
     */
    public List<Product> products() {
        List<Product> list=new ArrayList<>();
        for (int i = 1; i <=20; i++) {
            Random rand = new Random();
            int id= rand.nextInt(10000);
            Product obj=new Product((long) id,"product"+i,i,"detail");
            list.add(obj);
        }
        return list;
    }
}
 
package com.atguigu.redis.controller;

import com.atguigu.redis.entities.Product;
import com.atguigu.redis.util.Constants;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @auther zzyy
 * @create 2021-05-09 14:56
 */
@RestController
@Slf4j
@Api(description = "聚划算商品列表接口")
public class JHSProductController
{
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 分页查询:在高并发的情况下,只能走redis查询,走db的话必定会把db打垮
     * http://localhost:5555/swagger-ui.html#/jhs-product-controller/findUsingGET
     */
    @RequestMapping(value = "/pruduct/find",method = RequestMethod.GET)
    @ApiOperation("按照分页和每页显示容量,点击查看")
    public List<Product> find(int page, int size) {
        List<Product> list=null;
        long start = (page - 1) * size;
        long end = start + size - 1;
        try {
            //采用redis list数据结构的lrange命令实现分页查询
            list = this.redisTemplate.opsForList().range(Constants.JHS_KEY, start, end);
            if (CollectionUtils.isEmpty(list)) {
                //TODO 走DB查询
            }
            log.info("查询结果:{}", list);
        } catch (Exception ex) {
            //这里的异常,一般是redis瘫痪 ,或 redis网络timeout
            log.error("exception:", ex);
            //TODO 走DB查询
        }
        return list;
    }

}

Bug和隐患说明

  • QPS上1000后导致可怕的缓存击穿
  • 在这里插入图片描述
  • 在这里插入图片描述

进一步升级加固案例

  • 定时轮询,互斥更新,差异失效时间
  • 在这里插入图片描述
 
package com.atguigu.redis.service;

import cn.hutool.core.date.DateUtil;
import com.atguigu.redis.entities.Product;
import com.atguigu.redis.util.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @auther zzyy
 * @create 2021-05-09 15:54
 */
@Service
@Slf4j
public class JHSABTaskService
{
    @Autowired
    private RedisTemplate redisTemplate;

    @PostConstruct
    public void initJHSAB(){
        log.info("启动AB定时器计划任务淘宝聚划算功能模拟.........."+DateUtil.now());
        new Thread(() -> {
            //模拟定时器,定时把数据库的特价商品,刷新到redis中
            while (true){
                //模拟从数据库读取100件特价商品,用于加载到聚划算的页面中
                List<Product> list=this.products();
                //先更新B缓存
                this.redisTemplate.delete(Constants.JHS_KEY_B);
                this.redisTemplate.opsForList().leftPushAll(Constants.JHS_KEY_B,list);
                this.redisTemplate.expire(Constants.JHS_KEY_B,20L,TimeUnit.DAYS);
                //再更新A缓存
                this.redisTemplate.delete(Constants.JHS_KEY_A);
                this.redisTemplate.opsForList().leftPushAll(Constants.JHS_KEY_A,list);
                this.redisTemplate.expire(Constants.JHS_KEY_A,15L,TimeUnit.DAYS);
                //间隔一分钟 执行一遍
                try { TimeUnit.MINUTES.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

                log.info("runJhs定时刷新..............");
            }
        },"t1").start();
    }

    /**
     * 模拟从数据库读取100件特价商品,用于加载到聚划算的页面中
     */
    public List<Product> products() {
        List<Product> list=new ArrayList<>();
        for (int i = 1; i <=20; i++) {
            Random rand = new Random();
            int id= rand.nextInt(10000);
            Product obj=new Product((long) id,"product"+i,i,"detail");
            list.add(obj);
        }
        return list;
    }
}
 
package com.atguigu.redis.controller;

import com.atguigu.redis.entities.Product;
import com.atguigu.redis.util.Constants;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @auther zzyy
 * @create 2021-05-09 15:58
 */
@RestController
@Slf4j
@Api(description = "聚划算商品列表接口AB")
public class JHSABProductController
{
    @Autowired
    private RedisTemplate redisTemplate;

    @RequestMapping(value = "/pruduct/findab",method = RequestMethod.GET)
    @ApiOperation("按照分页和每页显示容量,点击查看AB")
    public List<Product> findAB(int page, int size) {
        List<Product> list=null;
        long start = (page - 1) * size;
        long end = start + size - 1;
        try {
            //采用redis list数据结构的lrange命令实现分页查询
            list = this.redisTemplate.opsForList().range(Constants.JHS_KEY_A, start, end);
            if (CollectionUtils.isEmpty(list)) {
                log.info("=========A缓存已经失效了,记得人工修补,B缓存自动延续5天");
                //用户先查询缓存A(上面的代码),如果缓存A查询不到(例如,更新缓存的时候删除了),再查询缓存B
                this.redisTemplate.opsForList().range(Constants.JHS_KEY_B, start, end);
            }
            log.info("查询结果:{}", list);
        } catch (Exception ex) {
            //这里的异常,一般是redis瘫痪 ,或 redis网络timeout
            log.error("exception:", ex);
            //TODO 走DB查询
        }
        return list;
    }

}

总结

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Gouraud Shading(高洛德着色法)和其优缺点详解

​ Gouraud是一种插值方法&#xff0c;Gouraud着色法是计算机图形学中的一种插值方法&#xff0c;可以为多边形网格表面生成连续的明暗变化。实际使用时&#xff0c;通常先计算三角形每个顶点的光照&#xff0c;再通过双线性插值计算三角形区域中其它像素的颜色。 在图形处理器…

Benewake(北醒) 快速实现TFLuna-IIC与电脑通信的操作说明

目录 1. 概述2. 测试准备2.1 工具准备 3. IIC通讯测试3.1 引脚说明3.2 测试步骤3.2.1 TFLuna-IIC 与 PC 建立连接3.2.2 获取测距值3.2.3 更改 slave 地址 1. 概述 通过本文档的概述&#xff0c;能够让初次使用测试者快速了解测试 IIC 通信协议需要的工具以及查看哪些对应的 II…

小程序容器助力构建新型超级App软件应用架构

所谓软件架构&#xff0c;就是软件系统的骨骼与框架。近年来&#xff0c;软件及开源技术迅猛发展&#xff0c;软件应用架构的概念也愈加普遍。它提供了一种组织和设计软件系统的有效方法&#xff0c;具有许多优势和好处&#xff1a; 模块化和可维护性&#xff1a;软件应用架构将…

Spring Boot 集成Kafka简单应用

说明&#xff1a;当前kafka的版本为2.13-2.8.1&#xff0c;Spring Boot的版本为2.7.6。 第一步&#xff1a;在pom.xml中引入下述依赖 <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId><ver…

Android之解决RecyclerView与NestedScrollView的滑动冲突方法

1、解决RecyclerView与NestedScrollView的滑动冲突 问题一&#xff1a;当我们滑动RecyclerView组件时&#xff0c;上方的轮播图并没有进行滑动&#xff08;NestedScrollView没有滑动&#xff0c;即滑动事件被RecyclerView消费了&#xff09;&#xff0c;当RecyclerView滑到底时…

Nginx的搭建和优化

目录 一. Nginx简介1.1 概述1.2 Nginx和Apache优缺点比较 二. Nginx编译安装步骤1 关闭防火墙&#xff0c;安装依赖包2. 创建运行用户和组3. 编译安装 Nginx4. 做软连接并启动nginx5. 停止Nginx6. 添加nginx系统服务方法一&#xff1a;编写脚本方法二 将nginx命令加入服务 7. 查…

高完整性系统工程(四):Formal Verification and Validation

目录 1. Specification Process 1.1 State Invariants 1.2 Exceptional Behaviour 1.3 Framing 1.4 Summary 2. V&V FOR SPECS 2.1 V&V for formal specs 2.2 Proof 2.3 Proof Assistants 2.4 Model Checking 1. Specification Process Specification Proces…

1128 N Queens Puzzle(21行代码)

分数 20 全屏浏览题目 切换布局 作者 CHEN, Yue 单位 浙江大学 The "eight queens puzzle" is the problem of placing eight chess queens on an 88 chessboard so that no two queens threaten each other. Thus, a solution requires that no two queens sha…

QTranslator Class

QTranslator Class QTranslator 类公共成员函数类说明查找翻译使用多种翻译成员函数使用说明 QTranslator 类 QTranslator类为文本输出提供国际化支持。多国语言 Header: #include <QTranslator> qmake: QT core Inherits: QObject公共成员函数 构造函数QTranslator(…

代码随想录算法训练营15期 Day 7 | 454.四数相加II 、 383. 赎金信 、15. 三数之和 、18. 四数之和

昨天看了一下别的东西&#xff0c;导致昨天没有练习打卡&#xff0c;今天补上昨天的学习知识。 454.四数相加II 建议&#xff1a;本题是 使用map 巧妙解决的问题&#xff0c;好好体会一下 哈希法 如何提高程序执行效率&#xff0c;降低时间复杂度&#xff0c;当然使用哈希法 会…

AURIX TC3XX Cached PFLASH与Non-Cached PFLASH的区别

Cached ? Non-Cached&#xff1f; 在阅读TC3XX的用户手册时&#xff0c;在内存映射表中&#xff0c;有两个segment都是Program Flash&#xff0c;而且大小都一样是3M&#xff0c;一个是segment 8 另一个是segment10 这难免让人产生疑惑&#xff0c;二者区别在哪&#xff1f; …

高程实验 二分算法

学校的ppt把相等也考虑到大于上面去了&#xff0c;所以是错误的 1. (程序题) 有n(1<n<1000005)个整数&#xff0c;已经按照从小到大顺序排列好&#xff0c;现在另外给一个整数x&#xff0c;请找出序列中第1个大于x的数的下标&#xff01; 输入&#xff1a; 输入数据包含多…

4. 垃圾收集器ParNewCMS底层三色标记算法详解

JVM性能调优 1. 垃圾收集算法1.1 分代收集理论1.2 标记-复制算法1.3 标记-清除算法1.4 标记-整理算法 2. 垃圾收集器2.1 Serial收集器(-XX:UseSerialGC -XX:UseSerialOldGC)2.2 Parallel Scavenge收集器(-XX:UseParallelGC(年轻代)&#xff0c;-XX:UseParallelOldGC(老年代))2.…

浅谈MySQL主键

常用主键 常用主键 1&#xff09;自增 int、bigint等&#xff0c;顺序递增。 2&#xff09;雪花 雪花算法是因为有时间参数&#xff0c;所以是有序地&#xff0c;而且都是由数字组成。雪花id最大为64位,符合java中long的长度64位&#xff0c;适用于大规模分布式场景。 3&#…

docker基础操作与进阶 - 搭建基于pm2的node环境

1、为什么要使用docker 最近遇到一台机器需要部署两个不同版本node的情况&#xff0c;首先就想起了docker&#xff0c;想必还有其他类似环境问题的情况&#xff0c;需要进行项目隔离&#xff0c;而docker正是用来解决这个问题的。 docker的优势就在于环境隔离&#xff0c;相当…

第九篇、基于Arduino uno,用LCD1602(带IIC的)显示屏显示字符——结果导向

0、结果 说明&#xff1a;可以在LCD1602屏幕上面显示字符&#xff0c;实时的变量&#xff0c;也可以设置是否背光&#xff0c;如果是你想要的&#xff0c;可以接着往下看。 1、外观 说明&#xff1a;注意是带IIC通讯的LCD屏幕&#xff0c;外形如下。 2、连线 说明&#xff…

Hexo写文章不方便?用上GitHub Actions真的是泰裤辣

对于做个人博客的小伙伴来说 HEXO 大家肯定都是非常熟悉的吧,这是一个静态的个人博客程序,通过 HEXO + GitHub Pages 搭建免费个人博客也是很多博主的选择。但相信肯定也会有些困恼,比如博客的渲染维护太麻烦了,我要在一台新设备上写博客并推送到 GitHub Pages 还要先安装 …

【Redis】聊一下哨兵集群

上一篇中&#xff0c;介绍了哨兵机制可以减少主库实例下线的误判率&#xff0c;但是如果只有一个哨兵实例&#xff0c;出现宕机后没有办法保证服务的高可用&#xff0c;所以一般实际的生产环境都是搭建3个哨兵实例构建的集群进行运行。但是具体的运行机制是什么。其实主要就是三…

使用langchain及llama_index实现基于文档(长文本)的相似查询与询问

文章目录 1. 引言2. 简介3. 带关键字的查询方案4. 不带关键字的总结询问5. 实现代码 1. 引言 在调用ChatGPT接口时&#xff0c;我们常常受到4096个字符&#xff08;token&#xff09;的限制。这种限制对于处理长文本或者需要对文档进行相似查询和询问的场景来说是一个挑战。然…

如何复制投票链接投票怎样链接到公众号投票链接如何生成

关于微信投票&#xff0c;我们现在用的最多的就是小程序投票&#xff0c;今天的网络投票&#xff0c;在这里会教大家如何用“活动星投票”小程序来进行投票。 我们现在要以“妙趣拾光”为主题进行一次投票活动&#xff0c;我们可以在在微信小程序搜索&#xff0c;“活动星投票”…