Redis(十五)Bitmap、Hyperloglog、GEO案例、布隆过滤器

文章目录

  • 面试题
  • 常见统计类型
    • 聚合统计
    • 排序统计
    • 二值统计
    • 基数统计
  • Hyperloglog
    • 专有名词
      • UV(Unique Visitor)独立访客
      • PV(Page View)页面浏览量
      • DAU(Daily Active User)日活跃用户量
      • MAU(Monthly Active User)
    • 需求
    • 原理
    • 亿级UV的Redis统计方案
  • GEO
    • 面试题
    • 命令
      • GEOADD
      • 获取某位置的经纬度GEOPOS
      • 返回坐标的Geohash表示GEOHASH
      • 两个位置之间距离GEODIST
      • 半径范围内的坐标GEORADIUS
      • 半径范围内坐标中心点是给定元素GEORADIUSBYMEMBER
  • Bitmap
    • 面试题
    • 作用场景
  • 布隆过滤器BloomFilter
    • 需求
    • 概述
    • 作用
    • 原理
      • 概述原理
      • 添加、查询元素过程
      • 使用步骤
      • 使用场景
    • 手写布隆过滤器案例
      • 优缺点
      • 布谷鸟过滤器:解决布隆过滤器不能删除缺点

面试题

  1. 抖音电商直播,主播介绍的商品有评论,1个商品对应了1系列的评论,排序+展现+取前10条记录
  2. 用户在手机App上的签到打卡信息:1天对应1系列用户的签到记录,新浪微博、钉钉打卡签到,来没来如何统计?
  3. 应用网站上的网页访问信息:1个网页对应1系列的访问点击,淘宝网首页,每天有多少人浏览首页?
  4. 你们公司系统上线后,说一下UV、PV、DAU分别是多少?

记录对集合中的数据进行统计

  1. 在移动应用中,需要统计每天的新增用户数和第2天的留存用户数;
  2. 在电商网站的商品评论中,需要统计评论列表中的最新评论;
  3. 在签到打卡中,需要统计一个月内连续打卡的用户数;
  4. 在网页访问记录中,需要统计独立访客(Unique Visitor,UV)量。

需求
亿级数据的收集+清洗+统计+展现

常见统计类型

亿级系统常见统计方式

聚合统计

统计多个集合元素的聚合结果,就是前面讲解过的交差并等集合统计
在这里插入图片描述
交并差集和聚合函数的应用

排序统计

  • 抖音短视频最新评论留言的场景,请你设计一个展现列表。

在面对需要展示最新列表、排行榜等场景时,如果数据更新频繁或者需要分页显示,建议使用ZSet

二值统计

集合元素的取值就只有0和1两种
在钉钉上班签到打卡的场景中,我们只用记录有签到(1)或没签到(0)
bitmap

基数统计

指统计一个集合中不重复的元素个数
见hyperloglog

Hyperloglog

去重统计估计算法

专有名词

UV(Unique Visitor)独立访客

需要去重考虑

PV(Page View)页面浏览量

不用去重

DAU(Daily Active User)日活跃用户量

登录或者使用了某个产品的用户数(去重复登录的用户)
常用于反映网站、互联网应用或者网络游戏的运营情况

MAU(Monthly Active User)

月活跃用户量

需求

  1. 很多计数类场景,比如 每日注册 IP 数、每日访问 IP 数、页面实时访问数 PV、访问用户数 UV等。
  2. 因为主要的目标高效、巨量地进行计数,所以对存储的数据的内容并不太关心。
  3. 也就是说它只能用于统计巨量数量,不太涉及具体的统计对象的内容和精准性。
  4. 统计单日一个页面的访问量(PV),单次访问就算一次。
  5. 统计单日一个页面的用户访问量(UV),即按照用户为维度计算,单个用户一天内多次访问也只算一次。
  6. 多个key的合并统计,某个门户网站的所有模块的PV聚合统计就是整个网站的总PV。

问题
如果数据显较大亿级统计,使用bitmaps同样会有问题。

bitmap是通过用位bit数组来表示各元素是否出现,每个元素对应一位,所需的总内存为N个bit。

基数计数则将每一个元素对应到bit数组中的其中一位,比如bit数组010010101(按照从零开始下标,有的就是1、4、6、8)。

新进入的元素只需要将已经有的bit数组和新加入的元素进行按位或计算就行。这个方式能大大减少内存占用且位操作迅速。

