一、Redis 事务管理
- 简介:
redis 事务作为一个命令执行的队列,将一系列的预处理的命令包装成为一个整体,当执行时按照添加顺序依次执行,中间不会被打断或干扰。因此 redis 采用 multi、exec、discar 进行对事务的处理。
开启事务:multi 关闭事务:exec 取消命令:discard
- redis 事务的特性:
在传统的关系数据库中存在事务的 ACID 属性。然而在 redis 中也存在事务的原子性(Atomicity)、一致性(Consistency)、隔离性(Lsolation)以及在持久化时存在持久性(Durability)。具体 ACID 此处不展开叙述。学到 redis 的人应该之前都知道 ACID
- 注意事项:
redis 与关系型数据库还是有很大的区别,例如在 mysql 的 LnnoDB 存储引擎中具有支持事务的处理,以及在 SQL 中他们都支持事务的回滚机制,但是在 mysql 中并不存在这种机制。
PS:有的人会认为 discard 是事务的回滚,这种认为是错误的,他只是在事务开启后输入 discard 指令,然后取消预处理队列中的所有命令也就是取消事务。
- 执行过程:
总的来说就是,我们开启客户端后输入 mutil 指令,开启事务,事务开启后,就可进行 get set 操作。直到我们输入 exec,开始进行事务处理,或者是遇到 discard 取消事务。
- 测试案例:
- 闲谈:
也许这时候你会想到,万一我写的时候命令写错了怎么办,嗯,没事他会取消所有的指令操作,也就是取消整个事务。然后可能你还会想到,万一我指令没写错,数据写错了怎么办呢,emmmmm,那就祝你好运吧,你懂的。
二、Reids 锁
当我们在进行某些操作时需要对其加锁处理,redis 也提供相应的操作。
watch 监视锁:对某个 key 进行监视,key 一旦发生改变则不再执行
- 未加监视锁:
- 启监视锁:
- 闲谈:
这里也许你会想到说,这只是监视锁,我想要的是当我做操作的时候其他人不可以做,只有等我结束了其他人才可以做,别急我们来看看下面的分布式锁。
三、分布式锁
- 说明:
当一个线程真正执行的过程中,不允许其他线程的操作,也就是在做操作之前判断是否有锁,如果有锁,说明有线程在执行,进入等待状态,直到锁被释放后得到锁,然后加锁--执行--释放。
- 举个例子:
有一天你去广场上看大妈们跳广场舞。突然,这时候你肚子疼。但是这个广场只有一个公共卫生间每次只能共一个人使用。然后你就飞快的跑着过去,突然你发现门从里面被反锁了。然后你没办法,只能在外面等待里面的人出来,这时候门开了,你飞快跑进去。然后关门、上锁,开始拉粑粑,直达拉好,然后你开锁,然后打开门出来,下一个人进去。
在这个例子中,你卫生间就相当于公共资源,每当一个人进去之后就会关上门(加锁)当一个人使用的时候另一个人只能进入等待状态,直到锁打开(锁被释放)才能够获得其资源。
- 案例:
**PS:**在我们处理分布式锁的时候通常事微秒或毫秒级别的,因此加锁时间不宜过大,具体时间需要业务测试后确认。
设定时间推荐: 最大耗时 120%+ 平均网络延迟 110 or 最大耗时 << 网络平均时延,则取网络延时,反之相反
四、删除策略
redis 采用的是内存数据库。除了持久化以外的文件,所有的数据均在内存中进行运行,但有些数据并不是有效的,因此出现了删除策略。
删除策略包括:定时删除、惰性删除、定期删除
- 引入:
在分别讲述删除策略时,我们先来看一下下面的这个图:
我们在进行信息存储的时候 Redis 不仅仅会进行一个信息的存储,同时还会分配出 expires 空间,通过地址关联存储 key 的过期时间。
- 定时删除:
创建一个定时器,当达到时间,定时器工作,删除其指令与 expires 空间中内容。
换句话说就是我们 set 的时候在设定过期时间的同时也就创建了一个定时器,当时间一到,定时器响应,然后删除其 key 相关的所有东西。
优点:
节约内存、到时就删除、快速释放内存
缺点:
CPU 压力大,无论 CPU 压力有多大都会占用 CPU,同时影响 redis 服务器的相应时间与吞吐量
PS:用 CPU 性能换取存储空间(拿时间换空间)
- 惰性删除
简单描述就是当数据过期后不做任何处理,当下次访问时候再将数据删除
也就是我们在设定 key 的过期时间,key 过期了,虽然我们不能够进行操作,但是他仍然存在于内存之中,而每次我们对 key 进行访问时会调用 expirelfNeeded()进行是否过期判断,如果过期则将其删除,没有过期则继续操作。
优点:
节约 CPU 性能,发现必须删除时候才进行删除
缺点:
内存压力大,出现长期占用内存的情况
PS:用存储空间换处理器性能(拿空间换时间)
- 定期删除
定时删除需要花费更多的时间,惰性删除需要花费更多的空间,而定期删除进行了二者的折中,采用周期性轮询 Redis 数据的时效性,采用随机读取的策略,采用过期数据占比的方式控制删除的频度。
具体实现:
如果觉得下面的废话太多,直接看图。
当 redis 服务器进行初始化时,会对配置文件进行读取,读取其中的 server.hz 的值(默认大小为 10)进行操作。然后进行每秒钟执行 server.hz 次 serverCron()操作。而每次的 serverCron()操作都会对所有的数据库进行 databaseseCron()轮询。在轮询过程中执行 axtiveExpireCyle()操作。而对于每一个 expires[*]进行逐一的检测,每次执行 250ms/server.hz 个。在检测过程中会采用随机挑选 W 个值进行检测,如果检测到 key 超时就将其删除。而在一次轮询中删除的 key 数量大于 25xW 时,则再次循环这个过程,如果小于等于 25xW 则检测下一个 expire。
W 取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 属性值
参数 Current_db 记录每次 activeExpireCycle 进入到那个 expires[]执行
如果 activeExpirecycle 执行时间到期,停止执行,下次继续相同位置执行
特点:
- cpu 的性能设有峰值,检测频度可以自己设定
- 内存压力不大,长期常用内存的过期数据会被持续性清除
PS:
随机性抽查,重点抽查存储空间
五、逐出算法
定义:
redis 使用内存存储数据,在执行每一个命令之前,都会调取 freeMemorylfNeeded()进行检测内存是否充足,如果内存不满足新书加入数据的最低要求,redis 要临时删除一些数据为当前指令清出存储空间,清除数据的策略称之为逐出算法。
注意:
逐出过程不是 100% 能够清理出足够的内存空间,当不成功时候会反复执行,当对所有的数据都尝试完毕后,还没有达到内存的清理的要求就会抛出错误信息:
(error)OOM command not allowed when used memomry>'maxmemory'
配置:
maxmemory 最大的可用内存(占用物理内存的比例,默认为 0,表示不限制,生产环境中根据需求设定,通常设置在 50% 以上)
maxmemory-samples:每次选取删除数据的个数,(选取数据时并不会全库扫描,导致严重的性能消耗,降低读写性能,因此采用随机获取数据的方式作为待检测删除数据策略)
策略配置:eg:maxmemory-policy volatile-lfu
检测易失数据(可能会过期的数据server.db[i].expire)
volatile-lru:挑选最近没有使用过的数据淘汰
volatile-lfu:挑选最近使用最少的数据淘汰
volatile-ttl:挑选将要过期的数据淘汰
volatile-random:任意选择数据淘汰
检测全库数据:(所有数据集server.db[i].dict)
allkeys-lru:挑选长时间未使用的数据
allkeys-lfu:挑选最近使用次数最少的数据
allkeys-random:任意选择淘汰
no-enviction:禁止驱逐数据(4.0中默认策略。会引发OOM)
调优:
InFO:查看 hit 命中与 miss 的次数然后进行调优
❤️ 给 ❤️ 梦 ❤️ 想 ❤️ 一 ❤️ 点 ❤️ 点 ❤️ 时 ❤️ 间 ❤️ 让 ❤️ 它 ❤️ 一 ❤️ 步 ❤️ 步 ❤️ 成 ❤️ 长 ❤️
💪 加油!!! 💪
redis 更多早期随笔:
redis 持久化(RDB 与 AOF)的方式比较:https://www.wslhome.top/articles/2020/06/16/1592312734423.html
redis 搭建、redis 命令、基础知识:
https://www.wslhome.top/articles/2020/06/12/1591944857524.html
redis 五种基本数据格式原理与应用:
https://www.wslhome.top/articles/2020/06/16/1592312 用 CPU 性能换取存储空间(拿时间换空间)
内存压力大,出现长期占用内存的
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于