Redis 详解(基础+数据类型+事务+持久化+发布订阅+主从复制+哨兵+缓存穿透、击穿、雪崩)

本篇文章总结自【bilibili 狂神说Java Redis】【狂神说Java】Redis最新超详细版教程通俗易懂

写在前面

在需求愈来愈多元化的今天,来自客户端的大量请求如果再直接访问关系型数据的话一定会消耗过多的资源,而且大多数据也没有必要进行持久化,因由等等原因,非关系型数据库被创造出来,例如存储键值对数据的 Redis、专门存储文档型数据的 MongoDB,非关系型数据库最大的特点之一就是将数据存储在内存中,就像是挡在关系型数据库前面的一道屏障,不仅降低了资源开销,也节约了查询的时间。

Redis 是什么

  • 官方解释:Redis 是一个开源(BSD许可)的,内存数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
  • Redis是一个开源、使用C语言编写、支持网络、可持久化、存储数据于内存的日志型、K-V数据库。

基础知识/命令:

  • 官网下载 Windows 版本或 Linux 版本,Windows 版本解压双击 Redis-server.exe 即可启动,Linux 版本先解压在输入命令( redis-server 文件位置 + redis 配置文件位置):redis-server redis.conf 即可启动

  • Redis有16个数据库,默认使用第0个数据库

  • Redis是单线程的,redis将所有数据存储到内存中,使用单线程操作效率最高,redis可达到QPS(每秒查询率)10万+

  • 以下命令在 redis 客户端中测试,Windows 双击运行 Redis-Client.exe,Linux 通过命令redis-client -p 6379启动客户端
    01.使用select【num】命令可切换数据库
    02.使用keys *命令获取数据库中所有的键
    03.Flushdb命令清除当前数据库数据
    04.Flushall命令清除数据库所有数据
    05.Exists【key】判断当前key是否存在
    06.Move【key】移除当前key
    07.Expire 【key】【seconds】设置该key的过期时间,单位为秒
    08.ttl【key】查看当前key的剩余时间
    09.type【key】查看当前key的类型

  • redis-benchmark是一个压力测试工具,可使用命令redis-benchmark -h localhost -p 6379 -c 100 -n 100000去测试redis的性能

Redis五大数据类型:

String(字符串)/ 操作命令

  • String 字符串类似于 Java 中的 HashMap,一个 key 对应一个字符串,字符串可以应用为能够增减的数字,也可以为 json 字符串
  • String 类似的使用场景:计数器、统计多单位的数量、粉丝数、对象缓存存储

01.Set【key】【value】设置值,当该key存在时则覆盖value

02.Get【key】获取值

03.Append【key】【字符串】追加字符串,如果当前key不存在相当于set该key

04.Strlen【key】获取字符串的长度

05.Incr【key】使该key自增1,如果value不是数字则会报错:ERR value is not an integer or out of range(值不是数字类型或值超过范围)

06.Decr【key】使该key自减1

07.Incrby / decrby【key】【步长】可设置该key的步长,指定增量

08.Getrange【key】【start】【end】截取字符串,例如hello截取[0,3]为hell,[0,-1]则获取全部字符串

09.Setrange【key】【start】【字符串】替换指定位置开始的字符串,例如setrange abcdef 1 xx,结果为:axxdef

10.Setex【key】【seconds】【value】设置key的过期时间,相当于set with expire

11.Setnx【key】【value】如果该key不存在就创建,相当于set if not exist

12.Mset【key1】【value1】【key2】【value2】…同时设置多个k-v

13.Mget【key1】【key2】…同时获取多个值

14.Msetnx【key1】【value1】【key2】【value2】设置多个值,这是一个原子性的操作,要么一起成功,要么一起失败

15.Set user:1 {name:zhangsan,age:3} 设置一个user:1对象,值为json字符来保存一个对象

16.Getset【key】【value】先get值,如果该key不存在则创建该k-v,如果存在则覆盖原value