但是,假设一个样本案例就是一亿个基数位值数据,一个样本就是一亿
如果要统计1亿个数据的基数位值,大约需要内存100000000/8/1024/1024约等于12M,内存减少占用的效果显著。

这样得到统计一个对象样本的基数值需要12M。
如果统计10000个对象样本(1w个亿级),就需要117.1875G将近120G,可见使用bitmaps还是不适用大数据量下(亿级)的基数计数场景,

但是bitmaps方法是精确计算的。

原理

概率算法
通过牺牲准确率来换取空间,对于不要求绝对准确率的场景下可以使用,因为概率算法不直接存储数据本身。
通过一定的概率统计方法预估基数值,同时保证误差在一定范围内,由于又不储存数据故此可以大大节约内存。
HyperLogLog就是一种概率算法的实现。

只是进行不重复的基数统计,不是集合也不保存数据,只记录数量而不是具体内容。
Hyperloglog提供不精确的去重计数方案
牺牲准确率来换取空间,误差仅仅只是0.81%左右
http://antirez.com/news/75

亿级UV的Redis统计方案

UV的统计需要去重,一个用户一天内的多次访问只能算作一次
淘宝、天猫首页的UV,平均每天是1~1.5个亿左右
每天存1.5个亿的IP,访问者来了后先去查是否存在,不存在加入

// 用于产生模拟后台访问数据
@Service
@Slf4j
public class HyperLogLogService
{
    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 模拟后台有用户点击首页,每个用户来自不同ip地址
     */
    @PostConstruct
    public void init()
    {
        log.info("------模拟后台有用户点击首页,每个用户来自不同ip地址");
        new Thread(() -> {
            String ip = null;
            for (int i = 1; i <=200; i++) {
                Random r = new Random();
                ip = r.nextInt(256) + "." + r.nextInt(256) + "." + r.nextInt(256) + "." + r.nextInt(256);

                Long hll = redisTemplate.opsForHyperLogLog().add("hll", ip);
                log.info("ip={},该ip地址访问首页的次数={}",ip,hll);
                //暂停几秒钟线程
                try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            }
        },"t1").start();
    }

}
@Api(description = "淘宝亿级UV的Redis统计方案")
@RestController
@Slf4j
public class HyperLogLogController
{
    @Resource
    private RedisTemplate redisTemplate;

    @ApiOperation("获得IP去重后的首页访问量")
    @RequestMapping(value = "/uv",method = RequestMethod.GET)
    public long uv()
    {
        //pfcount
        return redisTemplate.opsForHyperLogLog().size("hll");
    }

}

GEO

是zset

面试题

外卖软件中附近的美食店铺、打车软件附近的车辆等等。那这种附近各种形形色色的XXX地址位置选择

  1. 查询性能问题,如果并发高,数据量大这种查询是要搞垮mysql数据库的
  2. 一般mysql查询的是一个平面矩形访问,而叫车服务要以我为中心N公里为半径的圆形覆盖。
  3. 精准度的问题,我们知道地球不是平面坐标系,而是一个圆球,这种矩形计算在长距离计算时会有很大误差,mysql不合适

命令

GEOADD

GEOADD city 116.403963 39.915119 "天安门" 116.403414 39.924091 "故宫" 116.024067 40.362639 "长城"

在这里插入图片描述

获取某位置的经纬度GEOPOS

GEOPOS city 天安门 故宫

在这里插入图片描述

返回坐标的Geohash表示GEOHASH

GEOHASH city 天安门 故宫 长城

在这里插入图片描述

两个位置之间距离GEODIST

GEODIST city 天安门 长城 km

m 米
km 千米
ft 英尺
mi 英里
在这里插入图片描述

半径范围内的坐标GEORADIUS

GEORADIUS city 116.418017 39.914402 10 km withdist withcoord count 10 withhash desc
  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
  • WITHCOORD: 将位置元素的经度和维度也一并返回。
  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大
  • COUNT 限定返回的记录数。

半径范围内坐标中心点是给定元素GEORADIUSBYMEMBER

GEORADIUSBYMEMBER city 天安门 km withdist withcoord count 10 withhash desc

在这里插入图片描述

Bitmap

面试题

  1. 日活统计
  2. 连续签到打卡
  3. 最近一周的活跃用户
  4. 统计指定用户一年之中的登陆天数
  5. 某用户哪几天登陆过,哪几天没有登陆,全年中登录的天数共计多少

