Redis由浅入深详细解析(二)

事务

redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。当执行时,一次性按照添加顺序依次执行,中间不会被打断或者干扰;

事务的基本操作

#开启事务,设定事务的开启位置,此指令执行后,后续的所有指令均加入到事务中
multi

#设定事务的结束位置,同时执行事务。与multi成对出现,成对使用
exec

#终止当前事务的定义,发生在multi之后,exec之前
discard

在这里插入图片描述

事务的注意事项

1、加入事务的命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行;

2、如果定义的事务中所包含的命令存在语法错误,整体事务中所有命令均不会执行。包括那些语法正确的命令;

3、如果定义的事务中所包含的命令存在执行错误(语法没错,但执行会报错。比如对list进行incr操作),能够正确运行的命令会执行,运行错误的命令不会被执行;

数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可 能会读取和存储不正确的数据,破坏数据库的一致性。

加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作。

命令:setnx lock-key value
作用:使用 setnx 设置一个公共锁

操作完毕通过del操作释放锁。

但是由于锁操作是由用户控制加锁解锁,那么必定会存在加锁后未解锁的风险。因此解锁操作不能仅依赖用户控制,系统级别要给出对应的保底处理方案;

解决方案:使用 expire 命令为锁key添加时间限定,到时不释放,放弃锁!

expire lock-key second			秒
pexpire lock-key milliseconds	毫秒

删除策略

Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态。

  • XX :具有时效性的数据
  • -1 :永久有效的数据
  • -2 :已经过期的数据 或 被删除的数据 或 未定义的数据

那么过期的数据真的删除了吗?

Redis共有三种数据删除策略:

  1. 定时删除
  2. 惰性删除
  3. 定期删除

数据删除策略的目标:在内存占用与CPU占用之间寻找一种平衡,顾此失彼都会造成整体redis性能的下降,甚至引发服务器宕机或内存泄露。

在这里插入图片描述
当我们用以上命令为一个key设置过期时间时,在Redis中会开放出一块空间expires。

expires的键是一个指针(地址),这个指针指向键空间中的某个键对象( 也即是某个数据库键),值是一个long类型的整数,这个整数保存了键所指向的数据库键的过期时间:一个毫秒精度的UNIX 时间戳。

1、定时删除

创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作。

优点:节约内存,到时就删除,快速释放掉不必要的内存占用

缺点:CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量

总结:用处理器性能换取存储空间(拿时间换空间)

2、惰性删除

数据到达过期时间,不做处理。等下次访问该数据时:

  • 如果未过期,返回数据
  • 发现已过期,删除,返回不存在

优点:节约CPU性能,发现必须删除的时候才删除

缺点:内存压力很大,出现长期占用内存的数据

总结:用存储空间换取处理器性能 (拿时间换空间)

3、定期删除

Redis启动服务器初始化时,读取配置server.hz的值,默认为10;

每秒钟执行server.hz次serverCron函数(这个函数负责管理服务器的资源,并保持服务器自身的良好运转。默认每隔100ms执行一次)

serverCron函数每次执行时会调用databasesCron函数,这个函数会对服务器中的数据库(0-15)进行轮询。databasesCron函数执行的时候又会调用activeExpireCycle函数。
在这里插入图片描述

activeExpireCycle()对每个expires[*]逐一进行检测,每次执行250ms/server.hz

对某个expires[*]检测时,随机挑选W个key检测:

  • 如果key超时,删除key
  • 如果一轮中删除的key的数量>W*25%,循环该过程
  • 如果一轮中删除的key的数量≤W*25%,检查下一个expires[ * ],0-15循环
  • W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值

参数current_db用于记录activeExpireCycle() 进入哪个expires[*] 执行,如果activeExpireCycle()执行时间到期,下次从current_db继续向下执行。

周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度

优点:

  1. CPU性能占用设置有峰值,检测频度可自定义设置
  2. 内存压力不是很大,长期占用内存的冷数据会被持续清理

