Redis基础

Redis

主流功能与应用

​ 1、分布式缓存,挡在mysql数据库之前。

与传统数据库关系(MySQL):

​ Redis是key-value数据库(NoSql)一种,mysql是关系型数据库;

​ Redis数据操作主要在内存,二musql主要存储在磁盘;

​ Redis在某一些场景使用中更明显优于musql,比如计数器、排行榜等方面;

​ Redis通常用于一些定场景,需要与mysql一起配合使用;

​ 两者并不是相互替换和竞争关系,而是共用和配合使用;

​ 2、内存存储和持久化(RDB+AOF)Redis支持异步将内存中的数据写到硬盘上,同时不影响句许服务。

​ 3、高可用架构搭配:单机、主从、哨兵,集群。

​ 4、缓存穿透、击穿、雪崩。

​ 5、分布式锁。

​ 6、队列。

​ 7、排行版+点赞。

优势

​ 1)性能极高:Redis能读的速度是110000次/秒,写的速度是81000次/秒;

​ 2)Redis数据类型丰富,不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash 等数据结构的存储;

​ 3)Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用;

​ 4)Redis支持数据的备份,即master-slave模式的数据备份;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i907uWgy-1686448682599)(C:\Users\yun\AppData\Roaming\Typora\typora-user-images\image-20230514162717196.png)]

Redis文档:

​ Redis源码地址:github.com/redis/redis

​ Redis命令参考:doc.redisfans.com

Redis安装步骤

​ 1、下载获取redis压缩包,将其放到LInux目录/opt mv source new path --移动文件

​ 2、/opt 目录解压redis tar -zxvf source --解压文件

​ 3、进入目录 cd source --进入文件夹

​ 4、在redis目录下执行make命令 make & make install

​ 5、查看默认安装目录:usr/local/bin

​ redis-benchmark:性能测试工具,服务启动后运行该命令,查看自己本子性能

​ redis-check-aof:修复有问题的AOF文件

​ reids-check-dump:修复有问题的dump.rdb

​ redis-cli:客户端,操作入口

​ redis-sentinel:redis集群使用

​ redis-server:redis服务器启动命令

​ 6、将默认的redis.config拷贝到自己定义好的一个路径下,比如/myredis mkdir myredis – 创建一个文件

cp redis.config /myredis ----------------默认不修改初始配置文件,而是新建一个配置文件

​ 7、修改/Myredis 目录下redis.config配置文件作为初始化设置

​ daemonize no --> deemonize yes //后台运行

​ protected-mode yes --> protected-mode no //保护模式改为no

​ bind 127.0.0.1 -->直接注释(默认bind127.0.0.1只能本机访问)或者改为本机IP地址,否则影响远程IP连接

​ 添加redis密码 --> requirepass 密码

​ 8、启动服务

​ 9、连接服务 redis-cli -a 密码 -p 端口号

​ 10、关闭

​ 单实例关闭:redis-cli -a 密码 shutdown 多实例关闭,指定端口号关闭:redis-cli -p 端口号 shutdown

Redis十大数据类型

数据类型一般指的Value的数据类型,key的类型都是字符串。

Key常用命令

​ **keys *** – 查看当前库所有key

exists key --判断某个key是否存在

type key --查看key类型

del key --删除指定key的数据

unlink key --非阻塞删除,仅仅将keys从keyspace元数据中删除,真正的删除会在一步中

ttl key --查看还有多少秒过期,-1表示永不过期,-2表示已过期

expire key 秒钟 --为给定的key设置过期时间

move key dbindex 【0-15】 --将当前数据库的key移动到给定的数据库db当中

dbsize --查看当前数据库key的数量

flushdb --清空当前库

flushingall – 通杀全部库

命令不区分大小写,Key区分大小写

1、字符串(String)

​ String是redis最基本的类型,一个key对应一个value;

​ String类型是二进制安全的,redis的String可以包含任何数据,比如jpg图片或者序列化对象;

​ string类型是redis最基本的数据类型,一个redis中字符串value最多可以使512M;

