Redis相关知识汇总(四)单实例场景下的应用

第一章说了, redis这类db的出现, 是为了解决访问数据库过慢的问题
数据库慢就是两种情况:1. 读慢, 2. 写慢

在这里插入图片描述
上图是最基本的redis读数据流程
但是这时候会出现一个问题, 设置缓存数据以后, val如果不删除, client会一直会读取缓存, 所以这时候会加入一个set timeout的操作
在这里插入图片描述
这样做表面上解决了大部分情况的读取速度的情况, 但是又有3种并发情况:

  1. 击穿: 当ttl过期的时候,同一时间,有一个超大的并发向数据库进行请求。

为了解决这个问题, 引入了 set nx(相当于排他锁) 和 sleep, 像下面这样子
在这里插入图片描述
这个方案还是存在两个问题

  1. 【client2】sleep 究竟多久合适?时间长了,请求处理不及时。
  2. 【client1】del look 之前 因为某些不可抗力出现问题了。导致【client2】出现死锁。

解决方案:

  1. 根据实际 select 时间,来规划 sleep 时间
  2. 增加 look的ttl 来防止死锁, 并增加线程,来延长ttl时间。 如下图:
    在这里插入图片描述
  1. 雪崩:大量的key缓存出现过期, 导致大量请求跑到数据库了(击穿的加强版)

这里要分两种情况:

  1. 缓存数据跟时间没有关系。【解决方案就是 随机ttl, 让缓存时间均匀分布】
  2. 缓存时间跟时间有关系,大量缓存再某一时间需要更新。 比如: 每个月都会更新一次信用卡账单,这时候上个月的数据就需要丢弃

解决方案也分两种:

  1. 再已知数据的情况下,可以使用预加载, 提前缓存好数据【比如 查询 上个月的信用卡账单,这个月2号才能查, 1号用来计算和缓存数据 】
  2. 在未知数据情况下,【 还是查账单, 上个月账单, 这个月1号0点开始就能查, 然后有大量请求出现】这种情况下必须采用 击穿的方案, 并在客户端进行优化, 过滤一部分客户端, 先等待或者返回等待提示。
  1. 穿透:查询db中不存在的值。

解决方案分两个步骤:

  1. 如果遇到不存在的值, 设置一个特殊标记作为缓存的值, 表示不存在, 不重复查数据库
  2. 采用过滤器来减少出发。 常见的有 Bloom Filter 布隆过滤器Counting Bloom Filter布谷鸟过滤器【留坑】
    在这里插入图片描述
    第一步通过 过滤器 查询key, 返回true,则执行第三步获取key的值。第五步查询key2 返回false直接结束, 不再执行获取第三步的操作。
    过滤器的判断是通过客户端设置的,一般再插入数据库的时候, 就需要设置过滤器了。这里有一个双写的坑存在,但是我觉得是完全可以接受的,毕竟这个是通过概率来过滤请求的,数据之间还有碰撞存在【即使过滤器返回true, 数据库中也不一定存在】(如果担心设置的时候出问题, 可以订阅binglog日志, 通过数据库的同步, 来更新)

写的方法有以下几种

  1. 正常的命令调用 【最常用的】
  2. pipe 管道式调用

cat data.txt | redis-cli --pipe【这个用的非常少,一般用于冷启动】

  1. 队列[list],集合[set/sorted set],发布订阅[pub/sub] 【异步】

发布订阅是有一个坑的, 以下是场景模拟

  1. A 再A1这个频道发布了一个“aaa”这个消息,这时候并没有任何订阅者
  2. B 这时候订阅了A1这个频道。“aaa”这个消息 B是收不到的
  3. B 一段时间后挂了, 挂了到修复这段时间的消息, B也是收不到的, 所以会丢数据
  1. 事务【数据一致性,但并不完整】

redis的事务分两种情况

  1. multi是先把命令丢到一个队列里面, 在exec执行的时候, 在把队列里的命令丢进去
    在这里插入图片描述
  2. 带上watch之后, 一旦aaa的值发生改变, exec直接失败, 后续客户端自己处理错误逻辑
    在这里插入图片描述

回收策略

  1. noeviction 返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令
  2. allkeys-lru 淘汰最后访问时间最久的元素(很久没访问的数据),使得新添加的数据有空间存放
  3. volatile-lru 淘汰最后访问时间最久的元素,但仅限于在过期集合的键,使得新添加的数据有空间存放
  4. allkeys-random 回收随机的键使得新添加的数据有空间存放
  5. volatile-random 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键
  6. volatile-ttl 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放
  7. volatile-lfu 淘汰最近访问频率最小的元素(访问次数最少的数据),使得新添加的数据有空间存放
  8. allkeys-lfu 淘汰最近访问频率最小的元素,但仅限于在过期集合的键,使得新添加的数据有空间存放

LFU 缺点:

  1. 最新加入的数据常常会被踢除,因为其起始方法次数少。
  2. 如果频率时间度量是1小时,则平均一天每个小时内的访问频率1000的热点数据可能会被2个小时的一段时间内的访问频率是1001的数据剔除掉
    LRU 缺点:
  3. 可能会由于一次冷数据的批量查询而误导大量热点的数据。

redis 过期原理:

  1. 【被动】 在访问的时候,把过期的key删除
  2. 【主动】 周期轮询采样key(增量),在牺牲一定的内存下,保证性能
    在这里插入图片描述

持久化

一般存储层, 有两种方式做持久层

  1. 快照(RDB)

在这里插入图片描述
快照的方式有两种:

  1. 阻塞【save】

阻塞的情况下, redis 不能对外提供服务, 这种情况下一般场景是不可以接受的, 主要应用于维护

  1. 非阻塞【bgsave】

非阻塞的首先要解决一个问题:8点的时候开始备份, 备份时间需要半小时, 但是这半小时之间数据会发生变化,但是备份的数据要是8点这个时间的数据, 不允许八点以后数据的变化影响到备份的数据
这里的解决方案是 copy-on-write(写入时复制)
原理如下:
在这里插入图片描述
如果主进程修改数据,则新建内存,指向新的地址
在这里插入图片描述
触发条件
配置文件中
在这里插入图片描述

  1. 缺点
  1. 不支持拉链, 只有一个 dump.rdb 文件
  2. 丢失数据比较多
  1. 日志(AOF)

相当于 binglog, 恢复的时候会触发io操作
在这里插入图片描述
触发条件
在这里插入图片描述
优点:就是每一个操作都会记录下,丢数据就比rdb好很多
缺点:由于运行非常久以后, AOF日志会变得非常庞大。
针对上述缺点,redis 有两种解决方案

  1. 在 4.0 以前,合并一些命令,日志结构没有变化,但随着时间越来越久,日志文件还是越来越大
  2. 在 4.0 以后,采用 RDB + AOF的方式来保存这个日志文件, 也就是下面所说的第三点。
    上述方案可通过 BGREWRITEAOF 来执行
    在这里插入图片描述
  1. RDB + AOF

镜像 + AOF日志 混合。将老的命令合并成RDB格式到AOF文件, 然后以增量的方式以存放AOF格式的命令到AOF文件
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值