总结:周期性抽查存储空间(随机抽查,重点抽查)

4、3种策略对比

删除策略内存cpu
定时删除节约内存,无占用不分时段占用CPU资源,频度高
惰性删除内存占用严重延时执行,CPU利用率高
定期删除内存定期随机清理每秒花费固定的CPU资源维护内存

逐出算法

当新数据进入redis时,如果内存不足怎么办?

Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法;

注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息;
在这里插入图片描述
影响数据逐出的相关配置

#最大可使用内存(占用物理内存的比例,默认值为0,表示不限制。生产环境中根据需求设定,通常设置在50%以上)
maxmemory

#每次选取待删除数据的个数(选取数据时并不会全库扫描,导致严重的性能消耗,降低读写性能。因此采用随机获取数据的方式作为待检测删除数据)
maxmemory-samples

#删除策略(达到最大内存后的,对被挑选出来的数据进行删除的策略)
maxmemory-policy

逐出策略包括以下三种:

一、检测易失数据(可能会过期的数据集server.db[i].expires )

  • volatile-lru:挑选最近最少使用的数据淘汰
  • volatile-lfu:挑选最近使用次数最少的数据淘汰
  • volatile-ttl:挑选将要过期的数据淘汰
  • volatile-random:任意选择数据淘汰

二、检测全库数据(所有数据集server.db[i].dict )

  • allkeys-lru:挑选最近最少使用的数据淘汰
  • allkeys-lfu:挑选最近使用次数最少的数据淘汰
  • allkeys-random:任意选择数据淘汰

三、放弃数据驱逐

  • no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),会引发错误OOM(Out Of Memory)

在这里插入图片描述

Redis 核心配置

服务器端设定

1、设置服务器以守护进程的方式运行;
daemonize yes|no

2、绑定主机地址
bind 127.0.0.1     //如果设定了此配置,则只允许通过配置的IP访问服务器。不设置则其它IP也可以访问!

3、设置服务器端口号
port 6379

4、设置数据库数量
databases 16

日志配置

1、设置服务器以指定日志记录级别
loglevel debug|verbose|notice|warning

2、日志记录文件名
logfile 端口号.log

客户端配置

1、设置同一时间最大客户端连接数,默认无限制。当客户端连接到达上限,Redis会关闭新的连接
maxclients 0

2、客户端闲置等待最大时长,达到最大值后关闭连接。如需关闭该功能,设置为 0
timeout 300

高级数据类型

Redis共有三种高级数据类型:

  1. Bitmaps
  2. HyperLogLog
  3. GEO

这三种类型的具体使用命令可以查阅文档,平时也很少用,了解下就行,传送门 ----- Redis 教程 | 菜鸟教程

Bitmaps

bitmap是一种伪数据类型,是基于String实现的;

使用场景:可以用于布尔型数据的存取,比如用户一年的签到记录,签到了是1,没签到是0,记录365天,通过 bitcount 指令来统计用户一共签到了多少天,每个签到记录只占用一位,365位大约是46个字节大小,用户上亿时,大大节约了内存空间;

HyperLogLog

HyperLogLog 是用来做基数统计的,运用了LogLog的算法;

在这里插入图片描述
注意: 仅用于进行基数统计,不是集合,不保存数据,只记录数量而不是具体数据!

GEO

GEO主要应用于地理位置计算;

在这里插入图片描述

主从复制

主从复制即将master中的数据即时、有效的复制到slave中
在这里插入图片描述

为了避免单点Redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服务器上,连接在一起,并保证数据是同步的。即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用,同时实现数据冗余备份;

主从复制的作用:

  1. 读写分离:master写、slave读,提高服务器的读写负载能力
  2. 负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
  3. 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
  4. 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式

主从复制工作流程

主从复制完整过程大体可以分为3个阶段:

  1. 建立连接阶段(即准备阶段)
  2. 数据同步阶段
  3. 命令传播阶段