set key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds | KEEPTTL]
	NX:键不存在的时候设置键值
	XX:键存在的时候设置键值
	GET:返回指定键原本的值,若键不存在返回nil
	EX seconds:以秒为单位设置过期时间
	PX milliseconds:以毫秒为单位设置过期时间
	EXAT timestamp:设置以秒为单位的UNIX时间戳对应的时间为过期时间	
	PXAT millseconds-timestamp:设置以毫秒为单位的UNIX时间戳所对应的时间为过期时间
	KEEPTTL:保留设置前指键的生存时间
--批量设置key/获取key
mset key value [key value]	--设置多个key值
mget key [key]	--获取多个键值
msetnx	--不存在时设置
--获取指定区间范围内的值
getrange key startIndex endIndex	-- 获取指定区间范围内的值两端闭合
setrange key offset(偏移量) value		--将value插入到key的值的指定位置
--数值增减 一定要是数字才能加减
incr key	--加一
incrby key increment	--加指定步长
decr key	--减一
decrby key decrement	--减指定步长
--获取字符串长度和内容追加
strlen k1	--获取字符长度
append k1 value	 --字符串尾追加内容
--分布式锁
setnx key value
set(set with expire)键秒值/setnx(set if not exist)
--先get 后set
getset key value	--将给定的key设置value,返回key的旧值

应用场景:抖音无线点赞某个视频或者商品,点一次加一次;是否喜欢文章

2、 列表(List)

​ redis列表是简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表头部或者尾部;

​ 他的底层实际是个双端链表,最多可以包含2^322-1个元素(4294967295,每个列表超过40亿个元素);

lpush/rpush/lrange list value...	--左端插入/右端插入、从左开始遍历
lpop/rpop list	--左端弹出/右端弹出
lindex list index	--通过下标获取元素
llen list	--获取list元素个数
lrem key 数字N 给定值value	--删除N个值等于value的元素
ltrim key startIndex endIndex	--截取指定范围的值后再复制给key
rpoplpush source target	--从source右边弹出一个从target左边push
lset key index value	--给指定的key的index下标设置value
linsert key before/after value1 value2	--在value1的前/后插入value2

应用场景:微信公众号订阅消息;

3、哈希表(Hash)

​ hash是一个string类型的field(字段)和value(值)的映射表,hash特别适合用于存储对象;

​ 每个hash可以存储2^32-1键值对;

hset/hget/hmset/hmget/hgetall/hdel 
hlen key	--获取当前key的所有元素数量
hexists key	--在key里面的某个值的key
hkeys/hvals list	--列出所有key/value
hincrby/hincrbyfloat icement	--加指定步长
hsetnx	--不存在插入失败\存在插入成功

**应用场景:**中小厂购物车;

4、集合(Set)

​ Set是String类型的无序集合。集合成员是唯一的,集合中不能出现重复的数据,集合对象的编码可以使intset或者hashtable;

​ Set集合是通过哈希表实现的,所以添加、删除的复杂度都是O(1);

​ 集合中最大的成员数是2^32-1;

sadd key member...	--添加元素
smembers key	--遍历集合中的所有元素
sismember key member	--判断元素是否在集合中
srem key member...	--删除元素
scard key	--获取集合中的元素个数
srandmember key 数组N	--从集合中随机展现设置的数字个数元素
spop key 数字N	--从集合中随机弹出一个元素,出一个删一个
smove key1 key2 在key1中存在的某个值	--将key中已存在的某个值赋值给key2
--集合运算
sdiff key1 key2	--差集,属于key1不属于key2
sunion key1 key2	--并集,属于key1或者属于key2的元素合并后的集合
sinter key1 key2	--交集,属于key1同时属于key2的元素	
sintercard numkeys key1 key2	--交集后的元素个数

应用场景:微信抽奖小程序; 微信朋友圈点赞查看共同好友;QQ内推可能认识的人;

5、有序集合(ZSet)

​ zset和set一样是String类型元素的集合,且不允许重复的成员;

​ 不同的是每个元素都会关联一个double类型的分数 ,redis通过分数来为集合中的成员进行从小到大的排序;

​ zset的成员是唯一的,但分数(score)却可以重复;

​ zset集合是通过哈希表实现的,所以添加,删除、查询的复杂度都是O(1),集合中最大成员数为2^32-1;