List(列表)/ 操作命令

  • 该数据结构类似与 HashMap<String,ArrayList>
  • 所有的 list 命令都是用 l 开头的
  • List实际上是一个链表,before Node after,与集合 LinkedList 的底层节点 Node 结构一致
  • left,right 都可以插入值;如果 key 不存在就创建新的链表,如果 key 存在则新增内容;如果移除了所有值,空链表,也代表不存在;在两边插入或者改动值,效率高,改变中间元素相对来说效率会低一点
  • 适合做消息队列(Lpush,Rpop)或栈(Lpush,Lpop)

01.Lpush【key】【value】插入一个值,插入到列表左边(头插法)

02.Rpush【key】【value】插入值,插入到列表右边(尾插法)

03.Lrange【key】【start】【end】获取列表中区间的值,[0,-1] 是获取所有值

04.Lpop【key】移除列表中最头上(左边)的一个元素

05.Rpop【key】移除列表中最后(右边)的一个元素

06.Lindex【key】【index】通过index下标获取某一个值

07.Llen【key】返回列表的长度

08.Lrem【key】【count】【value】移除key中指定count数量的value,精确匹配

09.Ltrim【key】【start】【end】截断方法,返回通过下标获取的值,其余未被返回的k-v被删除

10.Rpoplpush【key】【newkey】移除key中的最后一个元素,将其移动到newkey当中

11.Lset【key】【index】【newValue】将key中指定下标的值替换为newValue,如果该下标对应的值不存在则报错

12.Linsert【key】before/after【value】【newValue】将newValue插入到key中value的前面或后面

Set(集合)/ 操作命令

  • 该数据结构类似于 HashMap<String,HashSet>
  • Set 集合是无序不重复集合

01.Sadd【key】【value】添加元素

02.Smembers【key】获取key集合中所有值

03.Sismember【key】【value】判断某一个值是不是在set集合中

04.Scard【key】获取该key集合中的元素个数

05.Srem【key】【value】移除该key集合中指定的value

06.Srandmember【key】随机抽取key集合中的一个元素

07.Srandmember【key】【count】随机抽选出key集合中指定个数的元素

08.Spop【key】随机删除key集合中的一个元素

09.Smove【key】【newKey】【value】将一个指定的值移动到另外一个set集合

10.Sdiff【key1】【key2】取两个集合的差集

11.Sinter【key1】【key2】取两个集合交集

12.Sunion【key1】【key2】取两个集合并集

Hash(哈希)/ 操作命令

  • 该数据结构类似于 HashMap<String,HashMap<String,String>>
  • Map 集合,这时候这个值是一个 map 集合,本质和String类型没有太大区别,一个哈希 key 存储多个 key-vlaue
  • Hash 适合存储经常变动的信,适合于存储对象数据,String 更加适合字符串存储

01.Hset【hkey】【key】【value】插入一个具体的k-v

02.Hget【hkey】【key】获取hash中key的值

03.Hmset【hkey】【key1】【value1】【key2】【value2】…set多个k-v

04.Hmget【hkey】【key1】【key2】获取多个字段值

05.Hgetall【hkey】获取全部的k-v数据

06.Hdel【hkey】【key】删除hash中指定的key

07.Hlen【hkey】获取hash中字段(key)数量

08.Hexists【hkey】【key】判断hash中指定字段是否存在

09.Hkeys【hkey】只获得hash中所有key

10.Hvals【hkey】只获得hash中所有value

11.Hincrby【hkey】【key】【count】使key对应得value增加count

12.Hdecrby【hkey】【key】【count】使value减去count

13.Hsetnx【hkey】【key】【value】如果该k-v不存在则设置,存在则不能设置

操作Zset(有序集合)命令

  • 类似于数据结构HashMap<String,TreeSet>
  • 适用场景:zset存储班级成绩表,工资表排序;普通消息,1重要消息2带权重进行判断,排行榜应用实现,取Top N 测试。

01.Zadd【key】【score】【value】zset在set集合基础上新增了score值,score相当于当前value的排序值,zset可根据score来排序

02.Zadd【key】【score1】【value1】【score2】【value2】…添加多个值

03.Zrange【key】【start】【end】获取范围内的值,[0,-1]获取所有值