在这里插入图片描述

阶段一:建立连接阶段

建立slave到master的连接,使master能够识别slave,并保存slave端口号,主要分为以下五个步骤:

  1. 设置master的地址和端口,保存master信息
  2. 建立socket连接
  3. 发送ping命令(定时任务,用于测试slave与master的连接是否正常)
  4. 身份验证(如果master有配置访问密码则需要进行验证)
  5. 发送slave端口信息
    在这里插入图片描述

至此,主从连接成功,实现最终的目的:

  • slave保存了master的地址和端口
  • master保存了slave的端口

主从连接(slave连接master)的三种方式:

  1. 客户端发送命令:slaveof < masterip > < masterport >
  2. 启动服务器参数:redis-server -slaveof < masterip > < masterport >
  3. 服务器配置:slaveof < masterip > < masterport >

Redis Slaveof 命令可以将当前服务器转变为指定服务器的从属服务器(slave server);

另外,对一个从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。

利用『 SLAVEOF NO ONE 不会丢弃同步所得数据集』这个特性,可以在主服务器失败的时候,将从属服务器用作新的主服务器,从而实现无间断运行

阶段二:数据同步阶段工作流程

在slave初次连接master后,复制master中的所有数据到slave,将slave的数据库状态更新成master当前的数据库状态,共分为以下五个步骤:

  1. 请求同步数据
  2. 创建RDB同步数据
  3. 恢复RDB同步数据
  4. 请求部分缓冲区同步数据
  5. 恢复部分缓冲区同步数据

在这里插入图片描述

至此,数据同步工作完成,实现最终目的:

  • slave具有master端全部数据,包含RDB过程接收的数据
  • master保存slave当前数据同步的位置

数据同步阶段master说明:

  1. 如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行

  2. 复制缓冲区大小设定不合理,会导致数据溢出。如进行全量复制周期太长,进行部分复制时发现数据已经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态

    repl-backlog-size 1mb
    
  3. master单机内存占用主机内存的比例不应过大,建议使用50%-70%的内存,留下30%-50%的内存用于执行bgsave命令和创建复制缓冲区

数据同步阶段slave说明:

  1. 为避免slave进行全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭此期间的对外服务

    slave-serve-stale-data yes|no
    
  2. 数据同步阶段,master发送给slave信息可以理解master是slave的一个客户端,主动向slave发送命令

  3. 多个slave同时对master请求数据同步,master发送的RDB文件增多,会对带宽造成巨大冲击,如果master带宽不足,因此数据同步需要根据业务需求,适量错峰

阶段三:命令传播阶段

当同步操作完成之后,主服务器会进行相应的修改命令,这时候从服务器和主服务器状态就会不一致。

为了让主服务器和从服务器保持状态一致,主服务器需要对从服务器执行命令传播操作,主服务器会将自己的写命令发送给从服务器执行(一句话就是master将接收到的数据变更命令发送给slave,slave接收命令后执行命令)。从服务器执行相应的命令之后,主从服务器状态继续保持一致;

总结:通过同步操作以及命令传播功能,能够很好的保证了主从一致的特性。

部分复制工作原理

如果命令传播阶段出现了断网现象:

  • 网络闪断闪连:忽略
  • 短时间网络中断:部分复制(AOF)
  • 长时间网络中断:全量复制(RDB)

部分复制的三个核心要素:

  1. 服务器的运行 id(run id)
  2. 主服务器的复制积压缓冲区
  3. 主从服务器的复制偏移量

1、服务器运行ID(runid)

服务器运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行id

运行id由40位字符组成,是一个随机的十六进制字符,例如:fdc9ff13b9bbaab28db42b3d50f852bb5e3fcdce

运行id被用于在服务器间进行传输,识别身份,如果想两次操作均对同一台服务器进行,必须每次操作携带对应的运行id,用于对方识别;