zadd key score memeber [score member]	--向有序集合中加入一个元素和该元素的分数
zrange key start [withscores] stop end	--按元素从小到大的顺序返回索引从start到end之间的元素[带分数]值
zrevrange key start [withscores] stop end	--按元素从小到大
zrangebyscore key [(]min max [withscore][limit offset count]	--获取指定分数范围的元素[不包含][带分数][开始下标,走多少步长]
zscore key member	--获取元素的分数
zcard key	--获取集合中元素的数量
zrem key member	--删除某个key下对应的元素
zincrby key increment member	--增加某个元素的分数
zcount -key min max	--获取指定分数范围内的元素个数
zmpop 个数 key min count 个数	--从键名列表中的第一个费控排序集中弹出一个或多个元素,他们是成员分数对
zrank key member	--获取下标值
revrank	key member	--逆序获取下标值

**应用场景:**根据商品销售对商品进行排序显示 ;数量排序问题

6、地理空间(GEO)

​ GEO主要用于存储地理位置信息,并对存储的信息进行操作,包括:

​ 添加地理位置的坐标;

​ 获取地理位置的坐标;

​ 计算两个位置之间的距离;

​ 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合;

geoadd key longitude latetude member [longitude latetude member ...]	--多个经度、纬度、位置名称添加到指定key中(中文乱码 redis-cli --raw启动)
geopos key member	--从键里面返回所有给定位置元素的位置(经度和纬度)
geodist key member1 memeber2 单位	--返回两个给定位置之间的距离
georadius key 经纬度 范围 单位 withdist withcoord count 10 withhash desc	--以给定的经纬度为中心,返回与中心的距离不超过给定最大距离的所有位置元素
	withdist:在返回位置元素的同时,将位置元素与中心之间的距离一并返回,距离单位和用于给定的范围单位保持一致
	withcoord:将位置元素的经纬度也一并返回
	withhash:以52为有符号整数的形式,返回位置元素经过原始geohash编码的有序集合分值。
	count:限定返回的记录数
georadiusbymember 	--跟georadius相似
geohash	key member	--返回一个或多个位置元素的geohash表示
7、基数统计(HyperLogLog)

​ HyperLogLog用来做基数统计的算法,HyperLogLog的有点是,在输入元素的数量或者体积非常非常大时,计算基数需要的空间总是固定且很小的;

​ 在redis里面,每个HyperLogLog键只需要花费12KB内存 ,可以计算接近2^64个不同元素的技术,这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比;

​ 但欣慰Hyper只会根据输入的元素来进行计算基数,而不会存储输入元素本身,所以HyperLogLog不能像集合那样,返回输入的各个元素。

pfadd key value...	--添加基数
pfcount key	--获取基数个数(去重)

应用场景:

8、位图(bitmap)

​ 由0和1状态表现的二进制位的bit数组;

setbit key offset value	--setbit 键 偏移位 只能是0或1  
getbit key offset	--获取偏移量的值
strlen key	--统计这个字节占多少位
bitcount	--全键里包含1的有多少个
bitop operation destkey key	--对不同的二进制存储数据进行位运算(and、or、not、xor)

**应用场景:**一天365天,全年天天登录占多少个字节;

9、位域(bitfield)

​ 通过bitfield命令可以一次性操作多个比特位域(指的是连续多个比特位),他会执行一系列操作并返回一个相应数组,这数组中的元素对应参数列表中的相应操作的执行结果;

​ 通过bitfield命令可以一次性对多个比特位域进行操作;

10、流(Stream)

​ 主要用于消息队列(MQ Message Queue),redis本身是有一个redis发布订阅(pub/sub)来实现消息队列的功能,但他有个确定就是消息无法持久化,如果出现断网,redis宕机,消息就会全被丢弃;

​ redis Stream提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失;

xadd key *|id filed value [filed value...]	--向队列尾添加消息,如果指定的Stream队列不存在,则该命令会新建一个Stream队列。*表示服务器自动生成的MessageID
xrange key - +	[count num]	--获取消息列表[-代表最小 +代表最大][count 代表获取num个]
xrevrange key + -	--消息列表降序获取
xdel key id	[id...]	--根据主键删除
xlen key	--消息列表长度
xtrim [maxlen|minid]	--对Stream的长度进行截取[允许的最大长度,对流先进行修剪限制长度|允许的最小id,从某个id值开始比该id值小的将会被抛出]
xread [count num] [block milliseconds] strams key [key...] id [id ...] 	--读取[最多度多少条][block是否已阻塞的方式读取消息如果milliseconds设置为0,代表永远阻塞]
xgroup create key group id|$ 	--分组[$从Stream尾部开始消费|0从头开始消费]
xreadgroup group groupName key Stream key1	--将groupName中的key读取到key
中

持久化

1、RDB、

​ 在指定的时间间隔,执行数据集的时间点快照;在指定的时间间隔内将内存中的数据集快照写进磁盘,也就是行话讲的Snapshot内存快照,他恢复时再将硬盘快照文件直接读回到内存里;redis的数据都在内存中,保存数据备份时他执行的是全量快照。保存的文件是dump.rdb。

--自动触发(修改配置文件)
save <seconds> <changes>	--在seconds秒内变动key变动changes次触发
dir ./   -->  dir 指定文件路径
dbfilename dump.rdb  -->  dbfilename 指定文件名
config get/set [param]	--获取/设置配置文件、
--手动触发
save/bgsave 命令
--恢复
将备份文件移动到redis安装目录并启动服务即可
执行flushall/flushdb命令也会产生dump.rdb文件,但里面是空的,无意义
物理备份,一定服务和备份分机隔离


save在主程序中执行会阻塞当前redis服务器,直到持久化工作完成,执行save命令期间,redis不能处理其他命令,线上禁止使用。
bgsave对当前内存中的所有数据做快照,这个操作是子进程在后台完成的,这就允许主进程同时可以修改数据;
lastsave 上一次保存的时间戳,通过date -d @时间戳看出时间
--修复rdb文件
cd /usr/local/bin
redis-check-rdb  rdb文件路径
--触发rdb文件快照情况
配置文件中默认的快照配置
手动save/bgsave命令
执行flushall/flushdb命令也会产生dump.rdb文件,但里面是空的
执行shutdown且没有设置开启aof持久化
主从复制时,主节点自动触发
--禁用rdb快照
redis-cli config set value ""	--本次生效
在配置文件中save seconds changes --> save ""
--rdb参数优化
stop-writes-on-bgsave error yes	--默认yes,如果配置成no,表示不在乎数据一致性或者其他手段发现和控制这种不一致,那么在写入快照失败时,也能确保redis继续接收新的写请求;建议开启
rdbcompression yes	--默认yes,对于存储到磁盘中的快照,可以设置是否进行压缩存储,如果可以redis会采用lzf算法进行压缩,如果不想消耗cpu来进行压缩,可以设置为关闭此功能;建议yes
rdbchecksum yes	--默认yes,在存储快照后,还可以让redis使用crc64算法进行数据校验,但这样会增大大约10%的性能消耗,如果希望获取到最大的性能提高,可以关闭此功能;

优点:适合大规模的数据恢复;按照业务定时备份;对数据完整性和一致性要求不高;rdb文件在内存中的加载速度要比aof快的多。

**缺点:**在一定间隔时间做一次备份,如果redis意外down掉,就会丢失从当前至最近一次快照期间的数据,快照之间的数据丢失;内存数据的全量同步,如果数据量太大会导致I/O影响服务器性能;rdb依赖于进程的fork,在更大的数据集中,这可能会导致服务请求的瞬间延迟;fork的时候内存中的数据被克隆了一份,大概2倍膨胀性,需要考虑;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ih37Q0E-1686448682600)(C:\Users\yun\AppData\Roaming\Typora\typora-user-images\image-20230521170959145.png)]

