REDIS
它的全称是REmote DIctionary Service,直接翻译过来是远程字典服务。
Redis特性
速度快
支持多数据类型
功能丰富:持久化机制、过期策略
支持多种编程语言
集群部署
IO多路复用
Redis基本操作
1.切换数据库
select 数据库名
2.清空当前数据库
flushdb
3.清空所有数据库
flushall
存值
set bobo 888
取值
get bobo
查看所有键
keys *
获取键总数
dbsize
查看键是否存在
exists bobo
删除键
del bobo
重命名键
rename bobo bobo1
查看对外类型
type bobo1
Redis五大数据类型
1.String
可以用来存储字符串、整数、浮点数。
基本指令:
批量设置
mset bobo niuniuniu kuikui 888
批量获取
mget bobo kuikui
获取长度
strlen bobo
字符串追求内容
append bobo good
获取指定范围的字符
getrange bobo 0 5
(整数)值递增
incr intkey
incrby intkey 100
(浮点数)值递增
set f 2.6
incrbyfloat f 7.3
如果不存在,这个key设置成功,存在,这个key设置失败(分布式锁)
set lock1 1 EX 10 NX
应用场景
1.缓存 、主键
2.分布式ID
3.计数器、限流 ,incrby
2.Hash哈希
指令操作将s换成h即可
使用场景:
String可以做的事情,Hash都可以做!
存储对象类的数据
比如对象或者一张表的数据,比String节省了更多 key 的空间,也更加便于集中管理购物车,还可以通过hincrby hkey f 1 加数量!
3.List列表
存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色。
左右添加元素
lpush bobolist b c
rpush bobolist d e
左右弹出第一条
lpop bobolist
rpop bobolist
左右弹出第一条,并设置超时,直到有数据弹出或者超时
blpop bobolist 10
brpop bobolist 10
取值
lindex bobolist 0
lrange bobolist 0 -1
使用场景
1.用户消息时间线
因为list是有序的
2.消息队列
List提供了两个阻塞的弹出操作:BLPOP/BRPOP,可以设置超时时间。
BLPOP:BLPOP key1 timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOP:BRPOP key1 timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
队列:先进先出:rpush blpop,左头右尾,右边进入队列,左边出队列。
栈:先进后出:rpush brpop
4.Set集合
String 类型的无序集合,最大存储数量 2^32-1(40 亿左右)。
基本指令:
添加一个或者多个元素
sadd boboset a b c d e f g
获取所有元素
smembers boboset
获取所有元素的个数
scard boboset
随机获取一个元素
srandmember boboset
随机弹出一个元素
spop boboset
弹出指定元素
srem boboset g a
查看元素是否存在
sismember boboset e
获取前一个集合有而后面1个集合没有的
sdiff boboset huihuiset1
获取交集
sinter boboset huihuiset1
获取并集
sunion boboset huihuiset1
使用场景
1.抽奖
2.点赞、签到
3.交集并集 关注等
5.ZSet有序集合
sorted set,有序的set,每个元素有个score。 score相同时,按照key的ASCII码排序。
基本指令
批量添加
zadd bobozset 10 java 20 php 30 ruby 40 cpp 50 python
根据分数从低到高
zrange bobozset 0 -1 withscores
根据分数从高到低
zrevrange bobozset 0 -1 withscores
根据分数范围获取值
zrangebyscore bobozset 20 30
移除元素
zrem bobozset php
获取zset个数
zcard bobozset
给某个元素加分
zincrby bobozset 50 java
获取范围内的个数
zcount bobozset 50 60
返回指定元素的索引
zrank bobozset java
获取元素的分数
zscore bobozset java
使用场景
排行榜、公司绩效考核
内存淘汰
过期策略
1.定时过期(主动淘汰)
每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好,但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
2.惰性过期(被动淘汰)
该策略就可以最大化地节省CPU资源,但是却对内存非常不友好。因为你不实时过期了,该过期删除的就可能一直堆积在内存里面!极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的 key。
Redis 默认会每秒进行 10 次(redis.conf 中通过 hz 配置)过期扫描,扫描并不是遍历过期字典中的所有键,而是采用了如下方法:
1.获取20个hash桶
(active-expire-effort可以更改大小,默认20)
2.删除这20个桶中过期的键
3.如果过期键的比例超过 10%或者没有删除过期键 ,重复步骤 1 和 2,没循环16次会检测时间,超时会跳出!
该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得 CPU 和内存资源达到最优的平衡效果。 Redis中同时使用了惰性过期和定期过期两种过期策略。
3.淘汰策略
地址:https://redis.io/topics/lru-cache
如果redis可能没有需要过期的数据了,但是数据量还是h会把我们的内存都占满了,因为我们的内存是有个大小配置的
redis.conf 参数配置:
maxmemory
如果不设置 maxmemory 或者设置为0,64位系统不限制内存,32位系统最多使用3GB内存。 我们还可以通过命令动态修改
动态修改:
redis> config set maxmemory 2GB
redis.conf
maxmemory-policy noeviction 默认是这个,动态修改淘汰策略:
redis> config set maxmemory-policy volatile-lru
1.LRU(最久未使用)
Lru,Least Recently Used 那么它的一个衡量标准是啥?时间!翻译过来是最久未使用,根据时间轴来走,仍很久没用的数据只要最近有用过,我就默认是有效的。
那么,LRU本来的原理是这样子的:
它有2个操作,1个是移动顺序,要把最新的放在前面,还有1个就是要查数据,查出最后1个数据淘汰。就是要查跟插!
然后又是用于缓存淘汰,所以要保证时间复杂度的o(1),所以我们LRU算法hash+双向链表来实现的!
不足:如果我们用最原始的,我们需要额外的数据结构存储,因为要存储hash+双向链表,消耗额外空间。
2.LFU(最不常用)
LFU,英文 Least Frequently Used,翻译成中文就是最不常用,不常用,是按着使用次数、频率来算的。
传统的LFU算法简单就一句话,根据访问次数跟访问时间做倒排,实现末尾淘汰制!
LFU加的逻辑:
1.如果已经是最大值,我们不再加!没加影响不大,到达255的几率不是很高!
2.counter属于随机添加,添加的几率根据已有的counter值和配置lfu-log-factor相关,counter值越大,添加的几率越小,lfu-log-factor配置的值越大,添加的几率越小!所以我们可以得到,虽然只有8位,但是加满是很难很难的!
缓存场景分析
1.缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,但是用户一直请求不存在的数据!这时的用户很可能就是攻击者,恶意搞你们公司的,攻击会导致数据库压力过大。
2.缓存击穿
某条数据在即将过期的时候,并发请求到DB,导致DB压力突然增大
解决办法: 在redis数据没有,去DB拿的时候,加上互斥锁这种一般的公司都是不必要考虑的!因为它访问不是特别特别特别大的时候,也就最多过期那一刻的并发很高!加上锁后,就算你并发在高,那么我也只会请求一次DB!
3.缓存雪崩
这个跟缓存击穿有相同性,但是redis缓存里面没有,都打到DB,但是有点不一样,这个是redis的key同时全部过期了,所有的访问都打到DB!而不是只有1个key
这个解决办法很简单,就是每个key设置不一样的过期时间!我们就能解决这个问题!