运行id在每台服务器启动时自动生成的,master在首次连接slave时,会将自己的运行ID发送给slave,slave保存此ID,通过info Server命令,可以查看节点的runid;

2、复制缓冲区

复制缓冲区,又名复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区;

在这里插入图片描述

当master接收到主客户端的指令时,除了将指令执行,会将该指令存储到缓冲区中;

复制缓冲区默认数据存储空间大小是1M,由于存储空间大小是固定的,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列;

每台服务器启动时,如果开启有AOF或被连接成为master节点,即创建复制缓冲区,用于保存master收到的所有指令(仅影响数据变更的指令,例如set,select);

主从服务器复制偏移量(offset)

一个数字,描述复制缓冲区中的指令字节位置

分类:

  • master复制偏移量:master在处理完写入命令后,会把命令的字节长度做累加记录(统计信息在info replication中的master_repl_offset指标中);
  • slave复制偏移量:slave接收主节点的字节数,比如从节点接收主节点传来的 N 个字节数据时,从节点的 offset 会增加 N;

偏移量的作用非常大,它是用来衡量主从节点数据是否一致的唯一标准,如果主从节点的 offset 相等,表明数据一致,否则表明数据不一致。

在不一致的情况下,可以根据两个节点的 offset 找出从节点的缺少的那部分数据。比如,主节点的 offset 是 500,从节点的 offset 是 400,那么主节点在进行数据传输时只需要将 401 ~ 500 传递给从节点即可,这就是部分复制;

从节点通过心跳每秒都会将自身的偏移量告知主节点,所以主节点会保存从节点的偏移量。同时,主节点处理完命令后,会将命令的字节长度累加到自身的偏移量中,如下图:

在这里插入图片描述

从节点每次接受到主节点发送的命令后,也会累加到自身的偏移量中,并且记录主节点复制偏移量,如下图:

在这里插入图片描述

心跳机制

进入命令传播阶段候,master与slave间需要进行信息交换,使用心跳机制进行维护,实现双方连接保持在线

master心跳:

  • 指令:PING
  • 周期:由repl-ping-slave-period决定,默认10秒
  • 作用:判断slave是否在线
  • 查询:INFO replication 获取slave最后一次连接时间间隔,lag项维持在0或1视为正常

slave心跳任务:

  • 指令:REPLCONF ACK {offset}
  • 周期:1秒
  • 作用1:汇报slave自己的复制偏移量,获取最新的数据变更指令
  • 作用2:判断master是否在线

心跳阶段注意事项

当slave多数掉线,或延迟过高时,master为保障数据稳定性,将拒绝所有信息同步操作

#举个例子,如果我们向主服务器提供以下设置:

min-slaves-to-write 3
min-slaves-max-lag 10

那么在从服务器的数量少于3个,或者三个从服务器的延迟(lag)值都大于或等于10秒时,
主服务器将拒绝所有信息同步操作,这里的延迟值就是上面提到的INFO replication命令的lag 值

slave数量由slave发送REPLCONF ACK命令做确认,slave延迟由slave发送REPLCONF ACK命令做确认。

哨兵模式

哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master;

在这里插入图片描述
多个哨兵:

在这里插入图片描述

哨兵的作用

1、监控

  • 不断的检查master和slave是否正常运行
  • master存活检测、master与slave运行情况检测

2、通知(提醒)

  • 当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知

3、自动故障转移

  • 断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的服务器地址

注意:哨兵也是一台redis服务器,只是不提供数据服务,并且哨兵配置数量通常为单数(哨兵投票时不会打平)

配置哨兵