2、AOF

以日志对额形式来记录每个写操作,将redis执行过的所有写指令记录下来(读操作不记录),只需追加文件但是不可以改写文件,redis启动之初会读取该文件重新构建数据,reedis重启就根据日志文件的内容将指令从前到后执行一次以完成数据的恢复工作。

redis默认没有启动aof,开启aof功能需要设置配置:appendonly yes;

aof保存的文件是appendonly.aof文件;

aof持久化工作流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nKn56d72-1686448682601)(C:\Users\yun\AppData\Roaming\Typora\typora-user-images\image-20230521203128403.png)]

--aof三种写回策略 appendonlysync 策略  修改配置文件
Always	--同步会写,每个写命令执行完立刻同步地将日志写回磁盘
everysec	--默认,每一秒写一次
no	--操作系统控制的写回,每个写命令执行完,只是先把日志写到aof文件的内存缓冲区,由操作系统决定何时将缓冲区写回磁盘;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lvJfQb3c-1686448682602)(C:\Users\yun\AppData\Roaming\Typora\typora-user-images\image-20230521203934390.png)]

--redis7中aof文件保存位置设置  redis6保存位置和rdb一致
appenddirname 路径	--文件路径
appendfilename 文件名	--文件名
--redis7将appendonly.aof文件分为三部分   redis6只有一个aof文件
base基本文件、incr增量文件、manifset清单文件。
base:表示基础aof,他一般由子进程通过重写产生,该文件最多只有一个
incr:表示增量aof,他一般会在aofrw开始执行时被创建,该文件可能存在多个
history:表示历史aof,它是由base和incr_aof变化而来,每次aofrw完成时,本次aofrw之前对应的base和incr都将变为history,history类型的aof将会被redis自动删除;
--恢复异常
redis-check-aof --fix 文件名	--进行修复
--aof重写机制
--触发机制  自动、手动
自动触发机制:满足配置文件的选项后,redis会记录上次重写时的aof大小,默认配置是aof文件大小是上次rewrite后大小的一倍且文件大于64M时 --auto-aof-rewrite-percentage 100 |	auto-aof-rewrite-min-size 100M
手动触发:客户端向服务器发送bgrewriteaof命令
aof文件的内容压缩,只保留可以恢复数据的最小指令集。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8GmVqJQM-1686448682603)(C:\Users\yun\AppData\Roaming\Typora\typora-user-images\image-20230521213658045.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lBOI9IDT-1686448682604)(C:\Users\yun\AppData\Roaming\Typora\typora-user-images\image-20230521213921147.png)]