作用场景

  1. 用户是否登陆过Y、N,比如京东每日签到送京豆
  2. 电影、广告是否被点击播放过
  3. 钉钉打卡上下班,签到统计

布隆过滤器BloomFilter

需求

  1. 现有50亿个电话号码,现有10万个电话号码,如何要快速准确的判断这些电话号码是否已经存在?
  2. 安全连接网址,全球数10亿的网址判断
  3. 黑名单校验,识别垃圾邮件
  4. 白名单校验,识别出合法用户进行后续处理

概述

由一个初值都为零的bit数组和多个哈希函数构成,1用来快速判断集合中是否存在某个元素
本质就是判断具体数据是否存在于一个大的集合中

布隆过滤器是一种类似set的数据结构,国只是统计结果在巨量数据下有点小瑕疵,不够完美

作用

高效地插入和查询,占用空间少,返回的结果是不确定性+不够完美。

重点

  1. 一个元素如果判断结果:存在时,元素不一定存在但是判断结果为不存在时,则一定不存在
  2. 布隆过滤器可以添加元素,但是不能删除元素由于涉及hashcode判断依据,删掉元素会导致误判率增加。

原理

概述原理

布隆过滤器是专门用来解决去重问题的高级数据结构

实质就是一个大型位数组和几个不同的无偏hash函数(无偏表示分布均匀)。由一个初值都为零的bit数组和多个个哈希函数构成,用来快速判断某个数据是否存在。但是跟 HyperLogLog 一样,它也一样有那么一点点不精确,也存在一定的误判概率

添加、查询元素过程

  • 添加key时
    使用多个hash函数对key进行hash运算得到一个整数索引值,对位数组长度进行取模运算得到一个位置,每个hash函数都会得到一个不同的位置,将这几个位置都置1就完成了add操作。

  • 查询key时
    只要有其中一位是零就表示这个key不存在,但如果都是1,则不一定存在对应的key。

结论:有,是可能有 无,是肯定无

举例
当有变量被加入集合时,通过N个映射函数将这个变量映射成位图中的N个点,把它们置为 1(假定有两个变量都通过 3 个映射函数)。
在这里插入图片描述
如果这些点,有任何一个为零则被查询变量一定不在,如果都是 1,则被查询变量很可能存在

  • 为什么说是可能存在,而不是一定存在呢?那是因为映射函数本身就是散列函数,散列函数是会有碰撞的。(见上图3号坑两个对象都1)

缓存穿透解决方案:
正是基于布隆过滤器的快速检测特性,我们可以在把数据写入数据库时,使用布隆过滤器做个标记。当缓缺失后,应用查询数据库时,可以通过查询布降过滤器快速判断数据是否存在。如果不存在,就不用再去据库中查询了。这样一来,即使发生缓存穿透了,大量请求只会查询Redis和布隆过滤器,而不会积压到据库,也就不会影响数据库的正常运行。布降过滤器可以使用Redis实现,本身就能承担较大的并发访问力。

Hash冲突:https://segmentfault.com/a/1190000022553292

使用步骤

  1. 初始化Bitmap
    布隆过滤器 本质上 是由长度为 m 的位向量或位列表(仅包含 0 或 1 位值的列表)组成,最初所有的值均设置为 0
    在这里插入图片描述
  2. 添加对应占位

当我们向布隆过滤器中添加数据时,为了尽量地址不冲突,会使用多个 hash 函数对 key 进行运算,算得一个下标索引值,然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就完成了 add 操作。

例如:我们添加一个字符串wmyskxz,对字符串进行多次hash(key) → 取模运行→ 得到坑位
在这里插入图片描述

  1. 判断是否存在
    向布隆过滤器查询某个key是否存在时,先把这个 key 通过相同的多个 hash 函数进行运算,查看对应的位置是否都为 1,
    只要有一个位为零,那么说明布隆过滤器中这个 key 不存在;
    如果这几个位置全都是 1,那么说明极有可能存在;
    因为这些位置的 1 可能是因为其他的 key 存在导致的

例如:在 add 了字符串wmyskxz数据之后,很明显下面1/3/5 这几个位置的 1 是因为第一次添加的 wmyskxz 而导致的;此时我们查询一个没添加过的不存在的字符串inexistent-key,它有可能计算后坑位也是1/3/5
在这里插入图片描述

使用场景

  1. 解决缓存穿透问题:redis结合Bitmap使用

把已存在数据的key存在布隆过滤器中,相当于redis前面挡着一个布隆过滤器。

