Redis思维导图
2020-05-07 19:12:00 0 举报
AI智能生成
redis思维导图
作者其他创作
大纲/内容
定义
内存结构化数据存储(数据库、缓存、消息队列)
每个操作系统中可以安装多个redis实例,每个redis实例默认有0-15 16个库
单进程、单线程(计算线程)
与memcache对比
1、memcache的value无类型、redis的value有类型
2、memcache的value中可以存储json格式内容(可以表示任意类型),
但是每次都需将value完整取出来,到客户端发生计算。而redis支持value的各种操作
但是每次都需将value完整取出来,到客户端发生计算。而redis支持value的各种操作
value类型
string
字符串
set
del
mset
get
mget
append
setrange
getrange
strlen
getset
object encoding
del
mset
get
mget
append
setrange
getrange
strlen
getset
object encoding
set k1 abc [nx|xx]
nx:当k1不存在时该设置成功
xx:当k1存在时该设置成功
nx:当k1不存在时该设置成功
xx:当k1存在时该设置成功
二进制安全
内容是以字节流存储,不是已字符流存储。
保证原来的内容的字节完整保存
内容是以字节流存储,不是已字符流存储。
保证原来的内容的字节完整保存
数值
incr
decr
incrby
incrbyfloat
decrby
decrbyfloat
decr
incrby
incrbyfloat
decrby
decrbyfloat
bitmap
setbit k offset v
按照二进制位设置value,1byte=8bit
bitcount k start end
按照字节的位置统计
bitop operation destkey k1 k2
场景
统计客户一年内登录app的天数,及任意时间窗口内的登录次数
使用bitmap,客户id作为key,每天作为二进制位,每天登录行为记到二进制位里
客户1登录:
setbit user1 1 1
setbit user1 2 1
setbit user1 364 1
统计:
bitcount user1 start end
使用bitmap,客户id作为key,每天作为二进制位,每天登录行为记到二进制位里
客户1登录:
setbit user1 1 1
setbit user1 2 1
setbit user1 364 1
统计:
bitcount user1 start end
统计某一时间范围内有多少客户登录app
使用bitmap,日期作为key,每一个客户做为一个二进制位,每天登录的行为记为1,存到改二进制位里
客户1登录:
setbit 20200101 1 1
setbit 20200102 1 1
客户2登录:
setbit 20200102 2 1
统计:
bitop or destkey 20200101 20200102
bitcount destkey 0 -1
使用bitmap,日期作为key,每一个客户做为一个二进制位,每天登录的行为记为1,存到改二进制位里
客户1登录:
setbit 20200101 1 1
setbit 20200102 1 1
客户2登录:
setbit 20200102 2 1
统计:
bitop or destkey 20200101 20200102
bitcount destkey 0 -1
布隆过滤器
判断某个元素是否存在
1、通过多个不同的hash算法,将内容映射成hash值,存储到对应的bit上
2、将另外一个值通过不同的hash算法,映射到bit上,有可能覆盖第一步的bit,也有可能是新的bit
3、判断一个值是否存在,通过不同的hash算法算出该值的hash值,到bit上寻找,如果存在一位bit上的
值为0,则表示该值不存在,如果所有的bit都是1,则表示该值有可能存在
1、通过多个不同的hash算法,将内容映射成hash值,存储到对应的bit上
2、将另外一个值通过不同的hash算法,映射到bit上,有可能覆盖第一步的bit,也有可能是新的bit
3、判断一个值是否存在,通过不同的hash算法算出该值的hash值,到bit上寻找,如果存在一位bit上的
值为0,则表示该值不存在,如果所有的bit都是1,则表示该值有可能存在
list
栈
同向命令
同向命令
lpush
lpop
lpop
rpush
rpop
rpop
队列
反向命令
反向命令
lpush
rpop
rpop
rpush
lpop
lpop
数组
索引命令
索引命令
lrange k 0 -1
lindex
lset
lrem
linsert
ltrim
lindex
lset
lrem
linsert
ltrim
redis中的string、list都有正负向索引
阻塞、单波队列
客户端FIFO
客户端FIFO
blpop
brpop
brpop
hash
hset
hget
hmset
hmget
hkeys
hvals
hgetall
hget
hmset
hmget
hkeys
hvals
hgetall
set
sadd
spop
smembers
spop
smembers
交集
sinter
sinterstore
sinterstore
并集
sunion
sunionstore
sunionstore
差集
sdiff
sdiffstore
sdiffstore
随机事件
srandmember k 5 -5 10 -10
如果count为正数,则取出一个去重的结果集(不能超过已有集)
如果count为负数,则取出一个重复的结果集(一定会满足count数量)
如果count为正数,则取出一个去重的结果集(不能超过已有集)
如果count为负数,则取出一个重复的结果集(一定会满足count数量)
场景1:
抽奖,奖品为5个,用户可以大于5个,可以小于5个
count>0:每人只会抽取一次
count<0:每人可以重复抽取
抽奖,奖品为5个,用户可以大于5个,可以小于5个
count>0:每人只会抽取一次
count<0:每人可以重复抽取
spop
随机取出一个
随机取出一个
sorted set
物理内存左大右小,不随命令发生变化
集合操作
zadd
zrange
zrevrange
zscore
zrank
zrange
zrevrange
zscore
zrank
并集、交集
zinterstore、zunionstore,重点:权重/聚合指令
zinterstore、zunionstore,重点:权重/聚合指令
实现原理
skip list
跳跃表
跳跃表
pipelining
echo -e 'set k1 99\nincr k1\nget k1' | nc localhost 6379
cat 123.txt | redis-cli --pipe
pubsub
publish channel message
subscribe channel
psubscribe
subscribe channel
psubscribe
场景
直播
1、通过线性方法+事物
2、通过另外两个客户端订阅,写入sorted set 和 db
1、通过线性方法+事物
2、通过另外两个客户端订阅,写入sorted set 和 db
历史数据
db
最近三天数据
sorted set
实时数据
pub/sub
transactions
multi
exec
exec
1、multi开启事物,然后发送指令,这些指令不会执行,而是放到队列queue中,当发送exec指令时,这些指令才会被执行
2、当同时有多个客户端发送事物指令时,谁的exec指令先到达redis-server,则谁的指令会先执行
2、当同时有多个客户端发送事物指令时,谁的exec指令先到达redis-server,则谁的指令会先执行
watch
watch k
观察key的变化(cas),如果发现k的值变化了,则watch接下来的事物操作不会被执行
观察key的变化(cas),如果发现k的值变化了,则watch接下来的事物操作不会被执行
缓存回收
内存配置
配置最大内存,为0时则无内存限制:
maxmemory 100mb
32位机器默认内存3GB
maxmemory 100mb
32位机器默认内存3GB
回收策略
配置
maxmemory-policy
maxmemory-samples 5
maxmemory-samples 5
通过对配置的样本个数采样分析,基于他们的LRU访问时间
淘汰最久没有访问的key。
redis实现了一个LRU时钟,每个key在被访问时,会记录下服务器LRU时钟,
回收时比较key的LRU时钟和服务器的LRU时钟,间隔长的会被淘汰
如果maxmemory-samples配置的越大,则越接近理论的LRU算法,但是会
损耗CPU指令集
淘汰最久没有访问的key。
redis实现了一个LRU时钟,每个key在被访问时,会记录下服务器LRU时钟,
回收时比较key的LRU时钟和服务器的LRU时钟,间隔长的会被淘汰
如果maxmemory-samples配置的越大,则越接近理论的LRU算法,但是会
损耗CPU指令集
算法
noeviction
当内存已满,客户端有新的命令达到,需要更多内存时,直接返回错误
allkeys-lru
allkeys-lfu
allkeys-lfu
所有的key参与
LRU回收最远时间使用的key
LFU回收最不频繁使用的key
LRU回收最远时间使用的key
LFU回收最不频繁使用的key
volatile-lru
volatile-lfu
volatile-lfu
在过期集合里的key参与
LRU回收最远时间使用的key
LFU回收最不频繁使用的key
LRU回收最远时间使用的key
LFU回收最不频繁使用的key
allkeys-random
所有的key参与,随机回收
volatile-random
在过期集合里的key参与,随机回收
volatile-ttl
回收在过期key的集合里,优先回收过期时间短的key
persistence
RDB
描述
持久化数据到磁盘,优点恢复快、缺点容易丢失数据。
需要时点性的写入RDB, 8点-9点-10点
需要时点性的写入RDB, 8点-9点-10点
时点性
如果8点持久化一个rdb,但是redis中的数据量很大,
那么持久化的时间会很长,此时redis的数据变化了,
如何保证时点性
1、父子进程中的数据是隔离的,如果想子进程访问到父进程
的数据,在父进程中对数据使用export,则可以在子进程中
访问,如果父子进程都对该数据修改,两边不同步。
2、进程中的数据其实是对内存的一个映射,不同进程中指针都是对
这一块内存数据的映射
3、linux中提供fork系统调用,用于创建子进程,数据只有一份,
复制的是指针,由于两个进程中的数据不是同步的,所以主进程还对外
提供读写,而子进程只保留了fork那个时刻点的数据,保证了RDB的
时点性
4、linux中fork系统调用提供了一种copy-on-write(写时复制),达到
不同进程中的数据保持一致
如果8点持久化一个rdb,但是redis中的数据量很大,
那么持久化的时间会很长,此时redis的数据变化了,
如何保证时点性
1、父子进程中的数据是隔离的,如果想子进程访问到父进程
的数据,在父进程中对数据使用export,则可以在子进程中
访问,如果父子进程都对该数据修改,两边不同步。
2、进程中的数据其实是对内存的一个映射,不同进程中指针都是对
这一块内存数据的映射
3、linux中提供fork系统调用,用于创建子进程,数据只有一份,
复制的是指针,由于两个进程中的数据不是同步的,所以主进程还对外
提供读写,而子进程只保留了fork那个时刻点的数据,保证了RDB的
时点性
4、linux中fork系统调用提供了一种copy-on-write(写时复制),达到
不同进程中的数据保持一致
配置
文件默认名称:
dump.rdb
开启:
save "" 不开启
save 900 1
save 300 10
save 60 10000
60秒如果有10000个key发生变化,则触发持久化
如果没有10000个key变化,到了300秒,有10个key发生变化,则触发持久化
如果没有10个key变化,到了900秒,有1个key发生变化,则触发持久化
dump.rdb
开启:
save "" 不开启
save 900 1
save 300 10
save 60 10000
60秒如果有10000个key发生变化,则触发持久化
如果没有10000个key变化,到了300秒,有10个key发生变化,则触发持久化
如果没有10个key变化,到了900秒,有1个key发生变化,则触发持久化
命令
save
bgsave
bgsave
AOF
描述
记录客户端每笔的操作到aof文件中,同时开启RDB和AOF时,只有AOF会起作用
配置
开启:
appendonly yes
文件默认名称:
appendonly.aof
持久化aof三种方式,redis默认采用第二种
appendfsync always(每有一次操作,刷新到磁盘,同步)
appendfsync everysec(每秒一次,刷新到磁盘,同步)
appendfsync no(不由redis触发刷新到磁盘,由内核触发写入磁盘,异步)
aof 重写机制:
auto-aof-rewrite-percentage 100(当已经重写后会记录下aof大小,如果再次达到100%*64mb,则再次触发重写)
auto-aof-rewrite-min-size 64mb(达到64mb会触发aof自动重写)
appendonly yes
文件默认名称:
appendonly.aof
持久化aof三种方式,redis默认采用第二种
appendfsync always(每有一次操作,刷新到磁盘,同步)
appendfsync everysec(每秒一次,刷新到磁盘,同步)
appendfsync no(不由redis触发刷新到磁盘,由内核触发写入磁盘,异步)
aof 重写机制:
auto-aof-rewrite-percentage 100(当已经重写后会记录下aof大小,如果再次达到100%*64mb,则再次触发重写)
auto-aof-rewrite-min-size 64mb(达到64mb会触发aof自动重写)
内容写入磁盘的方式:
1、内核有一个buffer(4K),当数据填满buffer时,由内核触发写到磁盘,有可能丢失一个buffer的数据
2、由程序调用flush,强制内核写入磁盘,每写一次调用一次内核,成本高
3、程序每秒触发一次flush,最差的情况为,内核buffer快要满4K,还没到1秒,此时掉电,则会丢失接近一个buffer的数据
1、内核有一个buffer(4K),当数据填满buffer时,由内核触发写到磁盘,有可能丢失一个buffer的数据
2、由程序调用flush,强制内核写入磁盘,每写一次调用一次内核,成本高
3、程序每秒触发一次flush,最差的情况为,内核buffer快要满4K,还没到1秒,此时掉电,则会丢失接近一个buffer的数据
文件格式
*3
$3
set
$2
k1
$1
a
*3 表示此次操作会保存至3行记录
$2 表示此行记录有2个字符长度
$3
set
$2
k1
$1
a
*3 表示此次操作会保存至3行记录
$2 表示此行记录有2个字符长度
命令
bgrewriteaof:重写AOF文件,会合并之前的操作日志
4.0以上版本
支持RDB和AOF混合方式
aof-use-rdb-preamble yes
AOF文件是以REDIS开头
aof-use-rdb-preamble yes
AOF文件是以REDIS开头
4.0以下版本
AOF只记录操作日志
RDB只保存历史镜像
RDB只保存历史镜像
cluster
主从复制
描述
一主两从,主节点可读可写,从节点只能读
在从节点上执行:
老版本:slaveof host port
新版本:replicaof host port
如果主挂了,手动将从节点切换成主:
replicaof no one
在从节点上执行:
老版本:slaveof host port
新版本:replicaof host port
如果主挂了,手动将从节点切换成主:
replicaof no one
配置
replica-serve-stale-data yes
在从节点同步主节点数据时,是否对外提供读服务
replica-read-only yes
是否为只对外提供读服务
repl-diskless-sync no
rdb是走磁盘还是直接走网络
repl-backlog-size 1mb
增量日志
ha(哨兵)
描述
监控(Monitoring)
提醒(Notification)
自动故障迁移(Automatic failover)
提醒(Notification)
自动故障迁移(Automatic failover)
配置
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel monitor mymaster 127.0.0.1 6379 2
启动
redis-server /path/to/conf --sentinel
或
redis-sentinel
或
redis-sentinel
多个哨兵之间通信是通过主节点的发布/订阅实现的
shading分片
1、hash取模 modula
2、随机 random
适用于消息队列
3、一致性hash ketama
适用于缓存
1、虚拟一个很大的hash节点环 0-2^32
2、每个node节点根据关键词算出hash值,对应到hash环的节点中,成为物理节点
3、当有数据过来时,根据hash算法得到hash值,拿到一个比该值大的最邻近的一个物理节点,将key推送到该节点上
4、当有新节点加入时node03,node03有可能会落在node02之前,则有部分原本落在node02的数据,查询时
会从node03去查询,则会查询不到,会造成缓存击穿,查询会落到数据库中。有两种方案:
4.1 查询时如果当前节点查询不到,则往后多查一个节点,再次没有的话,则会缓存击穿
4.2 此种模式只用于缓存,不考虑上述问题,在从之前节点无法查询时,则会从数据库中查询,同时将缓存写入node03
而之前node02节点上的数据可以通过配置LRU、LFU进行缓存淘汰
2、每个node节点根据关键词算出hash值,对应到hash环的节点中,成为物理节点
3、当有数据过来时,根据hash算法得到hash值,拿到一个比该值大的最邻近的一个物理节点,将key推送到该节点上
4、当有新节点加入时node03,node03有可能会落在node02之前,则有部分原本落在node02的数据,查询时
会从node03去查询,则会查询不到,会造成缓存击穿,查询会落到数据库中。有两种方案:
4.1 查询时如果当前节点查询不到,则往后多查一个节点,再次没有的话,则会缓存击穿
4.2 此种模式只用于缓存,不考虑上述问题,在从之前节点无法查询时,则会从数据库中查询,同时将缓存写入node03
而之前node02节点上的数据可以通过配置LRU、LFU进行缓存淘汰
虚拟节点 如果节点个数太少,会出现数据倾斜,解决方法:
将节点拼接字符串方式,再次散列成物理节点,这些节点成为虚拟的节点
将节点拼接字符串方式,再次散列成物理节点,这些节点成为虚拟的节点
代理
swemproxy
predixy
codis
redis_cluster
模型
槽位 slots(16384个)
如果client连接的时redis2实例,到redis2中对key操作hash(key)%16384=12000
则会到该redis实例中的映射表查找,发现应该时redis3实例,则redis2会向客户端
回送消息让client重定向到redis3实例
如果client连接的时redis2实例,到redis2中对key操作hash(key)%16384=12000
则会到该redis实例中的映射表查找,发现应该时redis3实例,则redis2会向客户端
回送消息让client重定向到redis3实例
无主模型
命令
1、create-cluster start
2、create-cluster create
2、create-cluster create
1、create-cluster stop
redis-cli --cluster
redis-cli --cluster info
redis-cli --cluster check
redis-cli --cluster info
redis-cli --cluster check
redis-cli reshard
用于解决数据倾斜,迁移某些redis实例下的某些槽位至另外redis实例下
使用细节
如果使用普通客户端连接,redis-cli -p ,get key 如果key不在当前redis实例,则会提示报错,让去对应redis实例中操作
应该使用redis-cli -c -p 命令启动连接redis集群的客户端,上述问题会自动重定向到正确的redis实例中
应该使用redis-cli -c -p 命令启动连接redis集群的客户端,上述问题会自动重定向到正确的redis实例中
击穿
现象
当有一个或几个key失效,此时客户端有大量并发请求这个可以,此时会造成所有的请求到db,造成缓存击穿
解决方法
步骤:
1、所有的客户端往redis中执行指令setnx,如果key为空,会设置成功,否则失败
2、只有setnx执行成功的才会到请求到数据库中,请求完数据库后,重新设置请求的key值,
其他客户端睡眠一个随机时间,重新获取key,如果能拿到key的值返回,拿不到则重复1步骤
3、有一个问题,如果setnx成功的客户端突然挂了,此时该操作中断了,没有设置key的值也没有
将setnx的值销毁
4、给setnx加个过期时间,但是这个过期时间不好把握,如果设置短了,客户端还没请求完db,setnx
已经过期了,其他客户端会重新setnx
5、加一个线程,用户检测客户端请求db的操作,来延长setnx的过期时间
1、所有的客户端往redis中执行指令setnx,如果key为空,会设置成功,否则失败
2、只有setnx执行成功的才会到请求到数据库中,请求完数据库后,重新设置请求的key值,
其他客户端睡眠一个随机时间,重新获取key,如果能拿到key的值返回,拿不到则重复1步骤
3、有一个问题,如果setnx成功的客户端突然挂了,此时该操作中断了,没有设置key的值也没有
将setnx的值销毁
4、给setnx加个过期时间,但是这个过期时间不好把握,如果设置短了,客户端还没请求完db,setnx
已经过期了,其他客户端会重新setnx
5、加一个线程,用户检测客户端请求db的操作,来延长setnx的过期时间
穿透
现象
大量客户端请求了redis缓存中不存在的数据,请求直达db
解决方法
布隆过滤器
缺点:不能删除
布谷鸟过滤器
布隆过滤器+
雪崩
现象
缓存中大量key设置了固定的过期时间,大量并发的请求到达,会直接到db中
解决方法
与时点性无关:可以设置随机的过期时间
与时点行相关:在客户端请求时加上随机的时延,可以参考击穿方案
分布式锁
1、setnx
2、设置过期时间
3、创建线程延长锁过期时间
2、设置过期时间
3、创建线程延长锁过期时间
0 条评论
下一页