优点:

更好的保护数据不丢失、性能高、可做紧急恢复;

缺点:

相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb;aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同;

3、RDB+AOF
--开启混合方式设置  前置必须看开启AOF
aof-use-rdb-preamble  == yes	--yes表示开,no表示禁止
--RDB+AOF混合方式结论:RDB镜像做全量持久化,AOF做增量持久化
先试用rdb进行快照存储,然后使用aof持久化记录所有操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的rdb记录;重启服务的时候会从RDB和AOF两部分恢复数据,即保证了数据完整性,又提高了恢复数据的性能。简单说:持久化方式产生的文件一部分是rdb格式,另一部分是AOF格式  ==》AOF包括了RDB的头部+AOF混写;

事务

可以一次执行多个命令,本质是一组命令的组合。一个事务中的所有命令会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lTQkqdp9-1686448682605)(C:\Users\yun\AppData\Roaming\Typora\typora-user-images\image-20230522210718417.png)]

--正常执行
multi commands	--开启事务,后面跟着一串命令
exec	--执行事务
--放弃执行
multi	commands	
discard	--放弃事务
--全体连坐
在multi的时候命令写错就会报错,全部命令都会被取消
--谁出问题找谁
在multi的时候语法上没有错误,当执行之后会报错
--watch监控
watch key	--使用乐观锁形式,一旦执行了exec之前加的监控锁都会被取消掉,当客户端连接丢失,所有东西都会被取消监控
--总结
开启:multi开始一个事务
入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放在等待执行的事务队列里面
执行:又exec命令触发事务

管道

管道可以一次性发送多条命令给服务端,服务端依次处理完毕后,通过一条相应一次将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间。pipeline实现的原理是队列,先进先出特性保证了数据的顺序。pipeline是为了解决rtt往返时间,仅仅是将命令打包一次性发送,对这个redis的执行不造成其他影响。

