Redis的学习记录
1.先导了解
1.1 NOSQL概述
1.1.1 为什么要用NoSql?
PS:因为用户的个人信息,社交网络,地理位置,用户自己产生的数据,用户日志等等爆发式的增长。
1.1.2 NoSql了解
(1)Nosql即不仅仅是sql
(2)泛指非关系型数据库。随着web2.0互联网的诞生!传统的关系型数据库很难维护web2.0时代。尤其是超大规模的高并发的社区。
1.1.3 NoSql特点
(1)方便扩展–数据之间没有关系
(2)大数据量高性能–redis可以写8万次,能读取11万次NOSQL的缓存记录级,是一种细粒度的缓存,性能比较高
(3)数据类型是多样型的–不需要事先设计数据库,随取随用
(4)传统的RDBMS和NoSQL的区别
1.RDBMS
a.结构化组织
b.SQL
c.数据和关系都存在单独的表中
d.操作数据定义语言
e.严格的一致性
f.基础的事务操作等等
2.NoSQL
a.不仅仅是数据
b.没有固定的查询语言
c.键值对存储,列存储,文档存储,图形数据库
d.最终一致性
e.CAP定理和BASE理论(异地多活)
f.保证高性能,高可用,高可扩展性等等
1.1.4 NoSQL的四大分类
(1) KV键值对:
Redis
(2) 文档型数据库(bson格式)
1.MongoDB
a.MongoDB是一个基于分布式文件存储的数据库,主要用来处理大量的文档
b.MongoDB是一个介于关系型数据库和非关系型数据库中间的产品。也是非关系型
数据库中最像
2.ConthDB
(3) 列存储数据库
1.HBase
2.分布式文件系统
(4) 图关系数据库
1.它不是存图形的,存的是关系,比如:广告推荐等等
2.Neo4j, Infogrid
2. Redis概述
2.1 Redis是什么
①Redis(Remote Dictionary Server ),即远程字典服务。
②是一个开源的使用ANSI?C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API
③是一个NoSQL数据库,也被称为结构化数据库
2.2 Redis能干嘛
①内存存储,持久化,内存中是断电即失,所以持久化很重要(RDB, AOF)
②效率高,可以用于高速缓存
③发布订阅系统,地图信息分析,计时器,计数器等
2.3 Redis特性
①多样的数据类型
②持久化
③集群
④事务等等
2.4 使用redis-benchmark测试性能
①命令:redis-benchmark -h localhost -p 6379 -c 100 -n 100000
②命令解析:
1)-h : 表示要测试的ip地址,localhost表示测试本机
2)-p : 表示端口号
3)-c : 表示多少个并发连接数
4)-n : 表示指定多少请求数
2.5 Redis基础知识
①Redis有16个数据库,默认使用的是第0个
②切换数据库的命令:select 3–表示切换到第3个数据库
③查看DB大小命令:dbsize
④查看当前数据库里所有的key:keys *
⑤清空当前库:flushdb
⑥清空全部库:flushall
⑦redis是单线程的!Redis是基于内存操作的,redis的瓶颈不是CPU而是根据机器的内存和网络带宽。
⑧为什么Redis使用单线程还那么快?
1)因为redis是将所有的数据全部放在内存中的, 所以说使用单线程去操作效率是最高的。多线程(CPU会上下文切换:耗时的操作),对于内存系统来说,
如果没有上下文切换,效率就是最高的。
3.Redis的数据类型
3.1 Redis-Key(先导了解Redis的key)
①查看某个key是否存在:exists name – 表示查看name这个key是否存在
②移除某个key:move name 1 – 表示移除第1个数据库key为name的值
③设置key过期的时间:expire name 10 – 表示将key为name的值设置为10秒后过期
④查看某个key还有多久过期:ttl name – 表示查看key为name的这个值还有多久过期
⑤查看key的类型:type name – 表示查看key为name的类型
3.2 String类型(字符串类型)
①给key的值追加字符串:append name “yyds” 如果当前key不存在,那么这个命令就相当于增加key为那么的字符串。值为 yyds
②查看key的长度:strlen name
③增加值:incr age – 比如,age的值为0,每次使用这个命令,那么age的值就会加1
④减:decr age – 跟增加一样的理解
⑤增加设定值:incrby age 10 – 跟增加一样的理解,只是将增加1变为增加10
⑥减设定值:decrby age 10 – 同上
⑦截取字符串: getrange name 0 3 – 表示截取第0个到第三个(需要注意的是,java里面0,3取得是0 1 2. 而redis取得是:0 1 2 3);
⑧查看全部的字符串:getrange name 0 -1
⑨替换字符串:setrange name 1 58 – 表示将第二个字符串开始替换。比如字符串:hello,world = h58lo,world。如果命令为setrange name 1 581437 即 h581437orld -----PS:如图演示
⑩创建一个key并设定过期时间: setex name 30 “hello” – 表示设定一个key为name的字符串,值为hello,过期时间为30秒
11.创建一个key如果存在给key则不再创建:setnx name “redis” – 如果当前数据库有了该key。那么就不会再去创建,如果使用普通的set方法创建该key,如果当前数据库存在该key,那么key的值就会被替换。
12.批量创建key和key的值:mset k1 “1” k2 “2” k3 “3”
13.批量读取key的值:mget k1 k2 k3
14.批量创建key如果存在给key则不再创建:msetnx k1 “1” k4 “4” – 该创建失败,因为k1已经存在,后面虽然k4不存在,但是也不会继续创建下去。(即原子性的本质,要么一起成功,要么一起失败!)
15.创建对象:mset user:1 {name:shallow,aeg:18}
16.获取上面创建的对象:mget user:1
17.组合使用getset:getset name shallow – 表示,如果不存在这个key和值的话,如果没有返回nil(空),最后set会去创建这个值,然后你再get就能获取到shallow这个值。如果存在这个key和值的话,即会返回原先的值,再去set覆盖这个原先的值,你再去get name 就会返回shallow,PS:看图理解
3.3 List类型
①创建list并且push值:lpush list 1 – 这里list表示名字,1表示push进去的值。lpush为从头部添加值,rpush为从尾部添加值
②获取list里面的所有值:lrange 0 -1 – 表示获取list里面所有的值,注意,这里是先进后出。 — PS:看图
③移除值:lpop list – 表示移除列表的第一个元素。当然还有一个rpop list – 表示移除列表的最后一个元素
④获取列表指定位置的值:lindex list 0 – 表示获取名字为list列表的第一个值
⑤获取列表的长度:llen list – 表示返回列表的长度
⑥移除指定的值:lrem list 1 2 – 表示移除指定的值2,移除1个。PS:列表可以有重复的值。
⑦截取列表:ltrim list 1 2 – 表示通过下标截取需要的值 – PS:看图
⑧组合使用rpoplpush: rpoplpush list list_01 – 表示移除掉最后的一个值并放到一个新的列表 list_01里 — PS:看图
⑨查看是否存在某个列表:exists list – 表示查看这个list列表是否存在
⑩替换列表里的某个值:lset list 0 13 – 表示将list里的第一个元素改为13
PS:看图
11.往列表里插入值:linsert list before 2 1.5 – 表示往list列表的元素2前面(before)插入一个值为1.5。当然也可以往后面(after)插入值。Linsert list after 2 2.5 -------PS:看图
3.4 Set类型(set集合的值不能重复)
①创建set集合并且添加元素:sadd set 1 – 表示创建一个名叫set的集合,并加入元素1
②查看set集合的所有值:smembers set
③ 判断某个元素是否存在set集合:sismember set 1 - 表示查看元素1是否存在名字为set的set集合中。
④查看set集合有多少个元素:scard set
⑤移除set集合里的某个元素:srem set 2 --移除set集合里的元素为2的值
6.随机取出set集合里的指定数量的值:srandmember set 2 – 表示取出随机2个的值
PS:看图
⑦随机移除一个元素:spop set
⑧移除集合里一个指定的元素到另一个set集合:smove set set_01 4 – 表示移除set集合里的4这个元素,增加到set_01里
⑨比较两个集合有什么不同的元素(差集): sdiff set set_01 – 此命令返回的为不同的元素
⑩比较两个集合有什么相同的元素(交集):sinter set set_01
11.查看两个集合所有的元素(并集):sunion set set_01
3.5 Hash类型(哈希)
①创建hash集合并增加元素:hset hash01 name shallow – 表示创建名字为hash01的hash集合,这个hash集合的key为name, value为shallow
②获取值: hget hash01 name
③创建增加多个元素:hmset hash01 name01 shallow01 name02 shallow02 – 即表示创建一个hash集合,并增加对各键值对元素
④获取多个值:hmget hash01 name01 name02
⑤获取某个hash集合的全部值:hgetall hash01 – 返回的为键值对
⑥删除指定的key字段:hdel hash01 name01
⑦查看某个hash集合的长度:hlen hash01
⑧判断某个key是否存在:hexists hash01 name02
⑨查看某个hash集合的所有key:hkeys hash01
⑩查看某个hash集合的所有value:hvals hash01
11.让hash集合某个key的value自增:hincrby hash01 name02 2 – 2表示每次自加2
12.让hash集合某个key的value自减:hincrby hash01 name02 -1 – -1 表示每次自减1
13.创建hash集合并增加元素但是如果存在则不创建:hsetnx hash01 name04 4 – 如果name04 这个key存在的话,则不创建。
3.6 Zset类型(有序集合)
①创建并添加数据:zadd zset01 1 one 2 two 4 four 3 three
②显示全部用户并按从小到大排序:zrangebyscore zset01 -inf +inf
③显示全部用户且带上对应的值并按从小到大排序:zrangebyscore zset01 -inf +inf withscores
④显示大于负无穷到小于等于3的用户且带上对应的值并按从小到大排序:zrangebyscore zset01 -inf 3 withscores
⑤移除一个元素:zrem zset01 one
⑥查看zset集合元素数量:zcard zset01
⑦显示逆序的全部用户和值:zrevrange zset01 0 -1 withscores
⑧计算满足某个值到某个值的数量是多少: zcount zset01 60 100
3.7 Geospatial
①增加城市地理位置:PS:注意是东经北纬顺序
②获取城市的经纬度: geopos china:city beijing shanghai
③获取两个位置的距离:geodist china:city beijing shanghai km – km表示以千米为单位返回距离
④以某个坐标为中心,找出半径为800km以内的城市:georadius china:city 110 40 800 km
PS:加上withdist即可显示直线距离
PS:加上withcoord即可显示经纬度
PS:找出指定位置的周围1000km的其它城市位置
⑤查看所有城市:zrange china:city 0 -1
⑥移除某个城市:zrem china:city shanghai
3.8 Hyperloglog类型
①Hyperloglog的了解:
1)它是一个基数统计的算法
2)优点:占用的内存是固定的,2的64次方不同的元素的技术,只需要废12kb的内存。
②创建并添加元素:pfadd hpll 1 2 3 4 5 6 7 8 9 —hpll为这个集合的名字 1到9的数字为元素
③查看数量:pfcount hpll
④将两个集合合并且显示合并之后的集合数量:pfmerge phll03 phll phll02
PS:可以看出,重复的不会计算
3.9 Bitmap类型
①结合环境表达一下这个类型的用途:
1)因为它是一个位图数据结构,都是操作二进制位来进行记录。就只有0和1两个状态。
2)比如公司上班打卡的一个记录环境
3)添加记录:PS--星期一到星期天的打卡记录
4)比如查看某天的打卡情况:getbit sign 5 – 即查看星期六的打卡情况
5)统计这周的打卡记录:bitcount sign
4.Redis事务
(1)Redis单条命令是保存原子性的,但是事务不保证原子性。
(2)Redis事务没有隔离级别的概念,所有的命令在事务中,并没有被直接被执行,只有发起执行命令的时候才会被执行。Exec
(3)Redis事务的本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程中,会按顺序执行。(一次性,顺序性,排它性!)
(4)Redis的事务情况:
①开启事务--multi
②命令入列--即开始写命令
③执行事务--exec
PS:取消事务:discard
PS:Redis如果开启事务之后,命令入列的时候,命令没有错但是运行时有错,即运行时异常,其它的命令还是会正常运行。
PS:如果命令就是错误的,那么就不会执行事务,所有的命令都不会运行。
④测试redis的琐机制(watch监控命令实现)
1)比如第一个线程去开启事务
PS:可以看到。第一个线程去对money做更改,但是做到一半的时候,还没执行事务。又有另外一个线程去对money做了更改,这是时候第一个线程再去执行事务,就会执行失败!
PS:所以redis的watch可以看作一个乐观锁。
注意:一般使用完watch监控之后,后面要使用unwatch解锁
5.Jedis
①什么是jedis?
1)Jedis是redis官方推荐的java连接开发工具,使用java操作redis的中间件
2)Java连接redis
a.导入jedis包
b.编写测试连接类
PS:jedis的方法就是redis的命令,所以就不多作说明了!可以参考redis的命令来编写jedis的方法
=================================================
PS:这是一个jedis操作事务的例子
6.Springboot整合redis
6.1 springboot2.x版本后使用的redis的方法
①1.x版本下的用的是jedis来连接:jedis采用直连,多个线程操作的话,是不安全的,如果想避免不安全,就要使用jedis pool连接池!更像BIO模式
②2.x版本用的是lettuce来连接的:采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况。可以减少线程数量。更像NIO模式
6.2 整合流程(基于自定义RedisTemplate)
①首先导入依赖
②重写RedisTemplate
③然后去测试就行了
④注意点:记得给实体类实现序列化。然后重写的方法记得配置序列化
7.Redis.conf的详解
(1)单位了解(不区分大小写)
(2)包含(可以将多个redis配置文件组合成一个)
PS:就跟spring里面的import别的配置文件一样(如图)
(3)网络配置(==NETWORK)
①bind 127.0.0.1 ===表示绑定本地的地址
②protected-mode yes ====保护模式
③port 6379 ====== 端口设置
(4)通用配置(==GENERAL)
①daemonize yes === 以守护进程的方式运行yes开启
②pidfile /var/run/redis_6379.pid === 如果以后台的方式运行,那么就需要指定一个pid文件
③loglevel notice === 日志设置 默认使用notice就好
④logfile “” ==== 日志的文件位置名
⑤databases 16 === 数据库的数量,默认16个
(5) 快照(==SNAPSHOTTING)
①Redis持久化规则
1)save 900 1 === 如果900秒内,至少有一个key进行了修改,那么我们就进行持久化操作。
2)save 300 10 === 如果300秒内,至少有十个key进行了修改,那么我们就进行持久化操作。
3)save 60 10000 === 如果60秒内,至少有一万个key进行了修改,那么我们就进行持久化操作。
4)PS:redis是内存数据库,如果没有持久化,那么断电就会失去数据。
②stop-writes-on-bgsave-error yes === 持久化如果出错了,是否还要继续工作
③rdbcompression yes === 是否压缩rdb文件,需要消耗cpu资源!
④rdbchecksum yes === 保存rdb文件的时候,进行错误的校验
⑤dir ./ ==== rdb文件保存的目录
(6)主从复制(== REPLICATION == )
①前往conf配置文件里找到REPLICATION这个段
PS:这里只是它的简单配置,后面会有Redis主从复制详解
PS:上面这个输入主机地址和端口,下面输入主机的密码就行(我这个是windows下面的redis配置文件样式。高版本可能会有变化,但是一般不会太大)
(7)安全(SECURITY)
①密码设置(requirepass) === redis默认没有密码,需要我们自行设置
PS:可以看到,我们一开始查看密码,密码为空。通过set值设置密码,然后再去get查看密码,发现没有权限了。因为有密码了,这时候需要验证了:auth 密码
PS:也可以直接修改conf文件来设置密码
(8)客户端限制(CLIMNTS)
①maxclients 10000 === 设置能连接上redis的最大客户端的数量
②maxmemory === redis配置的最大内存容量
③maxmemory-policy noeviction === 内存到达上限的处理策略
1)volatile-lru:只对设置了过期时间的key进行LRU(默认值)
2)allkeys-lru : 删除lru算法的key
3)volatile-random:随机删除即将过期key
4)allkeys-random:随机删除
5)volatile-ttl : 删除即将过期的
6)noeviction : 永不过期,返回错误
(9)AOF配置(APPEND ONLY MODE)
①appendonly no === 默认不开启aof模式的。默认使用的是rdb持久化的,因为在大部分的情况下,rdb完全够用
②appendfilename “appendonly.aof” === 持久化的文件文字
③appendfysnc的配置
1)appendfsync everysec === 每秒都执行一次 sync 可能会丢失这ls的数据
2)appendfsync always === 每次修改都会sync,消耗性能
3)appendfsync no === 不执行sync, 这个时候操作系统自己同步数据,速度最快
8.Redis持久化
8.1 RDB(Redis DataBase)
①在指定的时间间隔将内存中的数据集快照写入磁盘,他恢复时是将快照文件直接读到内存里,Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好了的文件,整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高校,RDB的缺点是最后一次持久化后的数据可能丢失,我们默认的就是RDB,一般情况下不需要修改这个配置。
②触发机制
1)Save规则满足的情况下,会自动触发rdb文件
2)执行命令flushall命令,也会自动触发rdb文件
3)退出redis也会产生rdb文件
4)备注就自动生成一个dump.rdb文件
③如何恢复rdb文件
1)只需要将rdb文件放在我们redis启动目录就可以,redis启动的时候就会自动检查dump.rdb恢复其中的数据
2)怎么知道redis的启动目录:看图
④优缺点:
1)优点:
a.适合大规模的数据恢复!
b.如果你对数据完整性要求不高
2)缺点:
a.需要一定的时间间隔进程操作,如果redis意外宕机了,这个最后一次修改数据就没有了。
b.Fork进程的时候,会占用一定的内容空间
8.2 AOF(Append Only File)
①以日志的形式来记录每一个写的操作,将Redis执行过程中的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之处会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写的指令从前到后执行一次以完成数据的恢复工作。
②比如aof文件被破坏了我们可以使用redis-check-aof --fix appendonly.aof命令去修复它(如图)
PS:当aof被破坏了之后,我们去连接redis是失败的(如图)
③优缺点:
1)优点:
a.每一次修改都同步,这样会使文件完整性更好
b.默认每秒同步一次,可能会丢失一秒的数据
c.如果选择不同步的话,效率最高。
2)缺点:
a.相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢
b.Aof的运行效率也比rdb慢,所以redis默认是rdb
④注意点:如果aof文件大于配置的64m的时候,就会fork一个新的进程来将我们的文件进行重写
9.Redis发布和订阅
(1)Redis提供的发布订阅命令
(2)实例操作(如图)
10.Redis主从复制
10.1 Redis主从复制概念
①主从复制,是指将一台redis服务器的数据,复制到其它的redis服务器,前者称为主节点(master/leader),后者称为从节点(slave/follower)。数据的复制是单向的,只能由主节点到从节点,master以写为主,slave以读为主。
②默认情况下,每台redis服务器都是主节点,且一个主节点可以有多个从节点(或没有从节点),但是一个从节点只能有一个主节点。
③主从复制的作用主要包括:
1)数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式
2)故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复,实际上是一种服务的冗余。
3)负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写redis数据时应用连接主节点,读redis数据时应用连接从节点),分担服务器负载,尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高redis服务器的并发量。
4)高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是redis高可用的基础
5)注意点:一般来说,要将redis运用于工程项目中,只使用一台redis是万万不能的,原因如下:
a.从结构上来说,单个redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力过大。
b.从容量上来说,单个服务器内存容量有限,就算一台服务器内存容量为256G,也不能将所有的内存用作redis存储内存,一般来说,单台redis服务器不应该超过20G。
c.PS:电商网站上,一般都是一次上传,无数次预览,即多读少写。
10.2 环境配置
①查看当前库的信息:info replication
PS:可以看代当前redis服务器为主机,且没有从机
②复制三个配置文件,然后修改对应的信息(这是一台电脑模拟的情况下)–需要改的对应信息如下:
1)端口号
2)pid的名字
3)日志名字
4)rdb的名字
5)PS:如果开启了aof,记得aof也得改下名字
③一主二从
1)比如现在有三个redis主机:端口分别为6379 6380 6381 地址都为127.0.0.1
2)我们让6379为主机,然后剩下两个为它的从机,所以需要配置。(模型如图)
PS:操作和命令如图
PS:6381端口的redis服务器也执行同样的操作
PS:注意点:真实的主从配置应该在配置文件中配置,这样的话是永久的,使用命令的方式只是暂时的。就是一旦从机重启之后,就会重新变为主机,跟原先连接的主机没有关系了,也就是拿不到原先主机的数据了。要想重新拿到原先主机的数据就得再次执行跟随主机的命令:slaveof 主机地址 主机端口
3)复制原理
a.Slave(从机)启动成功连接到主机后会发送一个sync同步命令,主机接收到这个命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,主机将传送整个数据文件到slave,并完成一次同步。
b.全量复制:slave服务器在接受到数据库文件之后,将其存盘并加载到内存中。
c.增量复制:主机继续将所有搜集到的修改命令一次传送给从机,完成同步。
d.但是只要是重启连接主机,一次完全同步(全量复制)将被自动执行。
④第二种主从复制
1)6379服务器为第一个主节点,6380为6379的从节点但是为6381的主节点,模型如图
PS:这个需要注意的是,虽然6380是6381的主节点,但是它并没有写的权限,也是只能读
⑤手动更换主机点(当主节点断掉之后)
1)以第二种(主从复制)模型理解,当6379主机断了的时候,我们可以在6380服务器下使用命令slaveof no one来将6380更改为主机。
但是有个问题就是,当6379主机回来的时候,他不会变回为原先的主机。
10.3 哨兵模式
①概述:
1)主从切换技术的方法是:当主服务器宕机之后,需要手动切换,费时费力。所以衍生出来了哨兵模式。
2)哨兵模式是一种特殊的模式,首先redis提供了哨兵模式的命令。哨兵是一个独立的进程,作为进程,它独立存在,其原理是哨兵通过发送命令等待redis服务器响应,从未监控运行的多个redis实例。
PS:这里的哨兵有两个作用:1.通过发送命令,让redis服务器返回监控其运行的状态,包括主服务器和从服务器。2.当哨兵监测到主机宕机,会自动将从机切换为主机,然后通过发布订阅模式通知其它从服务器,修改配置文件,让它们切换主机。
PS:一个哨兵进程对redis服务器进行监控,可能会出现问题,为此我们可以使用多个哨兵进行监控,各个哨兵之间还会进行监控,这就形成了多哨兵模式
PS:假设主机服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观认为主服务器不可用,这个现象称为主观下线,当后面的哨兵也检车到主服务器不可用,并且数量达到一定峰值的时候,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover故障转移操作,切换成功以后,就会通过发布订阅模式,让各个哨兵把自己监控从服务器实现切换主机,这个过程称为客观下线。
3)开启哨兵模式:
a.先在目录下新建一个sentinel.conf文件,内容:sentinel monitor myredis 127.0.0.1 6379 2(解释如下)
a)sentinel monitor 主机名 地址 端口 数字表示当有2个哨兵认为主机宕机了那就执行failover操作
b.完整的理解一下哨兵模式的规则:
a)假如现在主机断了,哨兵1发现了,但是因为sentinel.conf文件配置的是要满足2个哨兵发现才能触发failover操作,
所以现在还不会进行failover操作。过会哨兵2也发现了,那么现在开始进行投票,最后比如还是以6379 6380 6381
这三个为例子(6379为主机):最后选定6380为新主机。加入这时候主机又重启了,他会归并到新主机下(6380),当作从机,这就是哨兵模式。
c.优缺点:
a)优点:
i.哨兵集群,基于主从复制模式,所以所有的主从配置优点,他都有
ii.主从可以切换,故障可以转移,系统的可用性就会更高
iii.哨兵模式就是主从模式的升级,手动到自动,更加健壮
b)缺点:
i.Redis不好在线扩容,集群容量一旦到达上限,在线扩容就会很麻烦
ii.实现哨兵模式的配置很麻烦
11.Redis缓存穿透和雪崩
11.1 概述
(1)Redis缓存的使用,极大的提升应用程序的性能和效率,特别是数据查询方面,但同时它也带来了一些问题,其中最要害的是数据一致性的问题,从严格意义上来说,这个问题无解,如果对数据的一致性要求很高,那么就不能使用缓存。
11.2 缓存穿透
①概念
1)缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库中没有,也就是缓存没有命中,于是向持久层数据库查询
发现没有,于是本次查询失败,当用户很多的时候,缓存没有命中,于是都去请求了持久层的数据库,
这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透
2)解决方案:
a)当存储层不命中时,即使返回的空对象也将其缓存下来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源
b)但是这种方法会存在两个问题
i.如果空值能被缓存下来,这就意味着缓存需要更多的空间存储更对的键,因为这当中会有很多的空值的键
ii.即使对空值进行了过期处理,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响
11.3 缓存击穿
(1)概念:设置了过期时间的key,这个key是一个热点数据,承载着高并发情况下,当这个key在失效的瞬间,持续的大并发就击穿缓存了,直接请求数据库,大量的请求有可能把数据库打死。
(2)解决方案:
a.设置key永远不过期,或者快过期时,通过另一个异步线程重新设置key
b.加互斥锁(代码示例如下看图)
11.4 缓存雪崩
①概念:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。
②解决办法
1)尽量避免给大量的数据设置相同的过期时间,如果业务层上有要求某些数据同时失效,可以在设置过期时间时,给这个过期时间加上
个较小的随机数,例如随机个1-3分钟。这样就不会有大量的数据同时过期失效,同时也保证了这些数据在相近的时间失效,仍然满足业务需求。
2)可以通过服务降级去应对缓存雪崩。针对不同的数据有不同的访问方式。
a.针对非核心数据,暂停从缓存中获取这些数据,而是直接返回预定义、空值或是错误信息;
b.针对核心数据,仍然走缓存,缓存找不到,继续通过数据库读取。
3)如果是因为实例发生宕机了,就需要依靠Redis缓存高可用集群了,通过发现节点宕机,将该节点切换为其它节点。