当有新的请求时,先到布隆过滤器中查询是否存在:
如果布隆过滤器中不存在该条数据则直接返回;
如果布隆过滤器中已存在,才去查询缓存redis,如果redis里没查询到则再查询Mysql数据库
在这里插入图片描述

  1. 黑名单校验
  2. 安全连接网址,亿级数量判断

手写布隆过滤器案例

在这里插入图片描述
初始化白名单用户到布隆过滤器

@PostConstruct
public void init()
 {
     //白名单客户预加载到布隆过滤器
     String uid = "customer:12";
     //1 计算hashcode,由于可能有负数,直接取绝对值
     int hashValue = Math.abs(uid.hashCode());
     //2 通过hashValue和2的32次方取余后,获得对应的下标坑位
     long index = (long) (hashValue % Math.pow(2, 32));
     log.info(uid+" 对应------坑位index:{}",index);
     //3 设置redis里面bitmap对应坑位,该有值设置为1
     redisTemplate.opsForValue().setBit("whitelistCustomer",index,true);
 }

布隆过滤器检查

@Component
@Slf4j
public class CheckUtils
{
    @Resource
    private RedisTemplate redisTemplate;

    public boolean checkWithBloomFilter(String checkItem,String key)
    {
        int hashValue = Math.abs(key.hashCode());
        long index = (long) (hashValue % Math.pow(2, 32));
        boolean existOK = redisTemplate.opsForValue().getBit(checkItem, index);
        log.info("----->key:"+key+"\t对应坑位index:"+index+"\t是否存在:"+existOK);
        return existOK;
    }
}

Controller

@RestController
@Slf4j
public class CustomerController
{
    @Resource private CustomerSerivce customerSerivce;

    @ApiOperation("数据库初始化2条Customer数据")
    @RequestMapping(value = "/customer/add", method = RequestMethod.POST)
    public void addCustomer() {
        for (int i = 0; i < 2; i++) {
            Customer customer = new Customer();

            customer.setCname("customer"+i);
            customer.setAge(new Random().nextInt(30)+1);
            customer.setPhone("1381111xxxx");
            customer.setSex((byte) new Random().nextInt(2));
            customer.setBirth(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()));

            customerSerivce.addCustomer(customer);
        }
    }

    @ApiOperation("单个用户查询,按customerid查用户信息")
    @RequestMapping(value = "/customer/{id}", method = RequestMethod.GET)
    public Customer findCustomerById(@PathVariable int id) {
        return customerSerivce.findCustomerById(id);
    }

    @ApiOperation("BloomFilter案例讲解")
    @RequestMapping(value = "/customerbloomfilter/{id}", method = RequestMethod.GET)
    public Customer findCustomerByIdWithBloomFilter(@PathVariable int id) throws ExecutionException, InterruptedException
    {
        return customerSerivce.findCustomerByIdWithBloomFilter(id);
    }
}

Service

@Service
@Slf4j
public class CustomerSerivce
{
    public static final String CACHA_KEY_CUSTOMER = "customer:";

    @Resource
    private CustomerMapper customerMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private CheckUtils checkUtils;

    /**
     * 写操作
     * @param customer
     */
    public void addCustomer(Customer customer)
    {
        int i = customerMapper.insertSelective(customer);

        if(i > 0)
        {
            //mysql插入成功,写进redis
            Customer result = customerMapper.selectByPrimaryKey(customer.getId());
            //redis缓存key
            String key = CACHA_KEY_CUSTOMER+customer.getId();
            //写进redis
            redisTemplate.opsForValue().set(key,result);
        }
    }

    public Customer findCustomerById(Integer customreId)
    {
        Customer customer = null;
        //缓存redis的key名称
        String key = CACHA_KEY_CUSTOMER+customreId;
        customer = getCustomer(customreId, key);
        return customer;
    }

    /**
     * 白名单:whitelistCustomer
     */
    public Customer findCustomerByIdWithBloomFilter (Integer customerId)
    {
        Customer customer = null;
        //缓存key的名称
        String key = CACHA_KEY_CUSTOMER + customerId;

        //布隆过滤器check,无是绝对无,有是可能有
        //===============================================
        if(!checkUtils.checkWithBloomFilter("whitelistCustomer",key))
        {
            log.info("白名单无此顾客,不可以访问: "+key);
            return null;
        }
        //===============================================

        //1 查询redis
        customer = getCustomer(customerId, key);
        return customer;
    }

    private Customer getCustomer(Integer customreId, String key) {
        Customer customer;//1 先去redis查询
        customer = (Customer) redisTemplate.opsForValue().get(key);

        //2 redis有直接返回,没有再进去查询mysql
        if (customer == null) {
            // 3 再去查询我们的mysql
            customer = customerMapper.selectByPrimaryKey(customreId);
            // 3.1 mysql有,redis无
            if (customer != null) {
                //3.2 把mysq查询出来的数据回写redis,保持一致性
                redisTemplate.opsForValue().set(key, customer);
            }
        }
        return customer;
    }
}

优缺点

优点
高效地插入和查询,内存占用bit空间少
缺点

  1. 不能删除元素。
  2. 因为删掉元素会导致误判率增加,因为hash冲突同一个位置可能存的东西是多个共有的你删除一个元素的同时可能也把其它的删除了。
  3. 存在误判,不能精准过滤:有,是很可能有;无,是肯定无。

布谷鸟过滤器:解决布隆过滤器不能删除缺点

为了解决布隆过滤器不能删除元素的问题,布谷鸟过滤器横空出世。

论文:
《Cuckoo Filter:Better Than Bloom》

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

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

相关文章

SICTF Round#3 RE WP

1. BabyC ShiftF12 一眼出 2. ez_pyc 好多wp里直接反编译出了源码&#xff0c;md5都能直接看见……我用的一样版本的uncompyle6但是没有这样的效果 这种事情也没法强求&#xff0c;老老实实逆吧 程序是一个数独&#xff0c;我实在没看出来…… 首先看到一个9*9的棋盘&…

springboot网站开发01-如何搭建Maven类型父子嵌套结构项目

springboot网站开发01-如何搭建Maven类型父子嵌套结构项目&#xff01;众所周知&#xff0c;实际上&#xff0c;在真正的公司项目开发中为了让代码实现更多的复用&#xff0c;提升项目的开发效率&#xff0c;节省开发的成本&#xff08;人力成本较高&#xff0c;代码可以尽量复…

Django——ORM增删改查

基本对象 model.objects 创建数据 可以通过django编写的命令行方式快捷创建数据 python manage.py shell 如果对模型层有任何修改都需要重启shell&#xff0c;否则操作容易出错 在shell中我们需要先引入我们的模型&#xff0c;如from bookstore.models import Book 然后通过…

TiDB离线部署、Tiup部署TiDB

先做tidb准备工作&#xff1a; 部署 TiDB 前的环境检查操作&#xff1a;TiDB 环境与系统配置检查 | PingCAP 文档中心 1.查看数据盘 fdisk -l &#xff08;2,3&#xff09;本人的分区已经是 ext4 文件系统不用分区&#xff0c;具体官方文档的分区&#xff1a; 4.查看数据盘…

7.(数据结构)堆

7.1 相关概念 堆&#xff08;Heap&#xff09;在计算机科学中是一种特殊的数据结构&#xff0c;它通常被实现为一个可以看作完全二叉树的数组对象。以下是一些关于堆的基本概念&#xff1a; 数据结构&#xff1a; 堆是一个优先队列的抽象数据类型实现&#xff0c;通过完全二叉树…

Upload-Labs-Linux1【CTF】

拿到这道题目一看&#xff0c;发现是upload靶场&#xff1b;这不简简单单吗&#xff1b;结果中间还是遇到了一些小问题 小坑总结&#xff1a;该关只识别标准php语法&#xff1a;<?php phpinfo()?>格式&#xff1b;即<?php ?> 不识别<? phpinfo()?> &…

LeetCode---385周赛

题目 3042. 统计前后缀下标对 I 3043. 最长公共前缀的长度 3044. 出现频率最高的质数 3045. 统计前后缀下标对 II 一、最长公共前缀的长度 这题可以用字典树来做。 这里简单介绍一下字典树&#xff0c;顾名思义&#xff0c;这是用来存放单词的树&#xff0c;如何存&#x…

ThreeJS 几何体顶点position、法向量normal及uv坐标 | UV映射 - 法向量 - 包围盒

文章目录 几何体的顶点position、法向量normal及uv坐标UV映射UV坐标系UV坐标与顶点坐标设置UV坐标案例1&#xff1a;使用PlaneGeometry创建平面缓存几何体案例2&#xff1a;使用BufferGeometry创建平面缓存几何体 法向量 - 顶点法向量光照计算案例1&#xff1a;不设置顶点法向量…