cat 文件|redis-cli -a password --pipe
--总结
--pipeline与原生批量命令对比
原生批量命令是原子性,pipeline是非原子性的
原生批量命令一次只能执行一种命令,pipeline支持批量执行不同命令
原生批量命令是服务器端实现 ,而pipeline需要服务端与客户端共同完成
--与事务对比
是与具有原子性 ,管道不具备
管道一次性将多条命令发送到服务器,事务是一条条的发,事务只有在接收到exec命令之后才会执行
执行事务时将会阻塞其他命令的执行,而执行管道中的命令时不会
--注意事项
pipeline缓冲的指令只是会依次执行,不保证原子性,如果执行中命令发生异常,将会继续执行后续命令
使用pipeline组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过久,同时服务器端此时也被迫回复一个队列答复

发布订阅

是一种消息通信模式:发送者(publish)发送消息,订阅者(subscribe)接收消息,可以实现进程间的消息传递。

Redis复制(replica)

主从复制,master以写为主,slave已读为主;当master数据变化的时候,自动将新的数据异步同步到其他slave数据库。

**作用:**读写分离、容灾恢复、数据备份、水平扩容支撑高并发

-- 主从复制
replicaof 主库ip 主库端口
配从库不配主库
-- 改为其他主库
slaveof 新主库ip 新主库端口
-- 自己为主库
slaveof no one
config文件配置
1、开启daemonize yes   --后台运行
2、注释bind 1227.0.0.1 --绑定ip
3、protected-mode no	--保护模式关闭
4、指定端口 port	
5、指定当前工作目录dir 指定路径
6、pid文件名字,pidfile 指定路径	--文件进程id
7、log文件名字,logfile 指定路径	--日志文件
8、requirepass	--设置密码 
9、dump.rdb
10、AOF文件,appendfilename
11、从机访问主机的同行密码masterauth,必须
-- 查看主从关系
info replication

主从问题

​ 1、从机不能执行写命令

​ 2、从机写入点从头开始(中间连接主机的从机也会复制主键的全部数据)

​ 3、主机shutdown之后,从机会等在从机启动

​ 4、主机从启后主从复制仍然存在

​ 5、从机shutdown之后,再次启动,仍然能够复制全部数据

slaveof 主库ip 主库端口	--临时命令,当两台从机关机从启之后命令主从关系不复存在
复制原理和工作流程
  • ​ slave启动,同步初清

    • slave启动成功连接到master后会发送一个sync命令
    • slave首次全新连接master,一次完全同步(全量复制)将被自动执行,slave自身原有数据会被master数据覆盖清除
  • 首次连接,全量复制

    • master节点收到sync命令后会开始在后台保存快照(即RDB持久化,主从复制会触发RDB),同时收集所有接收到的用于修改数据集命令缓存起来,master节点执行RDB持久化后,master将RDB快照文件和所有缓存的命令发送到所有slave,以完成一次完全同步
    • slave服务在接收到数据库文件数据后,将其存盘并加载到内存中,从而完成复制初始化
  • 心跳持续,保持通信

    • repl-ping-replica-period 10 --master发送ping包的周期默认为10秒
  • 进入平稳增量复制

    • master继续将新的所有收集到的修改命令自动一次传给slave,完成同步
  • 从机下线,重连续传

    • master会检查backlog里面的offset,master和slave都会保存一个复制的offset还有一个masterID,offset是保存在backlog中的。master只会把已复制的offset后面的数据复制给slave,类似断点续传。

复制的缺点

​ 1、复制延时,信号衰减:所有的写操作都会现在master上操作,然后同步更新到slave上,所以从master同步到slave及其有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,slave机器数量的增加也会使这个问题更加严重。

​ 2、master失效后,默认情况喜爱不会在slave节点中自动重选一个master。

Redis哨兵(Sentinel)

​ 吹哨人巡查监控后台master主机是否故障,如果故障了根据投票数自动将某一个从库转为新主库,继续对外服务。

作用:无人值守运维。

​ 监控redis运行状态,包括master和slave

​ 当master宕机,能自动将slave切换成新master

  • 主从监控

    • 监控行redis库运行是否正常
  • 消息通知

    • 小兵可以将故障转移的结果发送给客户端
  • 故障转移

    • 如果master异常,则从进行主从切换,将其中一个slave作为新的master
  • 配置中心

    • 客户端通过链接哨兵来获得当前redis服务的主节点地址