1、`设置哨兵监听的主服务器信息

设置哨兵监听的主服务器信息
sentinel monitor<自定义服务名称><主机地址><端口><票数>

示例:sentinel monitor mymaster 127.0.0.1 6379 2
Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 127.0.0.1 , 端口号为 6379 , 
而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)

2、设置哨兵判定服务器挂掉的时间周期(默认30秒)

指定哨兵在监控Redis服务时,判定服务器挂掉的时间周期,默认30秒(30000),也是主从切换的启动条件之一
sentinel down-after-milliseconds <服务名称><毫秒数(整数)>

示例:sentinel down-after-milliseconds mymaster 3000
3s内mymaster无响应,则认为mymaster宕机了

3、设置故障切换的最大超时时间

指定出现故障后,故障切换的最大超时时间,超过该值,认定切换失败,默认3分钟
sentinel failover-timeout <服务名称><毫秒数(整数)>

示例:sentinel failover-timeout mymaster 10000  
若sentinel在10s内未能完成failover(故障转移)操作(即故障时master/slave自动切换),则认为本次failover失败

4、指定同时进行主从的slave数量

在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长
sentinel parallel-syncs <服务名称><服务器数(整数)>

示例:sentinel parallel-syncs mymaster 1
执行故障转移时, 最多有1个从服务器同时对新的主服务器进行同步

5、启动哨兵

redis-sentinel sentinel-端口号.conf

哨兵工作原理

哨兵在进行主从切换过程中经历三个阶段:

  • 监控
  • 通知
  • 转移

阶段一:监控阶段

监控阶段用于同步各个节点的状态信息

  • 获取各个sentinel的状态(是否在线)
  • 获取master的状态(比如master属性、各个slave的详细信息)
  • 获取所有slave的状态(根据master中的slave信息)

阶段二:通知阶段

哨兵启动后会与要监控的主数据库建立两条连接;

在这里插入图片描述
和主数据库连接建立完成后,哨兵会使用连接2发送如下命令:

  1. 每10秒钟哨兵会向主数据库和从数据库发送INFO 命令
  2. 每2秒钟哨兵会向主数据库和从数据的_sentinel_:hello频道发送自己的消息
  3. 每1秒钟哨兵会向主数据、从数据库和其他哨兵节点发送PING命令

首先,发送INFO命令会返回当前数据库的相关信息(运行id,从数据库信息等)从而实现新节点的自动发现,前面提到的配置哨兵时只需要监控Redis主数据库即可,因为哨兵可以借助INFO命令来获取所有的从数据库信息(slave),进而和这两个从数据库分别建立两个连接。在此之后哨兵会每个10秒钟向已知的主从数据库发送INFO命令来获取信息更新并进行相应的操作

接下来哨兵向主数据库的_sentinel_:hello 频道发送信息来与同样监控该数据库的哨兵分享自己的信息,发送信息内容为:

<哨兵的地址>,<哨兵的端口>,<哨兵的运行ID>,<哨兵的配置版本>,
<主数据库的名字>,<主数据库的地址>,<主数据库的端口>,<主数据库的配置版本>

在这里插入图片描述
哨兵通过监听的_sentinel_:hello频道接收到其他哨兵发送的消息后会判断哨兵是不是新发现的哨兵,如果是则将其加入已发现的哨兵列表中并创建一个到其的连接(哨兵与哨兵只会创建用来发送PING命令的连接,不会创建订阅频道的连接)

实现了自定发现从数据库和其他哨兵节点后,哨兵要做的就是定时监控这些数据和节点运行情况,每隔一定时间向这些节点发送PING命令来监控,间隔时间和down-after-milliseconds选项有关,down-after-milliseconds的值小于1秒时,哨兵会每隔down-after-milliseconds指定的时间发送一次PING命令,示例如下:

// 每隔1秒发送一次PING命令
sentinel down-after-milliseconds mymaster 1000

主观下线

当超过down-after-milliseconds指定时间后,如果被PING的数据库或节点仍然未回复,则哨兵认为其主观下线;

客观下线

在主观下线后,如果该节点是主数据库,则哨兵会进一步判断是否需要对其进行故障恢复,哨兵发送SENTINEL is-master-down-by-addr 命令询问其他哨兵节点以了解他们是否也认为该主数据库主观下线,如果达到指定数量时,哨兵会认为其客观下线,并选举领头的哨兵节点对主从系统发起故障恢复。这个指定数量就是前面配置的票数

sentinel monitor mymaster 127.0.0.1 6380 2

该配置表示只有当至少有两个Sentinel节点(包括当前节点)认为该主数据库主观下线时,当前哨兵节点才会认为该主数据库客观下线,接下来选举领头哨兵。

选举领头哨兵

当前哨兵虽然发现了主数据客观下线,需要故障恢复,但故障恢复需要由领头哨兵来完成。这样来保证同一时间只有一个哨兵来执行故障恢复,选举领头哨兵的过程使用了Raft算法,Raft算法这里就不在深入讨论;

阶段三:故障转移阶段

选出领头哨兵后,领头哨兵将会开始对主数据库进行故障恢复。步骤如下:

  1. 首先领头哨兵将从停止服务的主数据库的从数据库中挑选一个来充当新的主数据库;
  2. 选出一个从数据库后,领头哨兵将向从数据库发送SLAVEOF NO ONE命令使其升格为主数据库;
  3. 而后领头哨兵向其他从数据库发送 SLAVEOF命令来使其成为新主数据库的从数据库
  4. 最后一步则是更新内部的记录,将已经停止服务的旧的主数据库更新为新的主数据库的从数据库,使得当其恢复服务时自动以从数据库的身份继续服务

缓存预热、雪崩、击穿、穿透

缓存预热

缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

缓存雪崩

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩!

解决方案:大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件!

缓存击穿

缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞;

解决方案:让缓存永不过期;

缓存穿透

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞

比如传入的参数为-1,这个-1,就是一定不存在的对象。就会每次都去查询数据库,而每次查询都是空,每次又都不会进行缓存。假如有恶意攻击,就可以利用这个漏洞,对数据库造成压力,甚至压垮数据库。即便是采用UUID,也是很容易找到一个不存在的KEY,进行攻击

解决方案:采用缓存空值的方式,如果从数据库查询的对象为空,也放入缓存,只是设定的缓存过期时间较短,比如设置为60秒;

性能指标监控

主要监控这5类:

  • 性能指标:Performance
  • 内存指标:Memory
  • 基本活动指标:Basic activity
  • 持久性指标:Persistence
  • 错误指标:Error

1、性能指标:Performance

NameDescription
latencyRedis响应一个请求的时间
instantaneous_ops_per_sec平均每秒处理总数
hit rate缓存命中率

缓存命中率如何计算?

Redis服务器上,运行命令info:

里面会有如下两个参数:
keyspace_hits:命中的次数
keyspace_misses:没有命中的次数

缓存命中率 = keyspace_hits / (keyspace_hits + keyspace_misses)

2、内存指标:Memory

NameDescription
used_memory已使用内存
mem_fragmemtation_ratio内存碎片率
evicted_keys由于最大内存限制被移除的key的数量
blocked_clients由于BLPOP,BRPOP、BRPOPLPUSH而被阻塞的客户端

3、基本活动指标:Basic activity

NameDescription
connected_clients客户端连接数
connected_slavesSlave数量
master_last_io_seconds_ago最近一次主从交互后的秒数
keyspace数据库中key的总数

4、持久性指标:Persistence

NameDescription
rdb_last_save_time最后一次持久化保存到磁盘的时间戳
rdb_change_since_last_time自最后一次持久化以来数据库的更改数

5、错误指标:Error

NameDescription
rejected_connections由于达到maxclient限制而被拒绝的连接数
keyspace_misseskey值查找失败(没有命中)次数
master_link_down_since_seconds主从断开的持续时间,以秒为单位

总结

Redis由浅入深详细解析(一)

本文仅总结笔记作后续复习理解使用,如果有侵犯到原作者,请第一时间通知我,我会进行处理,感谢!!!

本文参考资料:


版权声明:本文为z1790424577原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。