第2讲:C语言数据类型和变量

第2讲&#xff1a;C语言数据类型和变量 目录1.数据类型介绍1.1字符型1.2整型1.3浮点型1.4 布尔类型1.5 各种数据类型的长度1.5.1 sizeof 操作符1.5.2 数据类型长度1.5.3 sizeof 中表达式不计算 2.signed 和 unsigned3.数据类型的取值范围4. 变量4.1 变量的创建4.2 变量的分类 5…

【前端素材】推荐优质后台管理系统Upcube平台模板(附源码)

一、需求分析 后台管理系统在多个层次上提供了丰富的功能和细致的管理手段&#xff0c;帮助管理员轻松管理和控制系统的各个方面。其灵活性和可扩展性使得后台管理系统成为各种网站、应用程序和系统不可或缺的管理工具。 当我们从多个层次来详细分析后台管理系统时&#xff0…

Conmi的正确答案——将JAVA中maven的.m2文件夹放到D盘

系统&#xff1a;WIN11 1、将.m2文件夹移动到D盘 移动后&#xff1a; 2、创建目录链接 mklink /j "C:\Users\Administrator\.m2" "D:\.m2"至此&#xff0c;maven默认的jar包会加载到D盘的.m2文件夹

C语言:数组的地址和数组首元素的地址的区别

数组的地址和数组首元素的地址在编译器上可能输出相同的地址 int main() {int arr[] { 1 };printf("%p\n", &arr);printf("%p\n", arr);return 0; }C和C等语言中&#xff0c;数组是一种复合数据类型&#xff0c;可以存储相同类型的多个元素。当我们谈…

重大更新:GPT-4 API 现全面向公众开放!

重大更新&#xff1a;GPT-4 API 现全面向公众开放&#xff01; 在 AIGC&#xff08;人工智能生成内容&#xff09;领域内&#xff0c;我们一直致力于跟踪和分析如 OpenAI、百度文心一言等大型语言模型&#xff08;LLM&#xff09;的进展及其在实际应用中的落地情况。我们还专注…

类型转换(C++)

一、C语言中的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返回值类型与 接收返回值类型不一致时&#xff0c;就需要发生类型转化&#xff0c;C语言中总共有两种形式的类型转换&#xff1a;隐式类型 …

Redis篇之缓存雪崩、击穿、穿透详解

学习材料&#xff1a;https://xiaolincoding.com/redis/cluster/cache_problem.html 缓存雪崩 什么是缓存雪崩 在面对业务量较大的查询场景时&#xff0c;会把数据库中的数据缓存至redis中&#xff0c;避免大量的读写请求同时访问mysql客户端导致系统崩溃。这种情况下&#x…

vite+ts+vue3项目配置

如何生成用户代码片段&#xff08;快捷生成代码&#xff09; 点击用户代码片段 新建全局代码片段&#xff0c;然后起个名字 {"vue": {"prefix": "vue","body": ["<template>"," <div class\"contai…

汽车大灯尾灯破裂修复用什么胶?

汽车大灯尾灯破裂可以使用硅酮玻璃胶或者环氧树脂胶进行修复。 硅酮玻璃胶的优点主要包括&#xff1a; 粘接力强&#xff1a;硅酮玻璃胶具有很强的粘接力&#xff0c;可以有效地将裂缝两侧的材料紧密粘合在一起。拉伸强度大&#xff1a;硅酮玻璃胶固化后形成的固体具有较高的…

2023最新盲盒交友脱单系统源码

源码获取方式 搜一搜&#xff1a;万能工具箱合集 点击资源库直接进去获取源码即可 如果没看到就是待更新&#xff0c;会陆续更新上 或 源码软件库 最新盲盒交友脱单系统源码&#xff0c;纸条广场&#xff0c;单独抽取/连抽/同城抽取/高质量盒子 新增功能包括心动推荐&#xff…

【深入理解设计模式】原型设计模式

原型设计模式 原型设计模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;它允许通过复制已有对象来创建新对象&#xff0c;而无需直接依赖它们的具体类。这种模式通常用于需要频繁创建相似对象的场景&#xff0c;以避免昂贵的创建操作或初始化过…

QT-串口工具

一、演示效果 二、关键程序 &#xff1a; #include "mainwindow.h" #include "ui_mainwindow.h"#include <QMessageBox>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow),listPlugins(QList<TabPluginInt…