04.Zrangebyscore【key】-inf +inf根据score值从小到大显示所有的元素

05.Zrangebyscore【key】【down level】【up level】获取level区间的元素

06.Zrangebyscore【key】-inf +inf withscores从小到大显示全部的元素并附带score值

07.Zrevrange【key】0 -1从小到大显示所有元素

08.Zrem【key】【value】移除zset集合中指定元素

09.Zcard【key】获取zset中元素个数

10.Zcount【key】【start】【end】获取指定区间内的元素数量

Redis 三种特殊数据类型:

Geospatial 地理位置

  • 这个数据类型可以存储地点的地理位置信息,可以推算某个地点到另一个地点的距离,使用场景例如:朋友之间的定位、附近的人、地图计算到目的地的距离。

01.geoadd 通过传入经纬度添加某个地点的位置

02.geopos 获取某个地点的经纬度坐标

03.geodist 算出两个地点间直线距离,可以换算为米、千米之类的单位

04.georadius 以某经纬度为中心找出方圆XX千米内的地点

05.georadiusbymember 找出指定地点周围的地点

06.geohash 返回一个或多个位置的 Geohash 字符串

07.geo 底层的实现原理就是 Zset,可使用 Zset 命令来操作 geo

Hyperloglog 基数统计

  • HyperLogLog 是用来做基数统计的算法,基数就是不重复的元素,也就是说HyperLogLog可以统计不重复元素的个数。
  • HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
  • 在Redis里面,每个 HyperLogLog 键只需要花费 12KB 内存,就可以计算接近 2^64 个不同元素的基数,但是 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样返回输入的各个元素。
  • 使用场景例如:计算页面的用户访问量。

01.Pfadd【key】【value…】创建多个元素

02.Pfcount【key】统计key的基数数量

03.Pfmerge【newKey】【key1】【key2】合并key1和key2中的元素至newKey,同时做去重操作

Bitmap 位图

  • Bitmap 用二进制位来记录数据,只有 0 和 1 两个状态,例如记录一个人 365 天的的打卡情况,只需要 365 个二进制位,每天只有 0 和 1 两个状态。

Redis 事务 / 命令

  • Redis 在开启事务后,后续对数据的操作会存放入队列中,直到进行执行事务操作,队列中的任务会按顺序依次执行,Redis 事务具有一致性、顺序性、排他性

  • Redis事务没有隔离级别的概念,而且不保证原子性,例如某一操作在事务执行中失败,之后的操作依然执行,之前的操作也不会回滚。

  • Redis事务中分为编译型异常与运行时异常,编译型异常例如输入错误的命令,事务执行直接报错,所有命令不会执行;运行时异常例如对某个不是数字的字符串 +1 ,该操作报错但其他操作执行。

01.Multi开启事务

02.Exec执行事务

03.Discard取消事务

04.Watch【key】监控key,相当于记录当前key的版本号,在事务exec时拿之前的version与现在的version做判断,检查是否有其他线程修改了key。因此watch可以当做Redis的乐观锁操作。
例如执行watch money,再开启一个事务操作,将 money 减少 20,在事务exec之前,让第二个线程去修改 money,则exec操作时事务不会执行,报异常。

05.Unwatch【key】解除该key的操作

Redis持久化(RDB 与 AOF)

  • 持久化顾名思义就是将数据进行永久储存,也就是将内存中的数据存入硬盘当中,因为当 redis 断电后内存中的数据会丢失,所以 redis 提供了持久化功能。

RDB(Redis DataBase)

  • RDB 是 redis 持久化的一种方式。当触发持久化时,Redis 会单独创建一个子进程去进行持久化操作,先将数据写入到临时文件中,当持久化过程结束了,再把临时文件覆盖之前的rdb文件。整个过程中主进程不会进行 IO 操作。

Redis-Config 文件中关于 rdb 的配置信息(快照 snapshot ):

