Redis 脑图
2021-08-19 15:02:06 85 举报
AI智能生成
Redis 脑图
作者其他创作
大纲/内容
Redis的安装
打开阿里云把文件copy到software里面
cd /usr/local
mkdir software
tar -zxvf xxx.tar.gz
mkdir software
tar -zxvf xxx.tar.gz
安装gcc-c++
yum install gcc-c++
编译依赖
cd usr/local/software/redis-5.0.10/deps
make hiredis lua jemalloc linenoise
make hiredis lua jemalloc linenoise
编译Redis
cd /usr/local/software/redis-5.0.10
make
make
安装编译之后的文件
mkdir -p /usr/local/redis
make install PREFIX=/usr/local/redis (将redis 安装在该目录里面)
make install PREFIX=/usr/local/redis (将redis 安装在该目录里面)
验证安装是否成功
cd /usr/local/redis/bin
ls
ls
将解压后的redis配置文件copy到/usr/local/redis文件夹下
修改daemonize为yes 后台运行
修改bind 为0.0.0.0
单线程
这里的单线程只是在网络IO和键值对读写上是单线程,其他处理还是会使用多线程,例如AOF
redis里面是单线程,想支持并发连接怎么办
想使用一个单线程去支持高并发,那么线程就不能阻塞
让一个线程去管理多个连接
io多路复用技术
redis是单线程,为什么这么快
redis是单进程单线程模型,避免了线程的切换,可以避免锁,
redis的大量操作是在操作内存
io多路复用
缺点
无法发挥多核cpu的性能
可以通过多开Redis实例完善
Redis是菲关系型数据库,数据与数据之间没有联系
为什么需要多线程
平衡计算机硬件之间的差异
比如cpu要到磁盘读取数据,cpu就需要等待磁盘将数据
放入内存 ,这段时间很长,多线程的话CPU就不需要等待
,直接去处理其他的请求,等到磁盘的数据到内存中,再来处理
该数据
放入内存 ,这段时间很长,多线程的话CPU就不需要等待
,直接去处理其他的请求,等到磁盘的数据到内存中,再来处理
该数据
相关命令
key的相关命令
keys *
获取当前库的所有key
del k
删除key
exists k
判断是否存在key
db的相关命令
select index
切换库
dbsize
查看当前库key的数量
flushdb
清空当前库
flushall
清空所有库0-15(不安全)
Redis的数据类型
String
可做简单的k-v缓存,实现计数器、分布式锁、session共享、分布式ID生成(自增)
redis底层是C,为什么
不用c字符串而用sds
不用c字符串而用sds
获取长度
C字符串并不记录自身长度,想获取长度只能遍历
sds直接获取len即可
内存分配
c字符串每次长度变化都会对数组进行内存重新分配,比较耗时
对sds内容进行修改或者需要扩展时,sds有空间预分配和惰性空间释放
缓冲区安全
C字符串不记录自身长度,不会自动进行边界检查,所以会增加溢出的风险
sds先检查空间是否满足修改所需的要求,如果不满足就先扩容再进行修改
二进制安全
C字符串是以空字符串(\0)结尾,所以字符串中不能包含空字符串,只能保存文本数据
既能保存文本数据,也能保存二进制数据(通过长度判断结束,不受影响)
相关命令
set k v
存放一个k-v对
get k
获得k对应v
mset k1 v1 k2 v2 ...
存放多个k-v
mget k1 k2 k3 ...
获得多个v
setnx k v
当库中有该K时不存。当库中没有改K时存放
非常重要(做分布式锁)
非常重要(做分布式锁)
getset k v
获取值之后 修改该K的V
insc k1
该k1对应的v的值++(v必须是Integer类型)
desc k1
该k1对应的v的值--(v必须是Integer类型)
inscby k1 步长
设置每次走的步长
descby k1 步长
设置每次走的步长
list
list是一个双向链表
应用
实现高性能的分页
实现栈或队列:例如到货通知、邮件发送、秒杀、保存待抢购的商品列表
底层实现
压缩列表(ziplist)
当列表对象痛死满足两个条件时,
列表对象使用ziplist进行存储
列表对象使用ziplist进行存储
列表对象保存的元素数量小于512个
列表对象保存的所有字符串元素长度都小于64个字节
他将所有的元素紧挨着存储,分配的是一块连续的内存
快速列表(quicklist)
由于普通链表指针比较浪费空间且会加重内存碎片化,所以优化为quicklist
特点
将多个ziplist使用双向指针串起来(链表+ziplist)
既满足了快速的插入删除性能,又不会出现太大的空间冗余
相关命令
lpush k v
从左边放
rpush k v
从右边放
lpop k
从左边取第一个
rpop k
从右边取第一个
blpop k timeout
从左边取,没取到的话阻塞timeout时间
brpop k timeout
从右边取,没取到的话阻塞timeout时间
lrange k 0 -1
查看队列
-1代表倒数第一个
-2 代表倒数第二个
实现分页
page size
(page-1)* size
page*size-1
llen k
查看该队列的长度
lrem k count value
count = 0 ,移除队列里面所有与value 值相同的value
count > 0 , 从表头开始搜索,删除数据value的值,删除的个数为count个
count< 0 ,从表尾开始搜索,删除数据为value的值,删除的个数为 count的绝对值个
hash
map 适合存储对象?
因为对象的属性和值,我们可以认为是一个map集合里面的数据!
相比于json串,可单独修改对象的字段
可以快速定位,存储的信息需要被频繁的修改可用hash存储,比如实现购物车
相关命令
hset k field value
存
hget k filed
取
hmset k field value field value
存多个
hmget k field filed
取多个
hgetall k
取得所有的k-v
hkeys k
只取key
hvals k
只取value
set
无序唯一
命令
sadd k v
在k的set 集合里面添加一个v,该v 不能重复
spop k
随机弹出一个
smembers k
K的set集合的所有数据
scard k
K的set集合的长度
sdiff k1 k2 (k1-k2)
减集
sinter k1 k2
交集
sunion k1 k2
并集
zset
写数据带分数,实现排行榜
相关命令
zadd k 分数 成员
添加 可批量添加
zrange k start end
排行 (从低到高)
zreveage k start end
排行 (从高到低)
zrangebyscore k 分数的最小值 分数的最大值
指定分数区间排行(从低到高)
Redis事务
概念
Redis事务的本质是一组命令的集合。事务支持一次命令执行多个命令,一个事务中所有的命令都会被序列化
特点
一次性
顺序性
排他性
没有隔离级别的概念
批量操作在事务提交前放入魂村队列,并不会被实际运行
不保证原子性
Redis中的单条命令是原子性执行的,但事务不保证原子性,且没有回滚
事务中的任意命令执行失败,其余的命令仍会被执行
三个阶段
开始事务
命令入队
执行事务
相关命令
watch k1 k2
监视key,如果事务在被执行前,被监视的key被改动,则事务执行失败
实现乐观锁
multi
标记事务的开始
exec
执行事务
discard
放弃事务
unwatch
取消watch对所有key的监控
相关问题
如果在事务队列中出现编译异常(语法错误),则执行exec命令,所有的命令都不会执行
如果在事务队列中出现运行时异常,则执行exec命令,错误命令抛出异常,其他命令正常执行
Redis设置maxmemory-policy的方式
超过最大的容量后会怎么做
超过最大的容量后会怎么做
volatile-lru
从设置了过期时间的key集合中删除最近没有使用的key
allkeys-lru
通过lru算法删除最近没有使用的key
volatile-lfu
从设置了过期时间的key集合中删除最近使用频率最少的key
allkeys-lfu
在所有key的集合中 删除最近使用频率最少的key
volatile-random
在设置了过期时间的key的集合中随机删除一个key
allkeys-random
在所有key的集合中随机删除一个key
volatile-ttl
在设置了过期时间的key集合中删除即将过期的key
noeviction(Redis默认)
当超过最大容量,不会删除任何key,返回一个错误
LRU(least recently use)算法
最近没有使用算法
不需要额外的存储空间,使用一个双向连表就能实现
如果一个数据在最近一段时间没有被访问到,那么可以认为在将来它被访问的可能性也很小。
因此,当空间满时,最久没有访问的数据最先被置换(淘汰)
因此,当空间满时,最久没有访问的数据最先被置换(淘汰)
LFU(least recently use)算法
最近使用频率最少的key
需要一个能记录key 使用次数的空间,使用ZSet 这样的结构就能实现
如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能
性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰
性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰
过期删除策略
一个key 设置过期时间后(expire k seconds),能自动的删除
一个操作将在未来的某个确定时间发生。
一个操作将在未来的某个确定时间发生。
应用场景
订单的过期取消 (下了一个订单,超过30min没有支付,则自动取消)
key的过期删除(给key设置了一个过期时间,到达这个过期时间后,key能自动的删除)
三种策略
定时删除
定时删除的原理:给每一个设置了过期时间的key分配一个线程,
该线程睡眠了过期时间后,起来删除该key
该线程睡眠了过期时间后,起来删除该key
缺点:当过期的key特别多时,创建的线程也会非常多,特别消耗cpu资源
定期删除
定期删除原理:专门有一个线程监视所有设置了过期时间的key的时间,
如果过期,将该key删除
如果过期,将该key删除
缺点:实时性差一点
惰性删除
惰性删除原理:当用户访问该key 时,会判断该key 是否过期了
如果过期了就删除该key,给用户返回null,如果没有过期就返回value
如果过期了就删除该key,给用户返回null,如果没有过期就返回value
缺点:如果用户一直不访问该key,它就一直不会删除,
会一直占用内存
会一直占用内存
定期删除+惰性删除结合(Redis默认)
可以互相解决缺点
Redis的持久化
RDB
原理
redis会单独创建(fork)一个与当前进程一模一样的子进程来进行持久化
将数据写入到一个临时文件中,待持久化结束后替换上次持久化好的文件
将数据写入到一个临时文件中,待持久化结束后替换上次持久化好的文件
相当于两个rendis进程,这期间
主线程不参与持久化,保证redis的
高性能
主线程不参与持久化,保证redis的
高性能
触发
客户端执行shutdown命令
配置文件中有快照配置,例如:save 900 1 (15分钟内有一次修改)
执行save或bgsave命令
save命令会阻塞主线程,一般不用
bgsava会fork子进程异步持久化
执行flushall命令
特点
优点
恢复的时候比较快,适合大规模的数据恢复
缺点
如遇突然宕机,丢失的数据比较多
如果生成的快照文件比较大会影响redis的性能
AOF
原理
将所有的写命令追加到AOF缓冲区中,根据对应的写入策略向硬盘进行同步操作
由主线程完成
随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的
fork子进程来进行
触发
需手动开启:appendonly yes
线上开启 config set appendonly yes
开启后redis会保留一块内存供缓存使用,默认是1M
aof和rdb同时开启时,只保留save 900 1 减少fork子进程的次数(优化点)
写入策略:appendsync
everysec:每秒同步一次,效率高,可能会丢失1秒的数据【默认也推荐使用】
no:等到缓冲区满了才写入磁盘,次数少,效率高,不安全
追求效率
always:每次发生数据变更时立即同步到磁盘,效率低,安全
追求安全
重写机制
bgrewriteaof
bgrewriteaof
默认配置
auto-rewrite-min-size 64M
aof文件大于64M时重写
由于重写会fork子进程,为了减少重写次数,
这里建议配置5GB以上(优化点)
这里建议配置5GB以上(优化点)
auto-aof-rewirte-percentage 100
指超过优化后,第二次优化文件大小大于第一次优化文件后大小一倍时开始重写
重写后的文件为什么会变小
进程内已超时的数据不再写入文件,而且多条写命令可以合并为一条
新的AOF文件只保留最终数据的写入命令(去掉了修改命令)
特点
优点
相比于RDB,丢失的数据少,不过建议与RDB同时开启
缺点
恢复慢,恢复不稳定,容易bug
redis启动后持久化文件的加载流程
先判断是否开启了AOF,如果存在AOF文件,则直接加载AOF文件
如果找不到AOF文件,则直接启动,不会加载RDB文件
如果没有开启AOF,则会加载RDB文件
生产环境建议AOF和RDB同时使用,RDB做灾难备份
主从复制
概念
主机数据更新后根据配置和策略,自动同步到备机的master/slave机制,
Master以写为主,Slave以读为从
Master以写为主,Slave以读为从
配从不配主
在从机上输入命令SLAVEOF 【主机的ip】 【主机的端口号】
主从复制的一些问题
从机是从头开始复制还是从切入点开始复制
从头复制
从机是否可以写 set?
不能 从机只能读get
主机shutdown后,从机是上位还是原地待命
原定待命,不会变成主机
主机重新启动后,从机是否能够顺利复制
可以
从机shutdown后,情况如何
从机挂了之后,会丢失之前的主从关系,需要重新设置一次主从关系才行
在配置文件里面可以永久的设置主从关系(slaveof),挂了重启再启动,主从关系还会保持
记住命令info replication
查看本机的复制信息
主从复制数据同步的原理
前提
Master和Slave都会维护一个offset和run id ,Slave每秒都会上报自己的offset给master
Master记录在backlog(针对增量复制)中,这样才能知道双方数据是否一致
Slave发送run id 和offset到Master,Master根据情况返回信息(增量/全量)
全量复制
触发时机
Slave从机第一次启动时
Master重启时
复制过程
1.Slave启动时回向Master发送SYNC指令(请求同步)
2.Master收到后通过bgsave保存快照,同时将后续的命令存到缓存中
3.Master将RDB发给Slave,Slave收到文件后先写入到本地磁盘,然后在从本地磁盘加载到内存中
4.最后maser会将内存中的写命令同步给Slave,Slave收到后再执行一遍
增量复制
Master根据Slave发送的同步请求中的offset
在backlog中查询部分丢失的数据,发送给Slave
过期key的处理
Slave不会处理过期key,只会等待Master的过期通知
哨兵模式
概念
哨兵是一个分布式系统,监控主从架构中的节点通过 自动故障转移 保证集群的高可用
主要功能
监控
监控主节点从节点是否正常运行
自动故障转移
当确认主节点宕机后,在从节点中选一个座位主节点,将
其他从节点连接到新的主节点上通知客户端最新的地址
其他从节点连接到新的主节点上通知客户端最新的地址
工作原理
发现Master宕机
哨兵从服务器列表中挑选Master
先过滤掉不在线和响应慢的服务器
然后过滤掉与原Master断开时间最久的
最后比较优先级priority
如果两个服务器优先级一致,那么回去查看从服务器
中数据的offset,offset说明数据最新,选出offset
大的服务器为Master
中数据的offset,offset说明数据最新,选出offset
大的服务器为Master
新Master诞生
哨兵向选举出的新Master发送指令,断开与旧Master的连接
把新Master的ip地址同步到其他Slave节点
以前的Master如果重连了,那么以前的Master会变成新Master的Slave
主从复制的缺点
由于所有的写操作都是现在Master上操作,然后同步更新到Slave上
所以从Master同步到Slave上机器有一定的延迟,当系统很繁忙的时候,
延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重
所以从Master同步到Slave上机器有一定的延迟,当系统很繁忙的时候,
延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重
Redis集群
中心化
意思是所有的节点都要有一个主节点
缺点
中心挂了,服务就挂了
中心处理数据的能力有限,不能把节点性能发挥到最大
特点
就是一个路由作用
去中心化
让每个主机都拥有转发能力
创建集群时,集群节点直接要相互通信,
使用 redis-server的端口+10000 = 新的集群的监听端口
使用 redis-server的端口+10000 = 新的集群的监听端口
哈希槽 Redis集群时怎么样set一个key
执行流程
redis的使用
idea工程
0 条评论
下一页