文件配置

bind	-- 服务监听地址,用于客户端连接,默认是本机
deamonize	--是否启动后台daemon方式运行
protected-mode	--安全保护模式
port	--端口
logfile	--pid路径
dir	--工作目录
sentinel monitor <master-name> <ip> <redis-port> <quorum>	--设置要监控的master服务器;quorum表示最少有几个哨兵认可客观下线,同意故障迁移的法定票数。
sentinel down-after-milliseconds <master-name> <milliseconds>	--指定多少毫秒之后,主节点没有答应哨兵,此时哨兵主观上认为主节点下线
sentinel parallerl-syncs <master-name> <nums>	--表示允许并行同步的slave个数,当master挂后,哨兵会选出新的master,剩余的slave会向新的master发起同步数据
sentinel failover-timeout <master-name> <milliseconds>	--故障转移的超时时间,进行故障转移时,如果超过设置的毫秒,表示故障转移失败
sentinel notification-script <master-name> <sript-path>	--配置当某一件事发生时所需要执行的脚本
sentinel client-reconfig-script <master-name> <script-path>	--客户端重新配置主节点参数脚本

主从复制:主机shutdown后,文件的内容在运行期间会被sentinel动态进行动态更改。master-slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生变化、即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换。

运行流程和选举原理

​ 当一个主从配置的master失效后,sentinel可以选举出一个新的master用于自动接替原master的工作,主从配置的其他redis服务器自动指向新的master同步数据。一般建议sentinel采取奇数台,防止某一台sentinel无法连接到master导致误切换。

运行流程,故障切换

  • 三个哨兵正常运行

  • SDown主观下线

    • SDOWN(主观不可用)是单个sentinel自己主观上检测到的关于master的状态,从sentinel的角度来看,如果发送了ping心跳后,在一定时间内没有收到合法的回复,就达到了SDOWN的条件。
    • sentinel配置文件中的down-after-milliseconds设置了判断主观下线的时间长度。
  • ODown(客观下线)

    • ODOWN需要一定数量的sentinel,多个哨兵达成一致意见才能认为一个master客观下线。
  • 选举领导者哨兵

    • 当主节点被判断客观下线后,各个哨兵节点会进行协商,先选举出一个领导者哨兵节点并有该领导者节点,也即被选举出的兵王进行failover(故障迁移)。

    • 选举兵王Raft算法:监视该主节点的所有哨兵都有可能被选为领导者,选举使用的算法是raft算法;Raft的基本思路是先到先得:即在一轮选举中,哨兵A向哨兵B发送成为领导者的申请,如果B没有同意过其他哨兵,则会统一A成为领导者。

  • 由新的兵王开始推动故障切换流程并选出一个新的master。

    1. 新主:

      • 某个slave被选中成为新的master。

      • 选出新的master规则,剩余slave节点健康的前提下。

        • redis.conf文件中,优先级slave-priority或者replica-priority最高的从节点(数字越小优先级越高)。

        • 复制偏移位置offset最大的从节点。

        • 最小RunID的从节点。字典顺序,ASCLL码。

    2. 从机认同主机

      • 执行slave no one命令让选出来的从节点成为新的主节点,并通过slaveof命令让其他节点成为其从节点。
      • Sentinel leader会对选举出的新master执行slaveof no one操作,将其提升为master节点。
      • Sentinel leader向其他slave发送命令,让剩余的slave成为新的master节点的slave.
    3. 原主机跟从新主机

      • 将之前下线的老master设置为新选出的新master的从节点,当老master重新上线后,他会成为新master的从机。
      • Sentinel leader会让原来的master降级为slave并恢复正常工作。

image-20230607223025360

哨兵建议

  1. ​ 哨兵节点的数量应为多个,哨兵本省应该集群,保证高可用。
  2. 哨兵节点的数量应该为奇数。
  3. 各个哨兵节点的配置应一致。
  4. 如果哨兵节点部署在Docker等容器中,尤其要注意端口的正确映射。
  5. 哨兵+主从复制,并不能保证数据零丢失。

Redis集群(cluster)

