Redis
Redis
NoSQL
NoSQL是解决性能问题的一种技术,Redis是一种典型的NoSQL数据库
Redis
Redis的操作基本都是基于内存的,CPU资源根本就不是Redis的性能瓶颈,所以Redis不需要通过多线程技术来提升CPU利用率。
redis是设计为为缓存使用的
redis所有的操作都是原子性的。采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响
基础操作
开启 redis 数据库
在安装目录下使用 redis-server.exe redis.windows.conf 命令打开
help命令
help command 获得指定命令的帮助文档
help
help @group 获得群组的帮助文档
set命令
set key value
插入一个数据,以 key 为键,以 value 为值
get命令
get key
以 key 获得一个数据
del命令
del key
删除一个数据
quit、exit命令
quit / exit
退出客户端
数据类型
string
redis 自身是一个Map,其中所有的数据都是采用 key : value 的形式存储的
数据类型指的是存储的数据,key部分永远都是字符串
如果字符串以整数的形式展示,则可以作为数字使用,但还是个字符串
mset命令
一次添加多个数据,添加多个数据建议使用mset,但有极大的数据,建议分割后再发送,因为执行极大量的数据会造成线程阻塞
mget命令
一次获取多个数据,获取多个数据建议使用mget,但有极大的数据,建议分割后再发送,因为执行极大量的数据会造成线程阻塞
strlen命令
获取某个数据的字符长度
append命令
往一个数据的后面追加字符串
string类型数据的扩展操作
业务场景:大型企业中,分表是基本操作,使用多张表存储相同类型数据,但是对于主键id必须要不能重复
设置数值数据增加指定范围的值
incr命令
让指定的数据自增一
incrby命令
让指定的数据增加指定的值
incrbyfloat命令
让指定的数据增加指定的值(小数值)
设置数值数据减小指定范围的值
- decr命令
让指定的数据自减一
decrby命令
让指定的数据减小指定的值(小数值)
业务场景:海选投票,只能通过微信投票,每个微信号每4小时只能投1票
setex命令
添加一个值,并限制其过期的时间
setex key seconds value
psetex命令
setex命令的毫秒版本
业务场景:展示某用户的粉丝数量,博客数量
格式一:
格式二:
hash
- 新的存储结构:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
- 需要的存储结构:一个存储空间保存多个键值对数据
- hash类型:底层使用哈希表结构实现数据存储
添加 / 修改数据
hset key field value
1
2
3hset user name zhangsan
hset user age 38
hset user id 1批量添加 / 修改数据
hmset key field1 value1 field2 value2…
1
hmset user name zhangsan age 38 id 1
获取数据
hget key field
1
hget user name // ==> "zhangsan"
hgetall key
1
2
3
4
5
6
7hgetall user // ==> 单数为field
1) "name"
2) "zhangsan"
3) "age"
4) "38"
5) "id"
6) "1"批量获取数据
hmget key field1 field2…
1
hmget user name age
删除数据
hdel key field
1
hdel user name age id
获取哈希表中字段的数量
hlen key
1
hlen user // ==> 3
获取哈希表中是否存在指定的字段
hexists key field
1
hexists user name // ==> 1 (1表示true,0表示false)
hash类型数据的扩展操作
获取数据
获取哈希表中所有的键
hkeys key
1
2
3
4hkeys user // ==>
1) "id"
2) "name"
3) "age"获取哈希表中有的值
hvals key
1
2
3
4hvals user // ==>
1) "1"
2) "jjw"
3) "21"
增加 / 减小数据
设置指定字段的数值数据增加指定范围的值
hincrby key field incremnet
1
hincrby user age 2 // ==> 23
hincrbyfloat key field incremnet
1
hincrby user age 2。5 // ==> 23.5
注:
hash类型下的value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象
hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计的,不可滥用
如果当前这个key中有值就不做任何操作,如果没有就添加数据
hsetnx key field value
1
hsetnx user name jjw
list
- 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
- 需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
- list类型:保存多个数据,底层使用双向链表存储结构实现
添加 / 修改数据
左添加 / 修改数据
lpush key value1 value2…
1
lpush list huawei xiaomi apple
右添加 / 修改数据
rpush key value1 value2…
1
rpush list huawei
获取数据
按范围获取数据
lrange key start stop
1
lrange list 0 2 // ==> "apple" "xiaomi" "huawei"
按索引获取数据
lindex key index
1
lindex list 1 // ==> "xiaomi"
获取list类型的长度
llen key
1
llen list
获取并移除数据
左弹出数据
lpop key
1
lpop list // ==> "apple"
右弹出数据
rpop key
1
rpop list // ==> "huawei"
list类型数据扩展操作
规定时间内获取并移除数据
左弹出(b代表阻塞,可以从多个list中获取)
blpop key1 key2 timeout
1
blpop list 30 // 表示如果没有可以等待30秒,30秒之后没有就算了
右弹出
brpop key1 key2 timeout
移除指定数据
从左向右删除
lrem key count(移除多少个) value
1
2rpush list a b c c d e
lrem list 1 c // ==> "a" "b" "c" "d" "e"
注:
- list中保存的数据都是string类型的,数据总容量是有限的最多2^32-1个元素
- list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或栈形式
- 负数为全部数据操作结束的索引
set
- 新的存储需求:存储大量的数据,在查询方面提供更高的效率
- 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
- set类型:与hash存储结构完全相同,仅存储键,不存储值,并且值是不允许重复的
添加数据
sadd key member1 member2…
1
sadd users jjw1 jjw2
获取全部数据
smembers key
1
smembers users // ==> "jjw1" "jjw2"
判断集合中是否包含指定数据
sismember key member
1
sismember users jjw1
set类型数据的扩展操作
随机获取集合中指定数量的数据
srandmember key [count]
1
2sadd news 1 2 3 4 5
sranmember news 2 // ==>随机出现 "2" "4"
随机获取集合中的某个数据 并将该数据移出集合
spop key
1
2sadd news 1 2 3 4 5
spop news // ==> "3" 剩下: "1" "2" "4" "5"
求两个集合的交、并、差集
sinter key1 key2
1
2
3sadd set1 1 2 3 4 5
sadd set2 4 5 6 7 8
sinter set1 set2 // ==> "4" "5"sunion key1 key2
1
2
3sadd set1 1 2 3 4 5
sadd set2 4 5 6 7 8
sunion set1 set2 // ==> "1" "2" "3" "4" "5" "6" "7" "8"sdiff key1 key2
1
2
3
4sadd set1 1 2 3 4 5
sadd set2 4 5 6 7 8
sdiff set1 set2 // ==> set1-set2 ==> "1" "2" "3"
sdiff set2 set1 // ==> set2-set1 ==> "6" "7" "8"
求两个集合的交、并、差集并存储到指定集合中
sinterstore destination key1 key2
1
2sinterstore set3 set1 set2
smembers set3 // ==> "4" "5"sunionstore destination key1 key2
1
sunionstore set3 set1 set2
sdiffstore destination key1 key2
1
sdiffstore set3 set1 set2
将指定数据从原始集合中移动到目标集合中
smove source destination member
1
2smove set1 set2 1
smembers set2 // ==> "1" "4" "5" "6" "7" "8"
sorted_set
新的存储需求:数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式
需要的存储结构:新的存储模型,可以保存可排序的数据
sorted_类型:在set的存储结构基础上添加可排序字段(注意:score字段仅用于排序,不能用于存储数据)
添加数据
zadd key score1 member1 score2 member2
1
2
3zadd sset 99 lisi
zadd sset 94 zhangsan
zadd sset 100 wangwu
获取全部的数据
zrange key start stop [withscores]
1
2
3
4zrange sset 0 -1 // ==> 由小到大
"zhangsan"
"lisi"
"wangwu"zrevrange key start stop [withscores]
1
2
3
4
5
6
7zrevrange sset 0 -1 withscores(带上scores字段) // ==> 由大到小
"wangwu"
"100"
"lisi"
"99"
"zhangsan"
"94"
删除数据
zrem key member1 member2…
1
zrem sset wangwu
sorted_set类型数据的基本操作
按条件获取数据
由小到大获取数据
zrangebyscore key min max [withscores] [limit(限定查出多少个数据)]
1
2
3
4
5zrangebyscore sset 93 99 withscores // ==>
"zhangsan"
"94"
"lisi"
"99"由大到小获取数据
zrevrangebyscore key max min [withscores]
1
2
3zrevrangebyscore sset 99 93 // ==>
"lisi"
"zhangsan"
条件删除数据
按索引范围删除
zremrangebyrank key start stop
1
zremrangebyrank sset 0 1
按score字段范围删除
zremrangebyscore key min max
1
zremrangebyscore sset 93 99 // 删除score字段93 99之间的数据
获取集合数据总量
zcard key
按score字段范围获取总量
zcount key min max
集合交、并操作
zinterstore destination numkeys key1 key2 …
zunionstore destination numkeys key1 key2 …
获取数据对应的索引
由小到大查找索引
zrank key member
1
2zadd movies 100 a 99 b 150 c
zrank movies b // ==> 0由大到小查找索引
zrevrank key member
1
2zadd movies 100 a 99 b 150 c
zrevrank movies b // ==> 2
score值获取与修改
zscore key member
1
zscore movies b // ==> 99
对某一个数据的score字段进行加操作
zincrby key increment member
1
zincrby movies b 1
注:
- score保存的数据存储空间是64位
- score保存的数据也可以是一个双精度的double值,基于双精度浮点数的特征,可能会丢失精度,所以在排序时可能出现排序的问题,使用时候要谨慎
- sorted_set底层存储的还是基于set结构的,因此数据不能重复,新值会覆盖旧值的score字段
通用命令
key通用操作
删除指定key
del key
1
2
3
4
5
6
7
8
9
10
11set str str1 str2
hset hash hash1 hash2
lpush list list1 list2
sadd set set1 set2
zadd sset sset1 sset2
del str
del hash
del list
del set
del sset
获取key的类型
type key
1
2
3
4
5
6
7
8
9
10
11set str str1 str2
hset hash hash1 hash2
lpush list list1 list2
sadd set set1 set2
zadd sset sset1 sset2
type str // ==> string
type hash // ==> hash
type list // ==> list
type set // ==> set
type sset // ==> sored_set
判断key是否存在
exists key
1
exists list
为key改名
rename key newkey
1
rename user1 user2
如果newkey不存在才改名
renamenx key newkey
1
renamenx user1 user2
对所有key排序
对一个集合类型进行排序
sort
1
2
3lpush aa 1 aa 3 aa 2
lrange aa 0 -1 // ==> "2" "3" "1"
sort aa // ==> "1" "2" "3" (不改变元数据)
key扩展操作(时效性控制)
指定key设置有效期
expire key seconds
1
expire user 3
pexpire key milliseconds(毫秒)
1
pexpire user 3000
expireat key timestamp(时间戳)
1
pexpireat key milliseconds-timestamp
1
获取key的有效时间
ttl key
1
ttl user // ==> 24(秒)
pttl key(毫秒)
1
pttl user // ==> 300(毫秒)
切换key从时效性转换为永久性
persist key
1
persist user
查询key
keys pattern
1
2
3
4
5
6
7
8
9
10
11
12查询规则:
* 匹配任意数量的任意符号
?匹配一个任意符号
[] 匹配一个指定符号
keys * 查询所有
keys it* 查询所有以it开头
keys *heima 查询所有以heima结尾
keys ??heima 查询所有前面两个字符任意,后面以heima结尾
keys user: ? 查询所有以user:开头,最后一个字符任意
keys u[st]er:1 查询所有以u开头,以er:1结尾,中间包含一个字母,s或t
数据库通用操作
- redis为每个服务提供有16个数据库,编号从0~15
- 每个数据库之间的数据相互独立
数据库基本操作
切换数据库
select index
1
select 2 //切换到2号数据库
其它操作
quit(退出)
1
ping(测试连接)
1
echo message(打印日志)
1
echo asd // ==> "asd"
数据移动
move key db
1
2
3
4set jjw 1
move jjw 1
select 1
get jjw // ==> "1" (如果要移动到的数据库有这个key,则移动失败)
数据清除
dbsize(查看数据库里的数据总量)
1
dbsize
flushdb(清除当前所在数据库的所有数据)
1
flushdb
flushall(清除所有数据库的所有数据)
1
flushall
Jedis
Java语言连接redis服务:Jedis、SpringData Redis、Lettuce
1、创建maven工程
2、pom.xml文件中引入Jedis所需jar
1 | <dependency> |
3、使用 jedis
1 | import redis.clients.jedis.Jedis; |
Jedis工具类制作
1 | package util; |
Linux下使用Redis
linux下操作mysql:https://blog.csdn.net/longgeaisisi/article/details/78669007
linux下操作redis:https://blog.csdn.net/qq_43543789/article/details/104261786
安装
开启服务
暂停服务
查看状态
打开客户端
修改配置文件
基础配置
持久化
持久化就是利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化,为了防止数据的意外丢失,确保数据安全
RDB(快照)启动方式
描述:将当前数据进行保存,快照形式,存储数据结果,二进制存储
在配置文件中修改文件名
1
dbfilename dump.rdb 通常设为 dump-端口号.rdb
配置文件中修改rdb文件存放路径
1
dir /var/lib/redis 通常放到 data 文件夹下
配置文件中开启压缩、开启加载检测
1
2rdbcompression yes 设置存储至本地数据库时是否压缩数据
rdbchecksum yes 设置是否进行RDB文件格式校验
1 | save // 持久化 |
sava指令的执行会阻塞当前Redis服务器,有可能会造成阻塞时间过长,线上环境不建议使用
是否有方法解决?
后台执行
- 操作者发起指令;redis服务器在合理的时间控制指令执行
1 | bgsave // 不是立即执行的 |
忘记执行持久化操作了怎么办?
自动执行
- redis服务器在满足条件的时候发起指令
- 在conf配置文件中配置
1 | save 100 10 // 100秒内 key发生了10次变化就执行save指令 |
注:
- save配置要根据实际业务情况进行设置,频率过高或过低都会出现性能问题
- save配置对于second和changes设置通常具有互补对应关系
- save配置启动后执行的是bgsave操作
RDB特殊启动形式
全量复制
服务器运行过程中重启
1
debug reload
关闭服务器是指定保存数据
1
shutdown save
RDB优点
RDB是一个紧凑压缩的二进制文件,存储效率较高
RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
RDB恢复数据的速度要比AOF快很多
应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。
RDB缺点
- RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据
- bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能
- Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象
AOF(日志)启动形式
描述:将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂
以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的,可以简单描述为改记录数据为记录数据产生的过程
AOF的主要作用时解决了数据持久化的实时性,目前已经是Redis持久化的主流方式
AOF写数据的三种策略
always(每次)
每次写入操作均同步到AOF文件中,数据零误差,性能较低
everysec(每秒)
每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高,建议使用
no(系统控制)
由操作系统控制每次同步周期,整体过程不可控
在配置文件中开启
1 | appendonly yes|no // 开启后尽管RDB文件有配置,但优先使用AOF文件 |
配置选择哪一种策略
1 | appendfsync always|everysec|no |
配置文件名
1 | appendfilename filename // 建议配置为appendonly-端口号.aof |
配置存储路径
1 | dir |
AOF文件重写
参考:https://blog.csdn.net/hezhiqiang1314/article/details/69396887
由于不断的对redis进行操作会使aof文件越来越大,因此aof提供了如下几种重写规则
手动重写
1 | bgrewriteaof // 后台重写aof |
自动重写
配置文件中修改配置
1 | auto-aof-rewrite-min-size size // 触发条件是当前aof文件大小大于设置的最小值 |
重写流程
RDB 和 AOF 的区别
选择:
Redis事务
Redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。当执行时,一次性按照添加顺序依次执行,中间不会被打断
事务基本操作
开启事务,设定事务的开启位置,此指令执行后,后续的所有指令均加入到事务中
1 | multi |
执行事务,设定事务的结束位置,同时执行事务
1 | exec |
取消事务,终止当前事务的定义,multi之后,exec之前
1 | discard |
注:加入事务的命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行
事务的工作流程
事务的注意事项
定义事务的过程中,命令格式输入错误怎么办?
语法错误:命令书写格式有误
处理结果:如果定义的事务中所包含的命令存在语法错误,整体的事务中所有命令都不执行
运行错误:命令格式正确,但无法正确的执行。如对list进行incr操作
处理结果:能够正确执行的命令将会执行,运行错误的命令将不会执行
需要自己手动回滚
锁
监视锁
必须在事务开启前执行
对key添加监视锁,在执行exec前如果key发生了变化,终止事务执行
1 | watch key1 ... |
取消对所有key的监视
1 | unwatch |
客户端1 | 客户端2 |
---|---|
分布式锁
参考:https://blog.csdn.net/weixin_39764379/article/details/111006501
使用setnx设置一个公共锁,利用setnx命令达到返回值特征,有值返回设置失败,无值返回设置成功
1 | setnx lock-key value |
操作完毕通过del删除锁
1 | del lock-key |
分布式锁的死锁解决方案
业务分析
- 锁由用户控制加锁,若用户在加锁之后停电了,宕机了锁就解锁不了,存在风险
- 需要解锁操作不仅由用户控制,也能由系统控制
使用expire为锁添加时间限定,到时不释放锁,放弃锁
1 | expire lock-key second |
客户端一:
客户端二:
删除策略
数据会存放在expires,redis中有16个expires,以hash的类型存储
过期数据
过期的数据不会马上删除,因为其他的指令更需要被执行,先执行其他的指令
过期数据数据删除策略
定时删除
创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
优点:节约内存,到时就删,快速释放
缺点:CPU压力大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量
惰性删除
数据到达过期时间,不做处理,等下次访问该数据时发现过期了就删除,返回不存在
优点:节约CPU性能,发现必须删除时才删除
缺点:内存压力大,出现长期占用内存的数据
定期删除
Redis启动服务初始化时,读取配置server.hz的值,默认为10;每秒钟执行server.hz次serverCron()
逐出算法
当新数据进入redis时,内存不够怎么办?
Redis使用内存存储数据,在执行每一个命令前,会调用freeMemorylfNeeded()检测内存是否充足。如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法。
注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。
配置文件中配置最大可用内存,占用物理内存的比例,默认值为0,表示不限制
1 | maxmemory |
配置文件中配置每次选取待删除数据的个数,选取数据时并不会全库扫描,采用随机获取数据的方式作为待检测删除数据
1 | maxmemory-samples |
配置文件中配置数据逐出策略
1 | maxmemory-policy |
服务器基础配置
设置服务器以守护进程的方式运行
1 | daemonize yes|no |
绑定主机地址
1 | bind ... |
设置服务器端口号
1 | port 6379 |
设置数据库数量
1 | databases 16 |
日志记录文件名
1 | logfile 端口号.log |
设置服务器以指定日志记录级别
1 | loglevel debug|verbose|notice|warning |
设置同一时间最大客户端连接数,默认无限制。当客户端连接达到上限,Redis会关闭新的连接
1 | maxclients 0 |
客户端闲置等待最大时长,达到最大值后关闭连接,如需关闭该功能,设置为0
1 | timeout 300 |
导入并加载指定配置文件信息,用于快速创建redis公共配置较多的redis实例配置文件,便于维护
1 | include /path/server-端口号.conf |
高级数据类型
Bitmaps
获取指定key对应偏移量上的bit值
gerbit key offset
1 | gerbit bit 0 1 |
设置指定key对应偏移量上的bit值,value只能是1或0
setbit key offset value
1 | setbit bit 0 1 |
Bitmaps扩展操作
计算bitmaps中有多少个1
bitcount key [start end]
1 | bitcount bit(1101) // ==> 3 |
对指定key按位进行交、并、非、异或操作,并将结果保存到destKey中
bitop op destKey key1 ….
1 | bitop and destKey aa bb |
HyperLogLog
基数统计;基数是数据集去重后的元素个数
HyperLogLog是用来做基数统计的,运用了LogLog的算法
HyperLogLog类型的基本操作
添加数据
1 | pfadd key element |
统计数据
1 | pfcount key |
合并数据
1 | pfmerge destkey sourcekey |
GEO
GEO类型的基本操作
添加坐标点
geoadd key longitude latitude member
1 | geoadd geos 1 1 a |
获取坐标点
geopos key member
1 | geopos geos a |
计算坐标点距离
geodist key member1 member2
1 | geodist geos a b |
根据坐标求范围内的数据
georadius key longitude latitude redius m|km|ft|mi
1 | georadius geos 1.5 1.5 90 km |
根据点求范围内数据
georadiusbymember key member redius m|km|ft|mi
1 | georadiusbymember geos a 180 km |
获取指定点对应的坐标hash值
geohash key member …
1 |
Redis集群
主从复制(需要再理解一遍)
简介
作用
- 读写分离:master写、slave读,提高服务器的读写负载能力
- 负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个节点分担数据读取负载,大大提高redis服务器并发量和吞吐量
- 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
- 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
工作流程
大致可以分为三个阶段
- 建立连接(slave连接master)
步骤:
1、设置mater的地址和端口,保存master信息
2、建立socket连接
3、发送ping命令
4、身份验证
5、发送slave端口信息
6、连接成功
方式一:客户端发送命令
slaveof masterip masterport
1 | //开启两个服务器 一个端口号6380(slave) 一个端口号6379(master) |
方式二:以配置文件启动时连接
redis-server …./redis-6380.conf –slaveof masterip masterport
1 | redis-server ..../redis-6380.conf --slaveof 127.0.0.1 6379 |
方式三:改变配置文件连接
在配置文件中添加 slaveof masterip masterport
1 | slaveof 127.0.0.1 6379 |
断开连接
1 | slaveof no one |
- 数据同步
在slave初次连接master后,复制master中的所有数据到slave
将slave的数据库状态更新成master当前的数据库状态
步骤:
1、请求同步数据
2、 创建RDB同步数据
3、恢复RDB同步数据
4、请求部分同步数据
5、恢复部分同步数据
6、同步工作完成
- 命令传播
哨兵模式
简介
哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master
作用
- 监控
不断的检查master和slave是否正常运行。master存活检测、master与slave运行情况检测 - 通知(提醒)
当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知。 - 自动故障转移
断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的服务器地址
启用哨兵模式
注:需要先创建一个sentinel.conf的文件,默认是没有的
配置:
port :当前 Sentinel服务运行的端口
dir : Sentinel服务运行时使用的临时文件夹
sentinel monitor master001 192.168.110.101 6379 2 : Sentinel去监视一个名为 master001 的主redis实例,这个主实例的IP地址为本机地址 192.168 . 110.101 ,端口号为 6379 ,而将这个主实例判断为失效至少需要 2 个 Sentinel进程的同意,只要同意Sentinel的数量不达标,自动failover就不会执行
sentinel down-after-milliseconds master001 30000 : 指定了Sentinel认为Redis实例已经失效所需的毫秒数。 当实例超过该时间没有返回PING,或者直接返回错误,那么Sentinel将这个实例标记为主观下线。只有一个 Sentinel进程将实例标记为主观下线并不一定会引起实例的自动故障迁移:只有在足够数量的Sentinel都将一个实例标记为主观下线之后,实例才会被标记为客观下线,这时自动故障迁移才会执行
sentinel parallel-syncs master001 1 :指定了在执行故障转移时,最多可以有多少个从Redis实例在同步新的主实例,在从Redis实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长
sentinel failover-timeout master001 180000 :如果在该时间(ms)内未能完成failover操作,则认为该failover失败
sentinel notification-script
: 指定sentinel检测到该监控的redis实例指向的实例异常时,调用的报警脚本。该配置项可选,但是很常用
启动哨兵
1 | //启动之前需要先启动主机和从机,先搭建好主从模式 |
工作原理
哨兵在进行主从切换的过程中经历了三个阶段
监控
同步各个节点的状态信息
- 获取各个sentinel的状态
- 获取master的状态和各个slave的详细信息
- 通知
- 故障转移
- 发现问题
- 竞选负责人
- 优选新master
- 新master上任,其他slave切换master,原master作为slave故障恢复后连接
集群
简介:集群就是使用网络将若干台计算机连通起来,并提供统一的管理方式,使其对外呈现单机的服务效果
作用
- 分散单台服务器的访问压力,实现负载均衡
- 分散单台服务器的存储压力,实现可扩展性
- 降低单台服务器宕机带来的业务灾难
集群结构设计
数据存储设计
- 通过算法设计,计算出key应该保存的位置
- 将所有的存储空间计划切割成16384份,每台主机保存一部分
- 每份代表的是一个存储空间,不是一个key的保存空间
- 将key按照计算出来的结果放到对应的存储空间
集群内部通讯设计
- 各个数据库相互通信,保存各个库中槽的编号数据
- 一次命中,直接返回
- 一次未命中,告知具体位置
集群搭建
参考:https://blog.csdn.net/qq_42815754/article/details/82912130
配置文件中添加配置,表示这个为一个cluster节点
1 | cluster-enabled yes |
配置文件中添加配置,集群配置文件
1 | cluster-config-file nodes-6379.conf |
配置文件中添加配置,表示超时时间
1 | cluster-node-timeout 10000 |
Cluster节点指令
查看集群节点信息
1 | cluster nodes |
进入一个从节点redis,切换其主节点
1 | cluster replicate <master-id> |
发现一个新节点,新增主节点
1 | cluster meet ip:port |
忽略一个没有solt的节点
1 | cluster forget <id> |
手动故障转移
1 | cluster failover |
企业级解决方案
缓存预热
原因:
1、请求数量较高
2、主从之间数据吞吐量较大,数据同步操作频度较高
解决方案:
缓存雪崩
原因:
1、在一个较短的时间内,缓存中较多的key集中过期
2、此周期内请求访问过期的数据,redis未命中,redis向数据库获取数据
3、数据库同时接收到大量的请求无法及时处理
4、Redis大量请求被积压,开始出现超时现象
5、数据库流量激增,数据库崩溃
6、重启后仍然面对缓存中无数据可用
7、Redis服务器资源被严重占用,Redis服务器崩溃
8、Redis集群呈现崩塌,集群瓦解
9、应用服务器无法及时得到数据响应请求,来自客户端的请求数量越来越多,应用服务器崩溃
10、应用服务器,redis,数据库全部重启,效果不理想
解决方案:
缓存击穿
原因:
1、Redis中某个key过期,该key访问量巨大
2、多个数据请求从服务器直接压到Redis后,均未命中
3、Redis在短时间内发起了大量对数据库中同一数据的访问
解决方案:
缓存穿透
原因:
1、Redis中大面积出现未命中
2、出现非正常URL访问
解决方案: