1、redis的介绍及使用场景
1.1 介绍
⼀个开源的使⽤ ANSI C 语⾔编写、遵守 BSD 协议、⽀持⽹络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语⾔的 API。并且支持多种数据类型,例如string、list、set、sortset、
1.2 官网
https://redis.io/
2、redis支持的数据类型及常见的指令
2.1 通用指令
// 判断key是否存在
exist -> exist key
// 删除key
del -> del key
// 判断key的类型
type -> type key
// 查看key的存活时间
ttl -> ttl key
// 修改key的名称
rename -> rename oldName newName
2.2 数据结构之String(字符串)
2.2.1 应用场景
验证码、计数器、订单重复提交、用户登录信息等
2.2.2 常用命令
set|mset|get|mget|incr|decr|del|setex|setnx
// 设置给定key的值
set -> set key value
// 批量给定key的值
mset -> mset key1 value1 key2 value2
// 获取给定key的值
get -> get key
// 批量获取key的值
mget -> mget key1 key2 key2
// 给定key的值得加1 并且返回新的值
incr -> incr key
// 给定可以的值得增加特定的值,如果可以不存在操作之前key就会被设置为0,在进行增加
incrby -> incrby key amount
// 给定key的值得减1 并且返回新的值
decr -> decr key
// 给定key的值得减少特定的值,如果可以不存在操作之前key就会被设置为0,在进行减
decrby -> decrby key amount
// 给特定的可以设置value及过期时间
setex -> setex key seconds value
// 如果key不存在给key设定值,并返回1,如果不存在返回0
setnx -> setnx key value
*注意:
1)给定value的值得不可以超过512MB
2)key命名规范,不要过长,尽量用对应符号分割例如冒号,业务名:id
2.3 数据结构之List(列表)
2.3.1 数据结构介绍
list为双向链表,插入和删除时间复杂度为O(1)快,查询为O(n)慢。
2.3.2 应用场景
简单队列,列表、定时计算绑定等
2.3.3 常用命令
lpush|rpop|llen|lindex|lrange|rpush|lpop|brpop|lrem
// 给列表头部添加元素
lpush -> lpush key element
// 给列表尾部添加元素
rpush -> rpush key element
// 移除列表第一个元素并返回元素
lpop -> lpop key
// 移除列表最后一个元素并返回元素
rpop -> rpop key
// 查询列表长度
llen -> llen key
// 通过索引获取列表中的元素
lindex -> lindex key
// 获取可以对应列表的指定下标范围的元素,0表示第一个元素,1表示第二个元素,-1表示获取所有元素(lrange key 0 -1)
lrange -> lrange key 0 2
// 移除列表中最后一个元素,如果元素不存在则阻塞元素直到列表存在元素并且弹出为止(timeout 秒值)
brpop -> brpop key1 key2 ... timeout
// 移除列表中指定元素 可以指定元素的个数(count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT )
lrem -> lrem key count value
*注意:
1)存储的都是string类型
2)列表最多可以包含2的32-1次方个元素
2.4 数据结构之set
2.4.1 介绍
将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略,无序集合且集合元素唯一不可重复
2.4.2 应用场景
大数据里面的用户画像的标签集合,共同好友(利用交集,并集,差集)
2.4.3 常用命令
sadd|scard|sdiff|sinter|sismember|srem|sunion|smembers
// 将一个或者多个成员元素添加到指定key的集合中
sadd -> sadd key member1 member2 ...
// 返回结合中元素的数量
scard -> scard key
// 返回指定集合元素中的差集(diff - different 不相同)
sdiff -> sdiff key
// 返回指定集合元素中的交集
sinter -> sinter key
// 返回指定集合元素中的并集
sunion -> sunion key1 key2
// 判断元素是否是指定结合中的元素(存在返回1,不存在返回0)
sismember -> sismember key member
// 返回指定集合内的所有元素
smembers -> smembers key
// 移除指定集合中的指定的元素
srem -> srem key member
*注意:集合是通过哈希表实现的
2.5 数据结构之sortedset
2.5.1 介绍
使用hashmap+跳跃表skipList保证数据存储和有序。用于将一个或多个元素加入到有序的集合当中,如果成员已经是有序的成员,那么更新这个成员的分数值(score),分数可以是整数或者浮点数,有序集合可以看做是在set集合的基础上为集合中的每个元素维护了一个顺序值score,它允许集合内的元素按照score进行排序。
2.5.2 应用场景
商品热销榜单,积分应用榜单等
2.5.3 常用命令
zadd|zcard|zcount|zincrby|zrange|zrevrange|zrevrank|zrank|zrem|zscore
// 向有序集合添加一个或者多个成员,或者更新已经存在成员的分数
zadd -> zadd key score1 member1 score2 member2
// 获取指定有序集合内的元素数量
zcard -> zcard key
// 用于计算指定集合内指定分数区间的成员数量
zcount -> zcount key minScore maxScore
// 向有序集合内指定成员增加分数
zincrby -> zincrby key incrrment member
// 通过索引区间返回有序集合成指定区间内的成员(从小到大),下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
zrange -> zrange key start stop [withscores]
// 与上面基本相同顺序为从大到小
zrevrange -> zrevrange key start stop withscores
// 返回指定集合成员的member排名,其中有序集合成员按照score值递减(从小到大)顺序排列返回对应的索引值(从0开始)
zrank -> zrank key member
// 与zrank相同 排列顺序为从大到小
zrevrank -> zrevrank key member
// 移除集合元素内的一个成员或多个成员
zrem -> zrem key member1 member2 ...
// 返回集合内指定成员元素的分值
zscore -> zscore key member
2.6 数据结构之Hash(k-v)
2.6.1 介绍
是一个string类型的field和value的映射表,hash特别适合用于存储画像
2.6.2 应用场景
购物车存储,用户对象
2.6.3 常用命令
hset|hget|hgetall|hdel|hexists|hincrby|hmset|hmget
// 设置指定key的集合中指定的字段的值
hset -> hset key field value
// 获取指定key的field元素
hget -> hget key field
// 获取指定key的全部元素
hgetall -> hgetall key
// 从key指定的集合中移除指定的的元素
hdel -> hdel key field
// 返回集合中field是否存在 存在返回1不存在返回0
hexists -> hexists key field
// 增加key指定的哈希集钟指定字段的数据,如果是-1,则是递减
hincrby -> hincrby key field increment
// 批量设置key中多个field的值得
hmset -> hmset key field1 value1 field2 value2
// 批量获取指定key内多个field的值
hmget -> hmget key field1 field2
3、缓存击穿,穿透,雪崩及常见解决方案
3.1 击穿
3.1.1 介绍
缓存内没有,但数据库中有数据的情况为击穿
3.1.2 预防
* 如果是热点数据设置热点数据不过期
* 定时更新缓存
3.2 穿透
3.2.1 介绍
缓存内没有、数据库内也没有
3.2.2 预防
* 接口增加校验,校验数据合法性
* 可以将不存在的key 设置为null,并设置短暂的过期时间
* 通过通过位图bit或布隆过滤器实现拦截
3.3 雪崩
3.3.1 介绍
大量的key设置了相同的过期时间,导致缓存在同一时间全部失效,造成大连db请求,压力剧增
3.3.2 预防
* 设置随机过期时间
* 热点数据永不过期
* 定时任务定期更新缓存
4、redis的持久化
4.1 介绍
redis 是内存数据库,如果没有设置持久化redis重启后会出现数据丢失,因此将开启redis的持久化功能,将数据保存在硬盘上,当重启后可以从硬盘中恢复数据,主要有两种持久化方式RDB(redis database)和AOF(append only file).
4.2 RDB(redis database)
4.2.1 介绍
在指定的时间间隔内将内存钟的数据集以快照的方式写入硬盘,生成dump.rdb文件
4.2.2 备份方式和原理
1) save
调用save,会阻塞redis服务器,执行save命令期间不可以执行其他命令,知道rdb动作完成为止。
2) bgsave
调用bgsave,会创建响应的fork子进程,由子进程进行,在后台异步进行快照操作
3) 自动化配置
修改配置文件来完成,配置出发redis rdb持久化条件(save m n 表示m秒内存在n次修改时自动触发bgsave)。
4)主从
部署主从架构,从服务器进行同步数据的时候,会发送sync执行同步操作,主服务器就会执行bgsave
4.2.3 优缺点
优点:
* 全量备份,适用于进行备份和灾难恢复
* 在大数据量恢复的试试比aof快
* 生成的是一个二进制压缩文件
缺点:
* 每次快照是一次全量备份,fork子进程会后台进行操作,存在开销,数据集大的情况会很耗时间
* 在快照持久化期间修改的数据不会被保存,可能存在数据丢失
4.2.4 核心配置
dir:持久化文件路径
dbfilename : 文件名字(xxx.rdb)
4.3 AOF(append only file)
4.3.1 介绍
追加文件的方式,以独立日志的方式记录记录每次写的命令,重启时在重新执行aof文件中的命令达到恢复数据的目的,写入过程党纪,也步影响之前的数据,可以通过redis-check-aof检查修复
4.3.2 备份方式和原理
通过记录每次执行命令的方式进行备份(3种方式)
1)appendfsync always
每次有数据修改发生时都会写入aof文件,存在性能消耗
2) appendfsync eversec
每秒中同步一次
3) appendfsync no
不主动同步由操作系统自动调度刷磁盘,性能是最好,但也是最不安全的
核心原理
* redis 每次写入命令会之最佳到aof_buf(缓冲区)
* aof缓冲区根据对应的策略向硬盘做同步操作
* 高频aof会带来影响
4.3.3 核心配置
appendonly yes 开启,默认不开启
appendfilename 文件名(默认文件名appendonly.aof路径与rdb路径相同)
4.3.4 aof重新rewrite
1)介绍
* aof文件随着追加会越来越大,需要定期对aof文件进行重写达到压缩
* 旧的aof文件含有无效命令会被忽略,保留最新的数据命令
* 多条命令可以合并成一个命令
* aof重写会降低文件的占用空间
* 更小的aof文件可以更快的被redis加载
2)rewrite重写配置
手动触发:
直接调用bgrewrireaof命令
自动触发:
配置auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage参数
auto-aof-rewrite-min-size: 表示文件最小重写大小,当文件大于该值时才可以重写,默认64m
uto-aof-rewrite-percentage: 表示当前aof文件空间和上一次重写aof文件空间的比值
4.3.5 优缺点
优点:
* 数据更加安全
* 当aof文件太大时,redis能够在后台自动重写aof文件
* 可以包含所有的操作日志
缺点:
* aof文件通常比数据集的等效rdb文件大
* 根据恢复的策略,恢复的时候aof可能比rdb慢
5、redis key过期时间删除策略
5.1 背景
-
redis的key配置过期时间是怎么被删除的?
-
redis的数据明明过期了,怎么还占用这内存?
-
redis 就只能用10g,往里面写20g的数据会发生啥,会淘汰那些数据?
5.2 过期策略
5.2.1 定期删除
每隔一段时间就随机抽取⼀些设置了过期时间的key,检查其是否过期,如果过期就删除,地当期删除可能会导致很多过期key到了时间并没有被删除掉
5.2.2 惰性删除
当客户端尝试访问时,key会被发现并且主动的过期,每次从键空间钟获取键时都会检查取得的key是否过期,如果过期的话就会删除key
备注:使用惰性删除和定期删除这两种策略,通过配合使用服务器可以合理的使用cpu时间和避免浪费内存空间之间取得平衡
5.3 redis的key内存淘汰策略
5.3.1 策略
-
volatile-lru(least recently used)
最近最少使用算法,从设置了过期时间的键中选择【最长时间未使用】的key清除掉 -
volatile-lfu(least frequently used)
最近最不经常使用算法,从设置了过期时间的key中选择某段时间之内【使用频次】最小的key清除掉 -
volatile-ttl
从设置了过期时间key中选择过期时间最早的key清除掉 -
volatile-random
从设置了过期时间的key中,随机选择key进行清除 -
allkeys-lru
最近最少使用算法,从所有key中选择最长时间未使用的key清除掉 -
allkeys-lfu
最近最不经常使用算法,从所有key中选择某段时间之内【使用频次】最小的key清除掉 -
allkeys-random
从所有key钟随机选择key进行清除 -
noeviction
不做任何清理工作,在内存超过限制之后,所有写的操作都会返回错误,读操作正常
设置策略
config set maxmemory_policy volatile-lru
6、redis的高可用
6.1 主从复制
6.1.1 意义
- 相对于单机部署可以提高响应的可靠性,更好的利用cpu
- 扩展主节点的读能力,分担主节点的压力
- 一旦主节点宕机,从节点作为住节点的备份可以随时顶上来使用(可以一主多从)
6.1.2 架构
6.1.3 主从原理
主从复制分为2种(主从首次时进行全量同步,全量结束后,会进行增量同步):
1)全量同步
- 主节点会开启一个后台进行用于生成一个rdb文件
- 主服务器会缓存所有接收到客户端的写命令,当后台进程处理完毕后,会把rdb文件传递给从节点
- 从节点会将rdb文件保存到硬盘并通过读改文件将数据加载到内存
- 后续住节点服务器会将此后缓存的命令通过redis传输协议发送给从节点服务器
- 从节点服务器将这些命令依次作用于自己本地的数据集上,完成数据的一致性
2)增量同步
- 从服务器完成全量同步后,开始正常工作,主服务器发生操作同步到服务器
- 主服务器每次执行一个命令都会向从服务器发送相同的命令,从服务器收到命令并执行
注意:从节点不会让key过期,而是主节点过期后将命令发送给从节点,从节点才会删除
6.2 哨兵模式(sentinel)
6.2.1 介绍
哨兵是一个独立的进程,通过发送命令给多个节点,等待其他redis服务器响应,从而达到监控运行的多个redis实例运行情况,当哨兵监测到主节点宕机,会自动将从节点切换为主节点,通过通知其他服务器,修改配置文件切换主机。解决主从架构故障自动迁移的问题。
6.2.2 意义
1) 监控
哨兵会不断的检查你的主服务器和从服务器是否运行正常
2)提醒
当被监控的某个redis服务器出现问题的时候,哨兵可以通过api向管理员或者其他应用程序发送响应通知
3)故障转移
- 当主服务器不能正常工作时,哨兵会开始一次故障转移,会将从服务器的一个节点升级为主服务器,并让其他从服务器向新的主服务器复制
- 当客户端访问失效的主服务器时,集群也会向客户端返回新主服务的地址
6.2.3 架构
6.2.4 多哨兵模式
一个哨兵进程监控redis会出现单点问题,所以一般采用多个哨兵进行监控,每个哨兵之间还会进行监控,从而达到多哨兵的模式
1)主观下线(Subjectively down 简称:SDOWN)
- 是单个哨兵对服务器做出的判断,例如网络问题无法接收到通知
- redis服务器在没有接收到,dowm-after-miliseconds选项所指定的时间内,对给它发送ping命令的哨兵返回一个有效回复(valid reply),那么哨兵就会将这个服务器标识为主观下线(直白说哨兵主动跟服务器联系,但是没有收到回复就认为你下线了,实际并不一定下线)
2)客观下线(Objectively dowm 简称 ODOWN)
- 多个哨兵对同一个redis服务器做出的sdown判断,并通过哨兵 is-master-down-by-addr 命令互相交流之后得出的服务器下线判断
- 一个哨兵通过想另一个哨兵发送 is-master-down-by-addr 命令来寻味对方是否认为给定的服务器已下线(白话:张三问李四,服务器a你觉得他下线没,李四说下线了)
- 仅仅使用与主服务器
3)仲裁(qurem)
- 哨兵在给定的时间内从其他哨兵哪里接收到【足够数量】的主服务器下线的报告,那么哨兵就会将主服务器的状态从主观下线变成客观下线
- 【足够数量】为配置文件内的值,一般配置的是 总哨兵个数的一半+1,例如3个哨兵设置为2
- down-after-milliseconds 是哨兵在超过规定的时间依旧没有得到响应后,会自己认为不可以
- 当主观下线的哨兵达到设置的配置数量时,就会发起一次投票,进行failover
6.3 集群模式(cluster)
6.3.1 介绍
采用无中心架构设计,每隔节点保存的数据和整个集群的状态,每隔节点都和其他节点连接互相通信,
至少6个节点才能保证搞可用(3主3从 主从节点自动分配),数据分散存储在每隔节点上
6.3.2 数据分片和虚拟哈希槽
- 哈希槽(slot):redis预先分配好16384个槽,当需要在redis集群钟放置一个key-value时,根据CRC16(key)%
16384的值 决定将一个key放在哪个槽中 - 流程
以3个主节点为例,将16384个槽分配到3个节点,节点1(0-5460)节点2(5461-10922)节点3(10923-16383)
对哟啊存储或查找的key进行crc16哈希运算得到一个值,并通过16384取模运算,判断这个值在哪个范围区间
后续补充部署实操部分…
敬请期待!!!