01.save 900 1在900s内,至少有一个1个key被修改,则进行持久化操作
02.save 300 10在300内,10个key被修改
03.save 60 10000在60秒内,10000个key被修改
04.stop-writes-on-bgsave-error yes 持久化如果出错,是否还需要继续工作
05.rdbcompression yes 是否压缩rdb文件,压缩需消耗cpu资源
06.rdbchecksum yes 保存rdb文件的时候,进行错误的检查校验!
07.dir ./ 指rdb文件保存的目录

触发持久化机制:

01.满足三个save条件之一就触发
02.执行flushall命令
03.退出redis触发

恢复rdb文件中数据

只要rdb文件位置与配置文件中dir描述的位置一致,开启redis时自动恢复rdb中数据

RBD优缺点

  • 优点:
    适合大规模数据恢复
    对数据完整性要求不高

  • 缺点:
    如果 redis 意外宕机,例如在 save 条件的前一秒宕机,则最后修改的数据未被持久化
    主进程创建子进程持久化时,会占用一定内存空间

AOF(Append Only File)

  • 官方解释:Append Only File 是另一种持久性模式,它提供了更好的持久性。例如,如果使用默认的数据 fsync 策略(请参阅配置文件后面的部分),Redis 在服务器断电等戏剧性事件中可能只会丢失一秒钟的写入操作,或者如果 Redis 进程本身发生了问题,但操作系统仍在正常运行,则只会丢失一次写入操作。

  • AOF 是 redis 持久化的第二种方式。redis 默认开启 rdb 模式,AOF 模式需修改配置文件开启。AOF 是以日志形式将用户所有的写或修改操作全部记录下来(不记录读操作),当 redis 因为宕机或其他因素自启时,会自动加载 AOF 文件从上至下依次执行原操作,以完成数据的恢复。

Redis-Config 文件中关于 AOF 的配置信息(APPEND ONLY MODE):

01.appendonly no 默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分所有的情况下,rdb完全够用,appendfilename

02.appendfilename “appendonly.aof” 持久化的文件的名字

03.appendfsync always 每次修改都会fsync()。Fsync()方法就是进行持久化操作,该配置比较消耗性能,默认关闭。

04.appendfsync everysec (Redis 开启 AOF 后默认为该操作)每秒执行一次fsync(),可能当用户在修改数据时redis突然宕机,可能会丢失这1s的数据,但也仅仅丢失这一秒的数据。

05.appendfsync no 不执行fsync(),这个时候操作系统决定持久化,速度最快。

06.no-appendfsync-on-rewrite no 默认aof文件的无限追加,文件会越来越大

07.auto-aof-rewrite-percentage 100 设置aof日志大小以指定的百分比增长

08.auto-aof-rewrite-min-size 64mb 如果aof日志大于64M,会 fork 一个新的进程来将文件进行重写

AOF 优缺点

  • 优点:
    1、每一次修改都同步到日志中,文件的完整性好
    2、每秒同步一次,仅可能丢失最后一秒的数据
    3、从不同步,效率最高
    4、如果 appendonly.aof 文件遭到恶意修改,可以使用 redis 根目录下的 redis-check-aof 程序进行修复,数据仍能恢复

  • 缺点:
    1、相对于数据文件来说,aof 远远大于 rdb,修复的速度也比 rdb 慢
    2、AOF 运行效率也要比 RDB 慢,所以我们 redis 默认的配置就是 rdb 持久化

扩展

01.如果只做缓存的话,可以关闭任何持久化

02.同时开启两种持久化方式时,redis 重启的时会优先载入 AOF 文件来恢复数据,因为在通常情况下AOF 文件保存的数据集要比 RDB 文件保存的数据集完整。RDB 的数据不实时,同时使用两者时服务器重启也只会找 AOF 文件,但也不要只使用 AOF,因为 RDB 更适合用于备份数据库(AOF 在不断变化不好备份),快速重启,而且不会有 AOF 可能潜在的 Bug,留一个后手。

03.因为 RDB 文件只用作后备用途,建议只在 Slave(从机)上持久化 RDB 文件,而且只要 15 分钟备份一次就够了,只保留 save 900 1 这条规则。

