下面所有东西都是从昂炎数据买的,只需要7块就能买到一份超级全的redis知识集,下面也不吃独食,给大家分享一些知识点:
对象:
redis所有的类型都是一种对象:字符串对象、列表对象、字典、有序集合、无序集合
每一种对象底部都使用了一种或多种数据结构:字符串(SDS,和C的字符串有些区别,和java的String还是挺像的)、压缩表、跳跃表、哈希表、整型集合等
对象的引用计数:
这里的引用计数和jvm的引用计数基本相同。
对象的空转时长:
这里的空转时长通过对象数据结构中的lru字段表示,可以通过参数OBJECT IDLETIME key参数看空转时长。
Select
select命令可以切换数据库
对数据库的操作:
DBSIZE
flushdb
rename
keys
randomkeys
读取一个键的维护操作:
1、读取更新键的lru
2、读取更新键的命中次数,可以通过info stats命令的keyspace_hits和keyspace_misses属性查看
3、如果使用的watch key监视了某个键,更新后,会把该键标记为dirty
4、发现键过期,删除该键
5、如果开启了通知,修改该键,redis会发送相应的通知
设置键的生存时间
expire key 5秒 生存时间
pexpire key 166787777000 设置过期时间,这里是个时间戳
expireat key 5000 毫秒
pexpire key 166787777000
TTL key 计算并返回生存时间,秒
PTTL key 计算并返回过期时间和现在时间的差值,毫秒
persist key 移除过期时间
过期清除策略:
redis采用惰性删除和定期删除
惰性删除:
惰性删除就是在查看该键的时候,发现键过期了,就删除掉
定期删除:
分批对redis进行检查,过期的键删除掉
生成RDB文件:
保存数据库时使用save和rgsave命令,但是不会保存已经过期的键
载入RDB文件:
主服务器模式:已经过期的不会载入
从服务器模式:已经过期的仍然载入
AOF持久化模式:如果已经过期但是还没被删除,仍然会写入AOF文件,当键被删除时,追加一条删除命令
AOF重写:过期的键不会写入AOF重写的文件中,BGRewriteAOF命令可以开始 重写AOF
复制:从服务器还没有收到删除的命令,接到了读命令,仍然可以读到键里的内容。当接到主服务器的删除命令后,才删除键。
RDB持久化
RDB文件是经过压缩的二进制文件,AOF文件是在持续持久化模式下生成的文件。
使用两个文件的场景,例如:重启服务器,服务器启动等。
三个命令
save命令
save命令会停止redis的进程,直到rdb文件生成完毕
bgsave
创建子进程去保存文件
AOF文件
如果同时有AOF文件和rdb文件,redis会优先载入aof文件
BGSAVE
在执行BGSAVE时,不能执行save
在执行BGSAVE时,会延迟执行BGREWRITEAOF
在执行BGSAVE时,不能再执行BGSAVE
在执行BGREWRITEAOF时,不能执行BGSAVE
自动执行
save 900 1
save 300 10
save 60 10000
含义:满足三个条件中的任何一个都会执行save
900秒 至少一次修改
300秒至少10次修改
60s至少10000次修改
如果没设置,系统会给默认值,上面三个选项就是默认值
AOF持久化
aof持久化保存的是redis的写命令
例如:
set、sadd、rpush等
redis.conf 文件中的appendfsync控制着aof模式下,从缓冲区 到硬盘的模式
有三个选项:always,everysec,no
always是最安全的,但是性能是最差的,因为每次写入时间都要同步磁盘
everysec是每秒执行一次
no是每次写入都只是写到缓冲区,不写入磁盘。写入磁盘的时机由系统负责,也就是等缓冲区满才会写入磁盘
AOF重写
随着时间的发展,AOF文件会越来越庞大,添加,修改,删除都要记录AOF。这时就诞生了AOF重写
原理:
重写名字叫重写,其实就是不管以前的命令,直接把当前的所有记录都 set push 或者add一下,例如:
rpush 1 2 3 4 5
rpush 6 7
rpop
rpop
rpush 6
这是5条指令,重写直接 rpush 1 2 3 4 5 6,只有一条指令。
注意:AOF重写是异步的,这里会有一个文件和数据库状态不一致的问题,如何解决?
redis采用AOF重写缓冲区的方式解决。这个缓冲区在重写开始就启用。
主从复制
slaveof命令可以指定 从某个服务器复制
例如:在127.0.0.1:6534 执行 slaveof 127.0.0.1:8009 那么就是 8009是主服务器,6534是从服务器
1、同步
执行slaveof命令,主服务器收到从服务器的请求后,执行BGSAVE命令生成RDB文件,然后传给从服务器。
2、命令传播
同步完成后,主服务器上的写入命令 会传给从服务器执行达到一致性
3、主从断线重连后
主从都维护了一个复制偏移量,从服务器断线后,重连时发送psync命令,会检测主从的偏移量,不一致后,会把不一致的内容传给从服务器。(这里还有一个主从复制缓冲区的东西,博主不想讲了,看官可以自行搜索)
哨兵
哨兵是干嘛的?
作用其实和zk差不多,监视所有主从服务器,当主服务器下线了,推举一个从服务器成为主服务器,然后通知所有从服务器执行slaveof 命令,认推举出的服务器为主,执行复制操作。
启动哨兵
redis-sentinel path/to/your/sentinel.conf
启动后的步骤:
1、初始化服务器
哨兵其实就是一种特殊的redis服务器,但是不会载入rdb或者aof文件
2、替换成sentinel代码
前面说了,哨兵是一种特殊redis服务器,那就会把redis服务器代码替换成sentinel代码
3、初始化sentinel的master属性
master属性是一个字典值,保存着主服务器的相关信息
4、创建面向服务器的连接
这里可以理解成心跳,sentinel 会定时向主从服务器发送info命令,通过接受回复,分析回复来确定状态。
如何检测服务器是和否下线
sentinel每秒向服务器发送ping命令,能ping通代表在线,ping不通代表下线
sentinel down-after-milliseconds master 5000
这个命令是设置判断服务器主观下线时间的命令
主服务器下线后
sentinel先选出领头sentinel
sentinel首先会选举出一个主的sentinel,由主sentinel开展故障转移操作
该命令是主服务器下线后,发现的sentinel向其他sentinel发送的命令。
大意是在询问其他sentinel:“你们发现了吗,主服务器是不是宕机了?”
sentinel is-master-down-by addr ip port runid
这里的runid是sentinel自己的的id。表示让其他的sentinel的主sentinel设置成这个id。
大意就是:“如果你们发现这玩意也宕机了,就投我票,让我当老大,我去处理!”这个一旦小弟服务器设置过之后就不能再设置老大的id了,也就是只能认一个老大
当有超过半数的sentinel的主sentinel id都是这个sentinel时,这个sentinel就成为主sentinel
领头sentinel开始执行故障转移操作
1、选新服务器
领头的sentinel找到一个状态良好的从服务器,然后发送slaveof no one命令,然后从服务器自己会执行从变主的过程。
领头sentinel每1s向这个服务器发送info命令,检测这个服务器的状态,直到这个服务器的role信息从slave变成master。
2、向其他的从服务器发送slaveof 命令
3、给掉线又重新上线的主服务器发送slaveof 命令,让他变成一个从服务器
集群
创建集群的方式
假如有三个服务器:127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002
在7000上输入命令 CLUSTER MEET 127.0.0.1:7001
代表是让7001假如7000所在的集群。通过CLUSTER NODES命令可以查看7000集群上的node节点
给节点添加槽
集群的整个数据库被划分成16384个槽,当所有槽被管理时集群才是上线状态。可以通过CLUSTER INFO查看。
现在例如又7000,7001,7002三个节点,那么可以通过CLUSTER ADDSLOTS 0.。。。5000 指派0-5000个槽给7000节点,想指派给谁,就在那个节点执行。
想看某个键属于那个槽?
使用CLUSTER KEYSLOT key 命令
订阅和发布
subscribe “channel” 这是订阅命令,代表订阅了channel这个频道
publish “channel” “hello” 代表向channel这个频道发送hello,这是所有订阅channel的客户端都会收到消息。
psubscribe这个是订阅一个模式,模式可以包含一个或多个频道。punsubscribe 退订一个模式
事务
multi 开启事务
其实redis的事务的步骤是这样,multi开启事务,后面的所有操作不会立即执行,而是添加进入一个执行队列中,在执行exec命令时,会提交所有的队列。
watch key 命令
watch其实就是一个乐观锁,如果在事务中该键被修改了,事务提交就会失败,例如
watch “name”
multi
set “name” 123
exec
这里的exec提交事务时就会失败,因为name被修改了,但是name被加锁了。
但是redis的事务是不会回滚的,比如三个语句,1能成功,2会失败,3会成功。并不会因为2的失败导致1,3失败。结果就是1,3成功,2失败。
二进制数组
setbit,getbit,bitcount,bitop
如何用:
setbit bit 3 1
#0000 1000
getbit bit 0
得到的值:0
bitcount bit 这个命令是获取bit中为1 的个数
目前是1
bitop,是对位数组进行按位 与,或,非的操作
去其他博客搜一下,懒得讲了
慢查询日志
slowog-log-slower-than 用于设置超过多少微妙会记录进入慢查询日志中,单位是微妙
config set slowog-log-slower-than 100
监视器
monitor 可以让一个服务器变成一个监视器
分布式锁
首先说一下为什么需要分布式锁?
有一些同学会觉得分布式锁是防止DB被多个线程修改的,但是想想,DB都是读写分离的,写的话只有一个主库在写,缓存的话,redis又是单线程的,那这个分布式锁是为了确保什么?
答案是确保jvm中的变量的。
例如jvm中现在有一个变量,但是有三个进程对他进行修改,或者一个方法,有三个进行同时进行访问,修改其中的变量。最后的结果很难保证是正确的。
利用redis实现分布式锁
其实大家都知道redis实现分布式锁是通过setnx实现的,如果不存在该键的时候可以set成功。我们知道setnx可以设置过期时间,这个时间是一个时间戳,是通过expire命令实现的。但是setnx和expire在一起不是原子的,这时如果有一个极端操作。setnx后,节点挂了,那这个锁就没有过期时间了,锁变成了死锁。
可以通过以下操作:
这里还存在一个极端问题:
master设置成功了,开始给slave传命令了。啪!宕机了。这时哨兵把一个slave搞成了master,那这时其他机器就又能获取到锁了。这个锁也就失效了。
redis大key的理解:
首先说下redis单线程,这里的单线程知道现在仍然是主线程是单线程。但是类似和客户端的链接的io线程、和哨兵链接的线程都不是主线程。
删除大key会导致主线程阻塞,100w的值信息大概删除要1s,但是如果这个大key有1000w条信息,就要10s。那这10s内,各个客户端可能都以为超时掉了。作为补偿,要不然重试,要不然就去查db了,这将导致db压力飙升。