redis淘汰+过期双向保证高可用 | redis 为什么那么快?
前言
redis
和数据相比除了他们的结构型颠覆以外!还有他们存储位置也是不相同。传统数据库将数据存储在硬盘上每次数据操作都需要IO
而Redis
是将数据存储在内存上的。这里稍微解释下IO是啥意思。IO就是输入流输出流方式将数据在硬盘和内存之间进行交互!而redis
直接在内存上就剩下了IO
操作。这也是redis
快的原因之一吧
- 内存相对于硬盘来说很宝贵。我们平时的电脑也是硬盘是内存的几百倍。既然内存很宝贵而
redis
又将数据存储在内存上那么redis
肯定不能肆无忌惮的进行存储 。这就需要redis
和开发者们作出相应的优化 - 首先
redis
在配置文件(redis.conf
)中通过maxmemory
参数指定redis
设置整个对内存的支配大小! - 其次就是要求我们开发者在想
redis
中填值的时候根据自己的需求设置相应的key过期时间。这样不必要的数据就会被redis
过期驱逐策略清楚。从而节省内存供别人使用
本文凌驾于redis
基础之上,这里笔者默认大家都已经安装了redis
. 并实际使用过redis
内存分配
maxmemory
指定大小。在redis.conf
配置文件中可以直接指定。他的单位时byte。
- 上图中注释部分是给大家的解释,实际中#配置需要换行哈!!!友情提示
- 另外我们可以连接上
redis
通过config
命令来设置
- 两种方式都可以设置,前者是全局设置重启之后仍然有效!后者是临时设置重启之后就会重新加载
redis.conf
中的配置。
键过期
- 上面我们从
redis
本身角度出发设置了内存限制,这样不用担心他们吞噬系统内存!下面就需要我们开发者设计角度约束自己了。
设置过期时间
expire key time
设置过期时间默认单位时S 。
然后通过ttl 命令可以查看剩余过期时间
- 经过多次执行
ttl
能够观察到剩余时间在不断的减少!当减少到0的时候就被给驱逐策略驱逐!注意这里说的是驱逐策略驱逐并不是意味着立马被删除
更新过期时间
del key
直接将key删除了那么该key对应的过期自然也就不存在了!这种情况笔者也算作是更新过期时间set
getset
等命令重新设置key、value方式会覆盖过期时间 , 直接被覆盖成-1
set
、getset
包括del
严格意义是覆盖过期时间。真正做到更新过期时间的还是expire .在expire是已最新为准的!- 上面其实都修改了key才会应发原本的过期时间失效的!因为此key非彼key 。 但是
append
、incr
等命令是改变值这种命令是不会影响到原来的过期设置的
淘汰策略
- 根据上面配置我们可以将我们的
redis
最大内存设置为1MB
, 设置大小随便最好能小点。然后我们通过Java
小程序不断向redis
中填充。最终当内存不够使用时就会报错
- 报错就是因为内存满了,新增的key被
redis
拒绝了!不仅仅是新增的被拒绝,就算此时我们想改变已经在redis
中的key的值也是不可用的
public static void main(String[] args) {
Jedis jedis = new Jedis("39.102.60.114", 6379);
jedis.auth("Qq025025");
Integer index = 1;
while (true) {
String uuid = UUID.randomUUID().toString();
jedis.set(index.toString(), uuid);
System.out.println(index++);
}
}
不管是append 还是set 都是报
OOM command not allowed when used memory > maxmemory
。代码中打印和redis
键个数一致;说明我们默认的淘汰策略是直接拒绝总结下来就是:当
redis
内存被使用满了后,任何的写操作都会被拒绝!当没有足够内存时难道就这么直接拒绝吗?上面也提到了需要我们程序员自己根据需求设置键过期已释放内存供其他有需要的key使用!那么设置了过期key之后这些key又是怎么被清除的呢? 这就牵扯出我们的淘汰策略
volatile-lru【最近很少使用】
当内存告警时
redis
会将近期很少使用且设置了过期时间的key剔除出去,即使该key还没有到过期时间。如果没有符合的key也就是执行之后内存仍然不足时将会和默认淘汰策略noeviction
抛出一样的错误OOM command not allowed when used memory > maxmemory
- 首先我们在
redis.conf
中配置我们最近很少使用策略.maxmemory-policy volatile-lru
。 然后重启我们的redis
服务 。重启之后flushall
清空所有数据,我们在通过上面的Java
程序重新生成下数据!
- Java程序中我们设置前100个key添加过期时间
public static void main(String[] args) {
Jedis jedis = new Jedis("39.102.60.114", 6379);
jedis.auth("Qq025025");
Integer index = 1;
while (true) {
String uuid = UUID.randomUUID().toString();
if (index < 100) {
jedis.setex(index.toString(),360, uuid);
} else {
jedis.set(index.toString(), uuid);
}
System.out.println(index++);
}
}
- 简单分析下为什么程序计数器大于
redis
库中的key数量!就是因为我们为前100设置了过期时间。当内存不足时redis
就会将当前设置了过期时间的key中最近最少使用的key进行剔除!所以我们计数器会大于键数量。因为有部分键被清除了!我们获取前100的key都是null , 说明被删除了! 那么为什么本次计数器不是比上次多100 。 那是因为我们每次存储进来的是uuid, 所占长度都不是固定的。还有本身淘汰策略也是占用内存的
策略总结
- 上面演示了最近最少使用的淘汰策略!除此之外还有其他的策略
noeviction:拒绝写请求,正常提供读请求,这样可以保证已有数据不会丢失(默认策略);
2. volatile-lru:尝试淘汰设置了过期时间的key,虽少使用的key被淘汰,没有设置过期时间的key不会淘汰;
3. volatile-ttl:跟volatile-lru几乎一样,但是他是使用的key的ttl值进行比较,最先淘汰ttl最小的key;
4. volatile-random:其他同上,唯一就是他通过很随意的方式随机选择淘汰key集合中的key;
5. allkeys-lru:区别于volatile-lru的地方就是淘汰目标是全部key,没设置过期时间的key也不能幸免;
6. allkeys-random:这种方式同上,随机的淘汰所有的key。
- 使用哪种淘汰策略需要我们结合自己的项目场景来配合使用!!!
过期删除
- 上面我们从【键过期】、【淘汰策略】两个角度分析了
redis
。 仅仅这两方面还没有完全高效使用内存!淘汰策略是濒临内存不足时触发。那么当设置了过期时间的键真正到了过期时间而此时内存尚够使用?这种场景是不是需要将过期键删除呢? - 因为
redis
是单线程,那么在键过期的时候如何不影响对外服务的同时清除过期键呢?答案是【不行】。严格意义是无法解决的因为单线程同时只能做一件事!既然无法解决那么我们可以达到一种协调状态!如果同一时刻出现一个过期键那么清除键很快这时候阻塞外部服务的时间很短可能毫秒级设置纳秒级! - 但是如何同一时间发生上万键过期,如果想要删除上万键那肯定需要花费一定时间这时候就会阻塞对外服务!这肯定是不能接受的,阻塞时间过长会导致客户端连接超时报错的。这在并发场景下更是无法接受的!所以
redis
如何应对同一时间过多数据过期的场景,他的删除过期键的方法略有不同!
定时清除
- 针对每个过期键设置一个定时器,在过期时就会进行清理该键!
- 该做法能够做到数据实时被清理从而保证内存不会被长期占用!提高了内存的使用率!
- 但是问题也随之而来,每一个
key
需要设置一个定时器进行跟踪。redis
这里笔者猜测应该是启用另外线程来进行定时跟踪!这里有清除的还请帮忙解答下? - 当同一时间过期
key
很多的时候!我们的CPU就需要不断的执行这些定时器从而导致CPU资源紧张。最终会影响到redis
服务的性能
定期清除
- 定期删除就是上面我们图示效果,
redis
会每隔100ms
执行一次定时器,定时器的任务就是随机抽取20个设置过期的key
。 判断是否进行清除。上面图示中说明中写错了不是10S , 而是每隔100ms
。请原谅我的粗心!!!
- 定期删除和定时删除作用是相反的!定期删除是将key集中进行处理同时为了保证服务的高可用在处理时加入的时间限制。每次执行总时长不能超过
25ms
。 也就是说对于客户端来说服务端的延迟不会超过25ms
。 - 他的优点就是不需要CPU频繁的进行操作key清除!因为他是定期进行清除所以就会导致一部分数据没有来得及清除从而导致内存使用上会被一直占用!
惰性清除
- 关于惰性删除我们在平时开发中也经常使用这种方式!当数据过期时
redis
并不急着去清除这些数据,而是等到该key被再次请求时进行删除!这样在最终效果上是没有问题的。 - 优点和定期清除一样他保证了CPU不必频繁的进行切换!但是缺点也很明显会导致很多已经过期的key任然在
redis
中。
惰性清除+定期清除
- 我们开头说过了既要高可用又要实时清理过期key 这是无法做到的!既然无法做到我们就需要在CPU和内存中间做一个权衡!
redis
内部是使用惰性清除和定期清除两种方式结合使用,最终保重CPU和内存之间的一种平衡!
总结
- 相信大家对上面三个概念有点模糊了。【键过期】、【淘汰策略】、【过期清除】
- 首先【键过期】是
redis
给我们开发者提供的功能。我们可以根据自己的业务需求合理的设置键的过期时间,从而保证内存的高可用 - 其次【过期清除】在我们之前设置的过期的key如何进行合理的清除,并不能一股脑一下子进行清除因为数据过大会导致服务的卡顿。这个时候我们需要通过定期清除减缓清除key代码的卡顿。在
redis.conf
中我们可以设置hz 10
代表1S
中平均执行几次这也是我们上面所说的100MS
的由来。但是仅仅定期删除会产生遗漏数据所以我们还需要加上惰性清除,最终保证对客户端来说数据是准确实时清除的。 - 那么关于【淘汰策略】又是啥呢?在上面过期清除是如果用户一直不请求过期的key ,并且随着业务产生越来越多的过期key . 这时候
redis
服务中还会堆积很多过期的无效key 。这个时候如果内存不够用了的话那又该怎么办呢?这时候我们需要设置淘汰策略比如果volatile-lru
. 就会将最近最少使用的设置过期key进行清除从而保证尽可能的接收更多的有效数据! - 这就是为什么会设计三者的原因!好好理解上面三个主题我们再去想想为什么会发生【缓存雪崩】、【缓存奔溃】、【缓存击穿】就好理解一点了呢?
- 关于上述的
redis
常见的灾难场景,我们下章节继续分析如何产生的、并且如何进行修复进行展开讨论。
redis淘汰+过期双向保证高可用 | redis 为什么那么快?的更多相关文章
- redis 记一次搭建高可用redis集群过程,问题解决;Node 192.168.184.133:8001 is not configured as a cluster node
------------恢复内容开始------------ 步骤 1:每台redis服务器启动之后,需要将这几台redis关联起来, 2: 关联命令启动之后 报错: Node 192.168.184 ...
- Redis从出门到高可用--Redis复制原理与优化
Redis从出门到高可用–Redis复制原理与优化 单机有什么问题? 1.单机故障; 2.单机容量有瓶颈 3.单机有QPS瓶颈 主从复制:主机数据更新后根据配置和策略,自动同步到备机的master/s ...
- 高可用Redis服务架构分析与搭建
基于内存的Redis应该是目前各种web开发业务中最为常用的key-value数据库了,我们经常在业务中用其存储用户登陆态(Session存储),加速一些热数据的查询(相比较mysql而言,速度有数量 ...
- 高可用Redis(十二):Redis Cluster
Redis Cluster是Redis官方提供的Redis集群功能 1.为什么要实现Redis Cluster 1.主从复制不能实现高可用 2.随着公司发展,用户数量增多,并发越来越多,业务需要更高的 ...
- 高可用Redis(九):Redis Sentinel
1.主从复制高可用的问题 主从复制高可用的作用 1.为master提供备份,当master宕机时,slave有完整的备份数据 2.对master实现分流,实现读写分离 但是主从架构有一个问题 1.如果 ...
- 高可用Redis服务架构分析与搭建(单redis实例)
原文地址:https://www.cnblogs.com/xuning/p/8464625.html 基于内存的Redis应该是目前各种web开发业务中最为常用的key-value数据库了,我们经常在 ...
- 11.Redis 哨兵集群实现高可用
作者:中华石杉 Redis 哨兵集群实现高可用 哨兵的介绍 sentinel,中文名是哨兵.哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能: 集群监控:负责监控 redis mast ...
- 高可用Redis:Redis Cluster
转(https://www.cnblogs.com/renpingsheng/p/9862485.html) Redis Cluster是Redis官方提供的Redis集群功能 1.为什么要实现Red ...
- 如何搭建高可用redis架构?
如何搭建高可用redis架构? 温国兵 架构师小秘圈 昨天 作者:温国兵,曾任职于酷狗音乐,现为三七互娱 DBA.目前主要关注领域:数据库自动化运维.高可用架构设计.数据库安全.海量数据解决方案.以及 ...
随机推荐
- (转)elasticsearch6.0版本安装head插件
1.1 前言 不知道是我电脑问题还是最近的开源软件都比较**,mysql和elasticsearch新版本变动都比较大. elasticsearch6.0貌似已经不支持命令行安装head插件了,反正我 ...
- x265编码命令
CQP: #/bin/bash ./x265 --input FourPeople_1280x720_60.yuv --input-res 1280x720 --fps 60 --qp 40 --fr ...
- [MySQL数据库之表的详细操作:存储引擎、表介绍、表字段之数据类型]
[MySQL数据库之表的详细操作:存储引擎.表介绍.表字段之数据类型] 表的详细操作 存储引擎 mysql中建立的库======>文件夹 库中建立的表======>文件 用来存储数据的文件 ...
- Excel导出数据Excel.Application组件权限设置方法
很多网络应用系统都会涉及到数据采用Excel方式导出的模块,部分朋友问我到底怎么弄,其实方式很多种,目前比较优秀的方式还是直接用Excel的Excel.Application方式比较合适. 采用Exc ...
- [bug] Job for network.service failed because the control process exited with error code
原因 复制虚拟机,没有改网卡配置文件 参考 https://blog.csdn.net/dongfei2033/article/details/81124465
- CSS变量和浏览器前缀
一.CSS变量 CSS变量是CSS的新特性,大多数浏览器都实现了这个功能,使用CSS变量有利代码复用,而且当我们修改变量值时,所有引用该变量的属性都会发生改变. 定义变量后可以有两种使用方法,第一种时 ...
- 快成物流科技 x mPaaS | 小程序容器加持下的技术架构“提质增效”
导言 从 2017 年开始,GMTC"移动技术大会"就更名为"大前端技术大会".发展至今,混合开发.原生开发.前端开发等概念正在深度融合,组成"大 ...
- 『动善时』JMeter基础 — 27、通过JMeter函数助手实现参数化
目录 1.测试计划中的元件 2.数据文件内容 3.函数助手配置 (1)函数助手的打开方式 (2)函数助手界面介绍 (3)编辑后的函数助手界面 4.HTTP请求组件内容 5.线程组元件内容 6.脚本运行 ...
- Linux C 文件IO
文件IO 2021-05-31 12:46:14 星期一 目录 文件IO 基础IO open 错误 creat read 一个例子 write close lseek 文件空洞 unlink删除 io ...
- 【进阶之路】多线程条件下分段处理List集合的几种方法
这两个月来因为工作和家庭的事情,导致一直都很忙,没有多少时间去汲取养分,也就没有什么产出,最近稍微轻松了一点,后续的[进阶之路]会慢慢回到正轨. 开门见山的说,第一次接触到多线程处理同一个任务,是使用 ...