文章目录
Redis知识点总结
简介
Redis的16个DB
redis默认是有16个db组成,默认操作的一半都是第0个,这些DB主要有以下特点:
- 不支持自定义数据库名词
- 每个数据库不能单独设置授权
- 每个数据库之间并不是完全隔离的。 可以通过flushall命令清空redis实例面的所有数据库中的数据
通过 select dbid 去选择不同的DB 。 dbid的取值范围默认是0 -15
Redis的数据结构
主要有5种
- 字符类型(String)
- 散列类型(hash)
- 列表类型(List)
- 集合类型(Set)
- 有序集合类型(ZSet)
Redis的应用场景
- 数据缓存
- 单点登录
- 秒杀类活动
- 网站访问排名
- 应用模块开发
Redis常用命令
String命令 | 用法 | 含义 |
---|---|---|
set key value | set aaa aaa | 缓存一个字符串类型aaa,key是aaa,value是aaa |
get key | get aaa | 从缓存中获取一个key是aaa的数据 |
incr key | incr bbb | 将key是bbb的数据进行递增,类似i++,value必须是数字 |
incrby key increment | incrby bbb 5 | 将key是bbb的数据加5 |
decr key | decr bbb | 将key是bbb的数字递减,类似i– |
decrby key | decrby bbb 3 | 将key是bbb的数字减3 |
append key value | append aaa 000 | 将key是aaa的数据尾部添加000,比如说之前aaa的值是aaa,操作之后aaa的值是aaa000 |
strlen key | strlen aaa | 获取key是aaa的数据长度 |
mget key key … | mget aaa bbb | 同时获取多个key的数据 |
mset key value key value … | mset ccc 111 ddd 222 | 同时设置多个key和value |
Hash命令 | 用法 | 含义 |
---|---|---|
hset map key value | hset user name zhangsan | 设置user对象的name字段为zhangsan,设置多个就是一个对象,hash就可以用来表示这个关系 |
hmset map key1 value1 key2 value2 … | hmset user … | 一次设置多个属性,相当于上边的批量添加 |
hsetnx map key value | hnxset user age 13 | 如果user对象的age属性不存在,那就设置这个属性值 |
hget map key | hget user name | 获取user对象的name属性 |
havls map | havls user | 获取整个map的值,也就是user对象 |
hkeys map | hkeys user | 获取user所有的属性值 |
hlen map | hlen user | 获取user的字段数量 |
hdel map key1 key2 | hdel user name age | 删除一个或多个哈希表字段 |
hexists map key | hexists user name | 查看user对象不否存在name字段 |
List命令 | 用法 | 含义 |
---|---|---|
key value | lpush eee 111 | 从左边往列表插入数据 |
rpush key value | rpush eee 222 | 从右边往列表插入数据 |
lpop key | lpop eee | 从列表左边弹出数据,会把数据从列表删除 |
rpop key | rpop eee | 从列表右边弹出数据,也会删除 |
llen key | llen eee | 获取列表的长度 |
lrange key start stop | lrange eee 0 3 | 从列表做边开始获取范围数据,范围就是0-3,stop为-1时表示列表最大值,也就是最右边第一个元素 |
lrem key count value | lrem eee 1 3 | 从列表中删除1个值为3的数据 |
lset key index value | lset eee 0 5 | 把列表中key是eee的数据下标为0的值改成5 |
Set命令 | 用法 | 含义 |
---|---|---|
sadd set value | sadd mySet 1 | 添加元素 |
smembers set | smembers mySet | 查看全部元素 |
sismember set value | sismember mySet 3 | 判断是否包含某个值 |
srem set value | srem mySet 1 | 删除某个元素 |
srem set value1 value2 | srem mySet 2 4 | 删除某些元素 |
scard set | scard mySet | 查看元素个数 |
spop set | spop mySet | 随机删除一个元素 |
smove set1 set2 value | smove yourSet mySet 2 | 将一个set的元素移动到另外一个set |
sinter set1 set2 | sinter yourSet mySet | 求两set的交集 |
sunion set1 set2 | sunion yourSet mySet | 求两set的并集 |
sdiff set1 set2 | sdiff yourSet mySet | 求在yourSet中而不在mySet中的元素 |
ZSet命令 | 用法 | 含义 |
---|---|---|
zrange zset start stop | zrange zset 0 3 | 获取排名最后三位, start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员, 以 1 表示有序集第二个成员,以此类推。 你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。 |
zrevrange zset start stop | zrevrange zset 0 3 | 获取排名前三(默认是升序,所以需要 rev 改为降序) |
zrank zset value | zrank zset zhangsan | 获取zhangsan的排名 |
Lua脚本 | 用法 | 含义 |
---|---|---|
evel | evel(…) | 运行lua脚本 |
Redis分布式锁的实现
mysql
建个表,根据for update 或者乐观锁,或者insert和delete加唯一索引实现
zookeeper
- 竞争创建节点,然后监听创建成功的
- 根据znode,创建一个有序临时节点,
redis
#加锁,2s过期
set lock 随机数 nx px 2000
#删除锁,用lua脚本,找到 key 对应的 value,跟自己传过去的 value 做比较,如果是一样的才删除。
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
Redis数据过期策略
redis这三种都使用着,因为这三种策略是非互斥的
- (惰性删除)被动删除:当读/写一个已经过期的 key 时,会触发惰性删除策略,直接删除掉这个过期 key 。
- (定期删除)主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以 Redis 会定期主动淘汰一批已过期的 key,redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除
- (缓存淘汰)主动删除:当前已用内存超过 maxmemory 限定时,触发主动缓存淘汰策略
Redis缓存淘汰策略
Redis默认只能用10G的内存
- volatile-lru
当写入数据是发现内存不足,那就在设置了过期时间的key中挑选最近最少使用的key删除掉 - volatile-ttl
当写入数据是发现内存不足,那就在设置了过期时间的key中把快要过期的某个key提前删除 - volatile-random
当写入数据是发现内存不足,那就在设置了过期时间的key中随机删除 - allkeys-lru
当写入数据时发现内存不足,那就在所有key中挑选最近最少使用的key删除掉,也是最常用的策略 - allkeys-random
当写入数据时发现内存不足,那就在所有的key中随机删除某个key - no-enviction
当内存不足以容纳新写入数据时,新写入操作会报错,一般没人用吧
Lua
全局变量 local a = 1;
局部变量 a =2;
逻辑表达式
+ - * /
相等 ==
不等于 ~=
大于 >
小于 <
取余 %
负号 -
逻辑运算符
and /or /not
拼接 … eg : print(a…b)
获取长度 #
条件判断
if … then elseif … then else … end
循环
while … do … end
for i=0,10 do print(i) end
–[[范围注释]] --单行注释
函数
全局函数
local function(str…) … end
局部函数
function(str…) … end
Redis持久化策略
RDB(dump.rdb)
RDB会按照规则定制从内存把数据持久化到磁盘
快照(Snapshot)
redis在指定的情况下会触发快照
1.自己配置的快照规则
save save 秒-单位时间 在这个时间内更改次数大于某个值时会执行快照
save 10 3 就是在10秒内更改次数超过3次就会执行快照
2.通过save或者bgsave命令
save执行内存的数据同步到磁盘的操作,这个操作会阻塞客户端的请求.
bgsave在后台异步执行快照,这个不会阻塞客户端请求
3.执行flushall的时候
清除内存的所有数据,只要配置的规则存在,那就会执行快照
4.执行复制的时候
快照实现原理
redis会使用fork函数复制一份当前进程的副本(子进程),fork进程负责把内存的数据同步到磁盘的临时文件,父进程继续处理客户端请求
优点:
可以最大化redis的性能,但是数据量很大的话,fork时间过久也会影响一些性能
缺点:
可能会存在数据丢失的请求,也就是快照和下一次快照的中间,redis挂了
AOF
AOF是每次执行命令后,把命令本身记录到磁盘
开始AOF的方式就是在配置文件中把appendonly设置成yes,默认的文件名就是appendonly.aof
每次命令都保存,那些旧数据也被保存了,徒增烦恼,我们只需要最新的数据而已,redis配置文件中有压缩策略解决了这个
如下两个参数可以去对aof文件做优化
auto-aof-rewrite-percentage 100 表示当前aof文件大小超过上一次aof文件大小的百分之多少的时候会进行重写。如果之前没有重写过,以启动时aof文件大小为准
auto-aof-rewrite-min-size 64mb 限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
aof重写的原理
Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松
同步磁盘数据时的问题
redis每次更改数据的时候, aof机制都会将命令记录到aof文件中,但是由于操作系统的缓存机制,数据并没有实时的写入到硬盘中,而是先写入到了硬盘缓存。再通过硬盘缓存机制去保存到文件中,所以在这个时间段之内如果redis挂了,那就会存在数据同步问题,redis提供了appendfsync参数来解决这个问题.
- appendfsync always 每次执行写入都会进行同步,这个是最安全但是是效率比较低的方式
- appendfsync everysec 每一秒执行一次同步,就算丢失也是1秒的数据,是可接受的
- appendfsync no 不主动进行同步操作,交给操作系统去执行同步操作这个是速度最快的,但也是最不安全的方式
写入AOF的时候系统宕机怎么办
在写入AOF和同步到磁盘的时候,系统宕机了,结果造成了AOF文件损坏,那在redis重启的时候是不会加载损坏的AOF文件的,这样就造成了数据的不一致或者丢失的情况,redis本身提供了AOF文件修复工具,具体操作如下:
1.先备份一下AOF文件
2.使用Redis提供的 redis-check-aof 程序来修复原来的AOF文件,执行redis-check-aof --fix命令即可,修复完成后重启,RDB也有一个修复工具,道理相同
缺点
响应请求的同时还要写磁盘,稍微会影响性能,但是还是IO得问题,换固态即可
缓存击穿
key不存在
缓存穿透
key过期
缓存雪崩
宕机
总结
可单独使用也可一起使用,如果一起使用,当redis启动或重启时,redis会优先使用AOF来还原数据