04.如果开启 AOF,好处是在恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只 load AOF 文件就可以了,代价一是带来了持续的 IO,二是 AOF rewrite 的后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少 AOF rewrite 的频率,AOF 重写的基础大小默认值 64M 太小了,可以设到 5G 以上,默认超过原大小 100% 大小重写可以改到适当的数值。

05.如果不 Enable AOF,仅靠 Master-Slave Repllcation(主从复制)实现高可用性也可以,能省掉一大笔 IO,也减少了 rewrite 时带来的系统波动。代价是如果 Master/Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的RDB文件,载入较新的文件。

Redis 发布订阅

  • Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。发送者可以创建频道并在该频道内发布消息,订阅者可以订阅任意数量的频道。
    在这里插入图片描述

消息订阅常用命令

  1. PSUBSCRIBE pattern [pattern …] 订阅一个或多个符合给定模式的频道。
  2. PUBSUB subcommand [argument [argument …]] 查看订阅与发布系统状态。
  3. PUBLISH channel message 将信息发送到指定的频道。
  4. PUNSUBSCRIBE [pattern [pattern …]] 退订所有给定模式的频道。
  5. SUBSCRIBE channel [channel …] 订阅给定的一个或多个频道的信息。
  6. UNSUBSCRIBE [channel [channel …]] 指退订给定的频道。

Redis 主从复制

  • 因为在企业级项目中需要应对并发量、数据的持久性、数据备份、高可用等问题,所以需要使用到主从复制。
  • 官方解释:主从复制,是使用 slaveof 使 Redis 实例(从机)成为另一个 Redis 服务器(主机)的副本。也就是指将一台Redis服务器的数据,复制到其他的 Redis 服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。
  • Redis默认将从机配置为只读。

主从复制的作用:

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  2. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复。
  3. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
  4. 高可用(集群)基石:主从复制还是哨兵和集群能够实施的基础,因此说主从复制是 Redis 高可用的基础

Redis.conf 中关于主从复制的配置

  1. slaveof < masterip > < masterport > 设置主机的ip地址与端口
  2. masterauth < master-password > 如果主机需用密码认证,则在该配置上配置密码
  3. slave-serve-stale-data yes 该配置表示从机与主机断开链接时从机的操作;默认yes,表从机仍响应客户端请求,但数据可能为空或过期,如果该配置为“no”,则从机将对除INFO和SLAVEOF以外的所有类型的命令回复错误“SYNC with master in progress”
  4. slave-read-only yes 默认从机只读

配置主机与从机

  • 第一种方式:
    新建从机的配置文件,修改从机配置文件:端口号、rbd 文件名、pid 名、log 日志名、slaveof 中主机ip 与端口(只需修改从机的配置),开启时例如:redis-server.exe redis.windows.confredis-server.exe redis.windows.6380.conf依次开启主机与从机

下图是主机与从机的各自信息,role 获知是主是从。如果需要第二台从机依旧新建一个配置文件并修改再开启。
在这里插入图片描述
在这里插入图片描述

  • 第二种方式:新建从机配置文件修改(端口、pid 名字、log 文件名字、dump.rdb 名),slaveof 属性不需修改,使用命令 SLAVEOF【主机ip】【主机端口】来连接主机即可,但这种方式是暂时的,永久配置使用第一种方式。

复制原理

  • slave 启动成功连接到主机后会发送一个 sync 同步数据命令,master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master 将传送整个数据文件到 slave,并完成一次完全同步(全量复制)。
  • 全量复制:slave 服务在接收到数据库文件数据后,将其存盘并加载到内存中。
  • 增量复制:master 继续将新的所有收集到的修改命令依次传给 slave,完成同步,但是只要是重新连接 master,一次完全同步(全量复制)将被自动执行。