​ 由于数据量过大,单个master复制集难以承担,一次需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是redis的集群,其作用是在多个redis节点间共享数据的程序集。

作用:

  • Redis集群支持多个master ,每个master又可以挂载多个slave
    • 读写分离
    • 支持数据的高可用
    • 支持海量数据的读写存储操作
  • 由于Cluster自带sentinel的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能。
  • 客户端与Redis的节点连接,不再需要连接集群中所有的节点,只需要连接任意集群中的一个可用节点即可。
  • 槽位slot负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系。
集群算法-分片-槽位slot

槽位

​ Redis集群没有使用一致性hash,而是引入了哈希槽。Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽位,集群的每个节点负责一部分hash槽。

分片:

​ 使用Redis集群时,我们会将存储的数据分散到多台Redis机器上,这成为分片。简而言之,集群中的每个Redis实例都被认为是整个数据的一个分片。

​ 为了找到给定key的分片,我们对key进行CRC16(key)短发处理并通过对总分片数量取模,然后,使用确定性哈希函数,这意味着给定的key将多次使用映射到同一分片,可以推断将来读取特定key的位置。

使用槽位和分片优势:方便扩容和数据分派查找。这种结构很容易添加和删除节点。比如想要新添加一个节点ID ,需要从节点A、B、C中得到部分槽位到D上,如果想要移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽点的A节点从集群中移除即可,由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论天添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态。

slot槽位的三种映射方式

  1. 哈希取余分区
    • 优点:简单粗暴,直接有效,只需要预估好数据规划好节点,就能保证一段时间的数据支撑。使用hash算法让固定的一部分请求落到统一台服务器上,这样每台服务器固定处理一部分请求,起到负载均衡+分而治之的作用。
    • 缺点:原来规划好的节点进行扩容或者缩减比较麻烦,不管扩缩,每次数据变动大道至节点变动,映射关系需要重新计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化;Hash(key)/old变成Hash(key)/new。此时某个redis宕机,由于台数变化,会导致Hash取余全部数据重新洗牌。
  2. 一致性哈希算法分区
    • 目的:当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系。
    • 三个步骤
      • 算法构建一致性哈希环
      • 服务器Ip节点映射
      • key落到服务器的落键规则
    • 优点:容错性和扩展性性。
    • 缺点:数据倾斜问题,被缓存的对象大部分集中缓存在某一台服务器上。
  3. 哈希槽分区
    • ​ 能够均匀分配的问题,在数据和节点之间又加了一层,把这层成为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。
    • 槽解决的是粒度问题,相当与粒度变大,这样便于数据移动。哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。
    • 一个集群中有16384个槽,这些槽会分配给集群中的所有主节点,分配策略没有要求。集群会记录节点和槽的对应关系,解决了节点和槽的关系后,借此来就需要对key求Hash值,然后对16384取模,余数是几就落在 对应的槽里。 HASH_SLOT=CRC16(key) mod 16384.以槽位单位移动数据,因为草的数目是固定的,处理起来比较容易,这样数据移动的问题就解决了。

为什么Redis集群的最大槽数是16384?

  1. ​ 如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。
  2. redis的集群主节点数量基本不可能超过1000个。
  3. 槽位越小,节点少的情况下,压缩比高,容易传输

Redis集群不保证强一致性,这意味着在特定的条件下,redis集群可能会丢失一些被系统收到的写入请求命令。

cluster nodes		--查看并验证集群状态
cluster failover	--故障节点从属调整
集群常用操作命令和crc16算法分析
  • 不在同一个slot槽位下的多键操作支持不好,通识占位符出现。

    • 不在同一个slot槽位下的键值无法使用mset、mget等多键操作
    • 可以通过{}来定义同一个组的概念,使用key中{}内相同内容的键值对放到一个slot槽位
  • Redis集群有16384个哈希槽,每个key 通过crc16校验后对16384取模来决定放置那个槽。集群的每个节点负责一部分槽位。

cluster-require-full-coverage	--集群是否完整才能对外提供服务
cluster countkeysinslot	槽位数字编号		--判断该槽位是否被占用
cluster keyslot 键名	--该键应该放在哪个槽位
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值