Redis 哨兵模式

  • 当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式。
  • 这时,我们考虑哨兵模式。哨兵模式是一种特殊的模式,是一个独立的进程,它会向redis服务器发送命令,等待redis服务器响应,从而监控多个redis服务器的运行状态,如果监控到主服务器宕机,则会通过选举算法将一台从机选举为新得主机,然后通过发布订阅模式通知其他服务器并修改他们的配置文件,设置新的主机信息。
  • 多哨兵模式:当然一个哨兵也不满足高可用的需求,所以需要有时需多个哨兵同时监控,各个哨兵之间也会相互监控,例如有3个哨兵3个redis服务器,这样就会开启15条监控线。如果哨兵1监控到主服务器下线【主观下线】,不会立即选举新的主机,而是等后面的哨兵检测,当一定数量的哨兵都检测到主服务器下线,则进行投票选举新主机,再过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机【客观下线】。
  • 使用命令:redis-sentinel sentinel.conf来开启哨兵。

哨兵模式优缺点

  • 优点:
    1、哨兵集群,基于主从复制模式,所有的主从配置优点,它都有
    2、主从可以切换,故障可以转移,高可用性的系统
    3、哨兵模式就是主从模式的升级,手动到自动,更加健壮
  • 缺点:
    1、Redis不好在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦
    2、哨兵模式的配置繁琐

哨兵模式配置文件的配置信息

#Example sentinel.conf

#哨兵sentinel实例运行的端口 默认26379
port 26379

#哨兵sentinel的工作目录
dir /tmp

#哨兵sentinel监控的redis主节点的 ip port
#master-name可以自己命名的主节点名字,只能由字母A-z、数字0-9、这三个字符".-_"组成。
#quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了
#sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2
 
#当在Redis实例中开启了requirepass foobared授权密码,这样所有连接Redis实例的客户端都要提供密码 
#设置哨兵sentinel连接主从的密码,注意必须为主从设置一样的验证密码
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster XXX
#指定多少毫秒之后主节点没有应答哨兵,此时哨兵主观上认为主节点下线,默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000

# 这个配置项指定了在发生failover主备切换(选举)时多可以有多少个slave同时对新的master进行同步,数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为1来保证每次只有一个slave处于不能处理命令请求的状态。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1

#故障转移的超时时间failover-timeout可以用在以下这些方面:
#1. 同一个sentinel对同一个master两次failover之间的间隔时间。
#2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。
#4.当进行failover时,配置所有slaves指向新的master所需的大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了#默认三分钟
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000

#SCRIPTS EXECUTION

#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。#一个脚本的大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。

#通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,一个是事件的类型,一个是事件的描述。如果sentinel.conf配 置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无 法正常启动成功。
#通知脚本
# sentinel notification-script <master-name> <script-path>
sentinel notification-script mymaster /var/redis/notify.sh

#客户端重新配置主节点参数脚本
# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
#以下参数将会在调用脚本时传给脚本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>总是“failover”, # <role>是“leader”或者“observer”中的一个。
#参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的
# 这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

Redis 缓存穿透

  • 缓存穿透的概念很简单,用户想要查询一个数据,发现 redis 内存数据库没有,于是向持久层数据库查询。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就出现了缓存穿透。

缓存穿透的两种解决方案:

布隆过滤器

  • 布隆过滤器是一种数据结构,对所有可能查询的参数以 hash 形式存储,在控制层先行校验,不符合则丢弃,减小了对底层存储系统的查询压力。

缓存空对象

  • 当持久层数据库未查询到时,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了持久层数据库。
  • 但是这种方法会存在两个问题:
    1、如果空值能够被缓存起来,这当中可能会有很多储存了空值的键。
    2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

Redis 缓存击穿

  • 缓存击穿是当某个key在过期的瞬间,有大量的请求查询redis查不到而涌向持久层数据库的问题,会导使数据库瞬间压力过大。与缓存穿透的区别是,穿透是一直查redis查不到数据,而击穿是瞬间地查redis数据查不到,相同点都是会给持久化层数据库造成压力。

缓存击穿两种解决方案:

设置热点数据永不过期

从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题。

加互斥锁

使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

缓存雪崩

  • 缓存雪崩,是指在某一个时间段,缓存集中过期失效,也可能是redis集群全部宕机。大量的请求都涌向持久化数据库,数据库的调用量会暴增,造成数据库也会挂掉的情况。
  • 其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。

缓存雪崩三种解决方案:

Redis 高可用

这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,也就是搭建集群。

限流降级

这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

数据预热

数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值