欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > redis组件在PAAS平台运维总结

redis组件在PAAS平台运维总结

2025/4/27 0:31:51 来源:https://blog.csdn.net/lijunwusino/article/details/147443941  浏览:    关键词:redis组件在PAAS平台运维总结

背景

每个集群都有redis,日常运维中redis组件出现问题概率相对较多,总结一下较为全面而实用的文档资料,为初学者提供参考;注:有些文字引用了优秀博客文章以及官方文档 。

一、了解redis必知必会的基础概念

1.1、什么是Redis

Redis是一个开源、基于内存、使用C语言编写的key-value数据库,并提供了多种语言的API。它的数据结构十分丰富。

Redis的优势:

  1. 完全基于内存,数据存在内存中,绝大部分请求是纯粹的内存操作,非常快速,跟传统的磁盘文件数据存储相比,避免了通过磁盘IO读取到内存这部分的开销。
  2. 数据结构简单,对数据操作也简单。Redis中的数据结构是专门进行设计的,每种数据结构都有一种或多种数据结构来支持。Redis正是依赖这些灵活的数据结构,来提升读取和写入的性能。
  3. 采用单线程,省去了很多上下文切换的时间以及CPU消耗,不存在竞争条件,不用去考虑各种锁的问题,不存在加锁释放锁操作,也不会出现死锁而导致的性能消耗。
  4. 使用基于IO多路复用机制的线程模型,可以处理并发的链接。

1.2、什么是Redis集群

Redis 3.0加入了Redis的集群模式,实现了数据的分布式存储,对数据进行分片,将不同的数据存储在不同的master节点上面,从而解决了海量数据的存储问题。

1.3、Redis的五种数据结构:

  1. String:Redis最基本的数据类型,一个键对应一个值,一个键值最大存储512MB
  2. set:是String字符串类型的无序集合,也不可重复
  3. zset:是String类型的有序集合,也不可重复。有序集合中的每个元素都需要指定一个分数,根据分数对元素进行升序排序
  4. hash:hash是一个键值对的集合,是一个String类型的field和value的映射表,适合用于存储对象
  5. list:是redis的简单的字符串列表,按插入顺序排序

数据类型,其实就是数据的保存形式,但是数据类型的底层实现是最重要的,底层的数据结构主要分为6种,分别是简单动态字符串、双向链表、压缩链表、哈希表、跳表和整数数组。各个数据类型和底层结构的对应关系如下:

各个底层实现的时间复杂度如下:

可以看出除了string类型的底层实现只有一种数据结构,其他四种均有两种底层实现,这四种类型为集合类型,其中一个键对应了一个集合的数据

1.4、Redis和memcahce的区别?

memcache是一个纯缓存的键值数据库,而Redis是一个非关系型的数据库。

两者的差异较大,却仍然大部分的人问二者的区别?因为很多人对Redis的应用,主要是和memcache一样,作为键值缓存数据库来用的。

要知道,Redis不仅仅是缓存数据库,接下来,我们要深入Redis的应用场景,探寻它能为我们来解决什么样的问题。

1.5、Redis有哪些应用场景?

Redis是一个高性能的缓存,一般应用在 Session 缓存、队列、排行榜、计数器、最近最热文章、最近最热评论、发布订阅等。

众多语言都支持Redis,因为Redis交换数据快,在服务器中常用来存储一些需要频繁调取的数据,节省内存开销,也极大的提升了速度。

将一些热点数据存储到Redis中,要用的时候,直接从内存取,极大的提高了速度和节约了服务器的开销。

可以这样讲,Redis适用于数据实时性要求高、数据存储有过期和淘汰特征的、不需要持久化或者只需要保证弱一致性、逻辑简单的场景。

1).缓存

缓存肯定是大家应用场景最多的一个方向,几乎现在所有的中大型网站,都用到了缓存。

合理的使用缓存不但能提高网页的访问速度,也能够降低后端数据库的压力。

根据数据类型和实际使用情况,设置灵活的键值过期策略,又可以保障数据的有效性,所以用在缓存的场合非常多。

2).计数器

计数器究竟是什么?

我们可以通过我们实际的例子来说明,比如博主写了一篇博文,有多少人来浏览,博客网站都会有记录。

那么这个记录怎么来做,每次浏览的话,这个记录都会+1 ,当浏览人数太多的时候,或者文章基数较大的时候,每次都去数据库来操作读写这个数据,肯定对后端数据库会有较大的压力。

如果我们使用Redis的incr来实现这个功能,在内存中来计数,不但性能好,还可以减轻后端数据库的压力。所以是Redis!

3).排行榜

比如音乐或者某比赛排行榜,我们可以使用音乐名作为元素,使用播放次数作为分值。

如果使用Redis的zadd来实现这个功能,使用zrevrange 来按照分值获取前10名或者50名的歌曲,或者获取歌曲排名,都是操作比较容易的,试想一下这种范围取值,如果使用Mysql来操作,一般会全表扫描,对I/O、数据库都是压力,所以是Redis。

4).定位功能(3.2开始支持)

Redis的 GEO特性,我们可以通过提前输入具体的地理位置信息,经纬度一些主要内容,在使用时,可以快读定位到APP使用者的位置,以及位置之间的距离等。

5).简单的消息系统

在日常的应用开发中,消息队列的使用还是比较常见的,Redis也有阻塞队列的功能。能够让程序在执行时被另一个程序添加到队列。

6).交友

我们可以存储好友的信息,比如爱好、兴趣等,通过使用Set集合的差查找爱好不同,或者爱好相同的点,增加交友匹配度等。

1.6、关于redis雪崩、击穿、穿透三个概念理解与解决思路

关于雪崩

雪崩概念:

如果缓在某一个时刻出现大规模的key失效,那么就会导致大量的请求打在了数据库上面,导致数据库压力巨大,如果在高并发的情况下,可能瞬间就会导致数据库宕机。这时候如果运维马上又重启数据库,马上又会有新的流量把数据库打死。这就是缓存雪崩

为什么会发生雪崩

  1. 第一种是Redis宕机
  2. 第二种可能就是采用了相同的过期时间

雪崩解决方案:

事前:

  1. 均匀过期:设置不同的过期时间,让缓存失效的时间尽量均匀,避免相同的过期时间导致缓存雪崩,造成大量数据库的访问。
  2. 分级缓存:第一级缓存失效的基础上,访问二级缓存,每一级缓存的失效时间都不同。
  3. 热点数据缓存永远不过期
  4. 保证Redis缓存的高可用,防止Redis宕机导致缓存雪崩的问题。可以使用主从+哨兵,Redis集群来避免 Redis 全盘崩溃的情况

事中:

  1. 互斥锁:在缓存失效后,通过互斥锁或者队列来控制读数据写缓存的线程数量,比如某个key只允许一个线程查询数据和写缓存,其他线程等待。这种方式会阻塞其他的线程,此时系统的吞吐量会下降
  2. 使用熔断机制,限流降级。当流量达到一定的阈值,直接返回“系统拥挤”之类的提示,防止过多的请求打在数据库上将数据库击垮,至少能保证一部分用户是可以正常使用,其他用户多刷新几次也能得到结果。

事后:

  1. 开启Redis持久化机制,尽快恢复缓存数据,一旦重启,就能从磁盘上自动加载数据恢复内存中的数据。

永不过期实际包含两层意思:

  1. 物理不过期,针对热点key不设置过期时间
  2. 逻辑过期,把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建

关于击穿

击穿概念

缓存击穿跟缓存雪崩有点类似,缓存雪崩是大规模的key失效,而缓存击穿是某个热点的key失效,大并发集中对其进行请求,就会造成大量请求读缓存没读到数据,从而导致高并发访问数据库,引起数据库压力剧增。这种现象就叫做缓存击穿。

为什么会发生击穿

关键在于某个热点的key失效了,导致大并发集中打在数据库上。

解决方向

  1. 第一是否可以考虑热点key不设置过期时间
  2. 第二是否可以考虑降低打在数据库上的请求数量

解决方案

  1. 在缓存失效后,通过互斥锁或者队列来控制读数据写缓存的线程数量,比如某个key只允许一个线程查询数据和写缓存,其他线程等待。这种方式会阻塞其他的线程,此时系统的吞吐量会下降
  2. 热点数据缓存永远不过期。

关于穿透

穿透概念

缓存穿透是指用户请求的数据在缓存中不存在即没有命中,同时在数据库中也不存在,导致用户每次请求该数据都要去数据库中查询一遍。如果有恶意攻击者不断请求系统中不存在的数据,会导致短时间大量请求落在数据库上,造成数据库压力过大,甚至导致数据库承受不住而宕机崩溃。

为什么会发生穿透

缓存穿透的关键在于在Redis中查不到key值,它和缓存击穿的根本区别在于传进来的key在Redis中是不存在的。假如有黑客传进大量的不存在的key,那么大量的请求打在数据库上是很致命的问题,所以在日常开发中要对参数做好校验,一些非法的参数,不可能存在的key就直接返回错误提示。

解决方案

  1. 将无效的key存放进Redis中:当出现Redis查不到数据,数据库也查不到数据的情况,我们就把这个key保存到Redis中,设置value="null",并设置其过期时间极短,后面再出现查询这个key的请求的时候,直接返回null,就不需要再查询数据库了。但这种处理方式是有问题的,假如传进来的这个不存在的Key值每次都是随机的,那存进Redis也没有意义。
  2. 使用布隆过滤器:如果布隆过滤器判定某个 key 不存在布隆过滤器中,那么就一定不存在,如果判定某个 key 存在,那么很大可能是存在(存在一定的误判率)。于是我们可以在缓存之前再加一个布隆过滤器,将数据库中的所有key都存储在布隆过滤器中,在查询Redis前先去布隆过滤器查询 key 是否存在,如果不存在就直接返回,不让其访问数据库,从而避免了对底层存储系统的查询压力。

如何选择解决方案

针对一些恶意攻击,攻击带过来的大量key是随机,那么我们采用第一种方案就会缓存大量不存在key的数据。那么这种方案就不合适了,我们可以先对使用布隆过滤器方案进行过滤掉这些key。所以,针对这种key异常多、请求重复率比较低的数据,优先使用第二种方案直接过滤掉。而对于空数据的key有限的,重复率比较高的,则可优先采用第一种方式进行缓存。

1.7、Redis集群中节点的通信机制

gossip协议

Redis集群的数据分布算法

 Redis集群采用的算法是哈希槽分区算法。Redis集群中有16384个哈希槽(槽的范围是0-16383,哈希槽),将不同的哈希槽分布在不同的Redis节点上面进行管理,也就是说每个Redis节点只负责一部分的哈希槽。在对数据进行操作的时候,集群会对使用CRC16算法对key进行计算并对16384取模(slot = CRC16(key)%16383),得到的结果就是 Key-Value 所放入的槽,通过这个值,去找到对应的槽所对应的Redis节点,然后直接到这个对应的节点上进行存取操作。

使用哈希槽的优势

使用哈希槽的好处就在于可以方便的添加或者移除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;哈希槽数据分区算法具有以下几种特点:

  1. 解耦数据和节点之间的关系,简化了扩容和收缩难度;
  2. 节点自身维护槽的映射关系,不需要客户端代理服务维护槽分区元数据
  3. 支持节点、槽、键之间的映射查询,用于数据路由,在线伸缩等场景

关于槽的迁移与指派命令

CLUSTER ADDSLOTS 0 1 2 3 4 ... 5000

集群扩容

  1. 启动新节点
  2. 使用cluster meet命令将新节点加入到集群
  3. 迁移槽和数据:添加新节点后,需要将一些槽和数据从旧节点迁移到新节点

集群收缩

  1. 迁移槽。
  2. 忘记节点。通过命令 cluster forget {downNodeId} 通知其他的节点

1.8、哨兵机制

什么是哨兵模式

    在主从模式下(主从模式就是把所有哨兵去掉),master节点负责写请求,然后异步同步给slave节点,从节点负责处理读请求。如果master宕机了,需要手动将从节点晋升为主节点,并且还要切换客户端的连接数据源。这就无法达到高可用,而通过哨兵模式就可以解决这一问题。

哨兵模式是Redis的高可用方式,哨兵节点是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过sentinel代理访问redis的主节点,当redis的主节点挂掉时,哨兵会第一时间感知到,并且在slave节点中重新选出来一个新的master,然后将新的master信息通知给client端,从而实现高可用。这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息

哨兵的主要工作任务

  1. 监控:哨兵会不断地检查你的Master和Slave是否运作正常。
  2. 提醒:当被监控的某个Redis节点出现问题时,哨兵可以通过 API 向管理员或者其他应用程序发送通知。
  3. 自动故障迁移:当一个Master不能正常工作时,哨兵会进行自动故障迁移操作,将失效Master的其中一个Slave升级为新的Master,并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用新Master代替失效Master

哨兵模式的工作原理

  1. 心跳机制
  2. 判断master节点是否下线
  3. 基于Raft算法选举领头sentinel
  4. 故障转移
  5. 修改配置

1.9、持久化机制

什么是持久化机制

     Redis是一个基于内存的数据库,所有的数据都存放在内存中,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是Redis的持久化机制。

Redis的持久化机制有两种:第一种是RDB快照,第二种是AOF日志

RDB快照

    RDB快照就是把数据以快照的形式保存在磁盘上,是某个时间点的一次全量数据备份,以二进制序列化形式的文件存储,并且在存储上非常紧密。RDB持久化是指在指定的时间间隔内将内存中的数据集以快照的方式写入磁盘,并保存到一个名为dump.rdb的二进制文件中,也是默认的持久化方式,它恢复时是将快照文件从磁盘直接读到内存里。

RDB持久化触发机制有三种:save、bgsave、自动化触发。

RDB快照优势

  1. RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。
  2. 对于大规模数据的恢复,且对于数据恢复的完整性不是非常敏感的场景,RDB的恢复速度要比AOF方式更加的高效。
  3. 生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。

RDB快照劣势

  1. fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑。
  2. 当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。
  3. 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。

AOF日志

     每次都使用RDB机制全量备份的方式是非常耗时间的,因此Redis还提供了另一种持久化机制AOF(append only file)。AOF日志是持续增量的备份,将Redis执行过的每个写操作以日志的形式记录下来(读操作不记录),只许追加文件但不可以改写文件(appendonly.aof文件)。redis启动的时候会读取该文件进行数据恢复,根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

AOF持久化触发机制

  1. 每修改同步:appendfsync always同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好。
  2. 每秒同步:appendfsync everysec异步操作,每秒记录,如果一秒内宕机,有数据丢失。
  3. 不同步:appendfsync no从不同步

AOF日志优势

  1. AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。
  2. AOF只是追加写日志文件,对服务器性能影响较小,速度比RDB要快,消耗的内存较少
  3. AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。
  4. AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据。

AOF日志劣势

  1. 对于相同数据集的数据而言,aof文件要远大于rdb文件,恢复速度慢于rdb。
  2. 对于每秒一次同步的情况,aof运行效率要慢于rdb,不同步效率和rdb相同。

注:如果同时开启两种持久化方式,在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

Redis4.0的混合持久化

    大量数据使用粗粒度(时间上)的rdb快照方式,性能高,恢复时间快。

    增量数据使用细粒度(时间上)的AOF日志方式,尽量保证数据的不丢失。

RDB快照和AOF日志的区别

  1. RDB快照是一次全量备份,AOF是连续的增量备份。
  2. RDB快照是内存数据的二进制序列化形式,在存储上非常紧凑,而 AOF 日志记录的是内存数据修改的指令记录文本。
  3. RDB:内存中数据集的快照,默认开启,恢复速度快,数据容易丢失。
  4. AOF:操作日志,默认关闭,恢复速度慢,安全。

1.10、Redis的分布式锁

什么是分布式锁

    分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是,分布式系统中竞争共享资源的最小粒度从线程升级成了进程。

分布式锁应该具备哪些条件

  1. 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
  2. 高可用的获取锁与释放锁
  3. 具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
  4. 具备锁失效机制,即自动解锁,防止死锁
  5. 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败

分布式锁的实现方式

  1. 基于数据库实现分布式锁
  2. 基于Zookeeper实现分布式锁
  3. 基于reids实现分布式锁

MySQL:行锁+乐观锁。获取锁:select update  ;执行业务;释放锁:本地事物提交。

Zookeeper:公平锁。获取锁:创建节点(临时顺序);执行业务 ;释放锁:关闭连接,临时顺序节点自动删除。

Redis:加锁 setnx  orderlock A expire 设置过期时间;释放锁:del orderlock。

二、简单理解Redis架构演变全过程

我们从一个业务应用发展过程中去理解redis为了适用业务应用各个阶段而调整的(性能角度)架构。如下图:

三、关于磐基paas平台1.0企业套件redis集群巡检总结

  1. 测试redis实例是否是可用的或测试redis实例连接的延时情况

命令:

PODS=$(sudo kubectl get pod \

    -n "paas-middleware" \

    -l "cluster=***-***-***-cluster-1-redis-1,app=redis" \

    -o jsonpath="{.items[*].metadata.name}"); \

for POD in ${PODS:-}; do \

sudo kubectl exec \

    -n paas-middleware ${POD:-} \

    -c redis -- \

        redis-cli \

        -p "6379" \

        -a '******' \

        PING | \

        awk -v POD=${POD:-} "{ print POD, \" \\t\", \$0 }"; \

done

预计正常输出结果:

2、查看redis集群主从情况

PODS=$(sudo kubectl get pod \

    -n "paas-middleware" \

    -l "cluster=***-***-***-cluster-1-redis-1,app=redis" \

    -o jsonpath="{.items[*].metadata.name}"); \

for POD in ${PODS:-}; do \

sudo kubectl exec \

    -n paas-middleware ${POD:-} \

    -c redis -- \

        redis-cli \

        -p "6379" \

        -a '******' \

        -c \

        cluster nodes; \

break; \

done

预计正常输出结果:

说明:磐基PaaS平台1.0 redis集群一般都是三主三从

3、查看redis集群主从复制(info replication)具体情况

查看redis集群info replication命令:

PODS=$(sudo kubectl get pod \

    -n "paas-middleware" \

    -l "cluster=***-***-***-cluster-1-redis-1,app=redis" \

    -o jsonpath="{.items[*].metadata.name}"); \

for POD in ${PODS:-}; do \

echo ;\

sudo kubectl exec \

    -n paas-middleware ${POD:-} \

    -c redis -- \

        redis-cli \

        -p "6379" \

        -a '******' \

        -c \

        info replication | \

        awk -v POD=${POD:-} "{ print POD, \"  \\t\", \$0 }"; \

done

我们根据输出的结果分为主节点和从节点两部分进行说明:

主节点:(磐基PaaS平台1.0redis集群一般都是三主三从)

info replication 查看master节点各个参数说明:

*.*.*.*:6379> info replication

# Replication

# 角色

role:master

# 从节点的连接数

connected_slaves:1

# 从节点详细信息 IP PORT 状态 命令(单位:字节长度)偏移量 延迟秒数

# 主节点每次处理完写操作,会把命令的字节长度累加到master_repl_offset中。

# 从节点在接收到主节点发送的命令后,会累加记录子什么偏移量信息slave_repl_offset,同时,也会每秒钟上报自身的复制偏移量到主节点,以供主节点记录存储。

# 在实际应用中,可以通过对比主从复制偏移量信息来监控主从复制健康状况。

slave0:ip=197.166.***.***,port=6379,state=online,offset=23866,lag=0

slave1:ip=197.166.***.***,port=6379,state=online,offset=23866,lag=0

# master启动时生成的40位16进制的随机字符串,用来标识master节点

master_replid:acc2aaa1f0bb0fd79d7d3302f16bddcbe4add423

master_replid2:0000000000000000000000000000000000000000

# master 命令(单位:字节长度)已写入的偏移量

master_repl_offset:23866

second_repl_offset:-1

# 0/1:关闭/开启复制积压缓冲区标志(2.8+),主要用于增量复制及丢失命令补救

repl_backlog_active:1

# 缓冲区最大长度,默认 1M

repl_backlog_size:1048576

# 缓冲区起始偏移量

repl_backlog_first_byte_offset:1

# 缓冲区已存储的数据长度

repl_backlog_histlen:23866

从节点:

info replication 查看slave节点各个参数说明:

***.***.***.***:6379> info replication

# Replication

# 角色

role:slave

# 主节点详细信息

master_host:169.169.***.***

master_port:6379

# slave端可查看它与master之间同步状态,当复制断开后表示down

master_link_status:up

# 主库多少秒未发送数据到从库

master_last_io_seconds_ago:1

# 从服务器是否在与主服务器进行同步 0否/1是

master_sync_in_progress:0

# slave复制命令(单位:字节长度)偏移量

slave_repl_offset:24076

# 选举时,成为主节点的优先级,数字越大优先级越高,0 永远不会成为主节点

slave_priority:100

# 从库是否设置只读,0读写/1只读

slave_read_only:1

# 连接的slave实例个数

connected_slaves:0

# master启动时生成的40位16进制的随机字符串,用来标识master节点

master_replid:acc2aaa1f0bb0fd79d7d3302f16bddcbe4add423

# slave切换master之后,会生成了自己的master标识,之前的master节点的标识存到了master_replid2的位置

master_replid2:0000000000000000000000000000000000000000

# master 命令(单位:字节长度)已写入的偏移量

master_repl_offset:24076

# 主从切换时记录主节点的命令偏移量+1,为了避免全量复制

second_repl_offset:-1

# 0/1:关闭/开启复制积压缓冲区标志(2.8+),主要用于增量复制及丢失命令补救

repl_backlog_active:1

# 缓冲区最大长度,默认 1M

repl_backlog_size:1048576

# 缓冲区起始偏移量

repl_backlog_first_byte_offset:1

# 缓冲区已存储的数据长度

repl_backlog_histlen:24076

4、通过info memory命令查看内存使用情况:

通过学习Redis的内存知识可以使我们在保护Redis数据库的同时更高效的发挥出Redis的作用,进而管理内存,减少内存消耗和硬件成本。

Redis作为内存数据库,对于自身所使用的内存情况是有命令可以统计的,通过获取到的相关信息可以了解Redis自身内存的使用现状,进而有助于判断内存使用健康度。Redis提供查看内存的指令为info

Info memory命令参数说明:

点关注参数:

used_memory_rss和used_memory以及它们的比值mem_fragmentation_ratio

重点说明:

  1. used_memory和used_memory_rss: 前者是从Redis角度得到的量,后者是从操作系统角度得到的量。二者之所以有所不同,一方面是因为内存碎片和Redis进程运行需要占用内存,使得前者可能比后者小,另一方面虚拟内存的存在,使得前者可能比后者大。
  2. mem_fragmentation_ratio :由于在实际应用中,Redis的数据量会比较大,此时进程运行占用的内存与Redis数据量和内存碎片相比,都会小得多;因此used_memory_rss和used_memory的比例,便成了衡量Redis内存碎片率的参数;这个参数就是mem_fragmentation_ratio

mem_fragmentation_ratio =表示(used_memory_rss/used_memory)的比值

      A、当mem_fragmentation_ratio>1时,说明used_memory_rss-used_memory多出的部分内存并没有用于数据存储,而是被内存碎片所消耗,这个值越大,表明内存碎片越多。

      B、当mem_fragmentation_ratio<1时,这种情况说明正在使用虚拟内存,也就是在使用主机的硬盘,由于硬盘性能是远远低于内存的,所以要小心因为性能问题导致整体Redis故障。

      C、根据日常使用的情况mem_fragmentation_ratio的数值在1~1.5之间是比较健康的。在出现内存碎片过多的问题怎么处理呢?最简单暴力的办法就是重启,在Redis4.0版本之后支持在运行期进行自动内存碎片清理,主要通过设置config set activedefrag yes来进行实现,同时也提供了memory purge命令来手动进行内存碎片清理。

       Redis默认是无限使用内存的,所以防止系统内存被耗尽,需要对Redis的内存上限进行设置,Redis使用maxmemory参数限制最大可用内存。maxmemory配置的是Redis最大限度的实际使用的内存量,也就是used_memory统计项对应的内存。由于内存碎片率的存在,实际消耗的内存可能会比maxmemory设置的更大,实际使用时要小心这部分内存溢出。根据惯例一般会预留出20%的服务器空闲内存防止内存溢出通过。

       Redis的内存上限可以通过config set maxmemory进行动态修改,即修改最大可用内存。通过动态修改maxmemory,可以实现在当前服务器下动态伸缩Redis内存的目的,考虑到现在在部署Redis时大多采用集群或哨兵模式,单台主机上并非Redis单实例,因此建议针对所有的Redis进程都要配置maxmemory。

       Redis针对内存使用情况提供内存回收策略供运维人员进行配置,主要用于删除到达过期时间的键对象以及当Redis内存使用达到所设置的maxmemory上限时则执行内存回收策略。

5、查看和分析Redis性能瓶颈之慢查询

       由于Redis的单线程架构,所以需要每个命令能被快速执行完,否则会存在阻塞Redis的可能,理解Redis单线程命令处理机制是开发和运维Redis的核心之一。

       许多数据库会提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当然在数据库中最常见的就是select这些sql语句了,当超过预设阀值,就将这条命令的相关信息(例如:发生时间,耗时,命令的详细信息)记录下来,Redis也提供了类似的功能。

       那么如何使用redis所提供的慢查询功能呢?redis主要提供了

       slowlog-log-slower-than和slowlog-max-len两个配置参数来提供这项功能。两项参数分别用来设置慢查询的阈值以及存放慢查询的记录。 首先对redis的这两个配置进行一个说明 :

slowlog-log-slower-than:从字面意思就可以看出,可以通过slowlog-log-slower-than参数设置什么情况下是慢语句,只有redis命令执行时间大于slowlog-log-slower-than的才会定义成慢查询,才会被slowlog进行记录。它的单位是微秒(1秒=1000毫秒=1000000微秒),在初始情况下默认值是10000,也就是10ms,假如执行了一条比较慢的命令,如果它的执行时间超过了 10ms ,那么它将被记录在慢查询日志中。(如果slowlog-log-slower-than=0会记录所有的命令,slowlog-log-slower than<0对于任何命令都不会进行记录)

slowlog-max-len从字面意思看,slowlog-max-len说明了慢查询日志最多可以存储多少条记录,实际上Redis使用了一个列表来存储慢查询日志,slowlog-max-len就是列表的最大长度,它自身是一个先进先出队列,当slowlog超过设定的最大值后,会将最早的slowlog删除。简而言之当一个新的命令满足慢查询条件时会被插入到这个列表中,当慢查询日志列表已处于其最大长度时,最早插入的一个命令将从列表中移出,例如slowlog-max-len设置为50 ,当有第51条慢查询插入的话,那么队头的第一条数据就出列,第51条慢查询就会入列。

接下来详细介绍一下如何配置这两个参数,有两种方式进行配置,以下截图全部使用了redis-5.0.5版本:

方式一:通过配置redis.conf文件或者说configmap文件进行配置。

如果是宿主机部署redis集群通过配置redis.conf文件来配置,慢查询日志最多可以存储多少条记录。如果是k8s容器化部署redis集群一般通过配置configmap资源对象来配置慢查询日志最多存储的条数。配置好之后,重启redis服务,配置即可生效。

方式二:通过CONFIG命令进行动态配置

例如:

# 配置查询时间超过1毫秒的命令进行记录

# 保存500条慢查记录

然后通过config get命令验证配置是否已生效

       要注意通过config命令配置的为动态生效,一旦服务重启则会重新恢复为默认设置,所以建议在排查问题时通过config这种方式进行配置,但是服务稳定后通过修改配置文件方式进行最终确认(可以通过config rewrite命令持久化到本地文件,但要主要启动redis时要指定redis . conf文件该命令才可以生效)。

       相关的参数已经设置完成了,那么如何查看记录的信息呢?要想查看所记录的日志,主要使用SLOWLOG GET或者SLOWLOG GET number命令,前者将会输出所有的slow log,最大长度取决于 slowlog-max-len 选项的值,而SLOWLOG GET number 则只打印指定数量的日志。

查看当前日志数量: 使用SHOW LEN命令查看日志数量。如果日志条数过多,还可以使用slowlog reset命令进行日志清空

慢查询功能可以有效地帮助我们找到Redis可能存在的瓶颈,但在实际使用过程中要注意以下几点:

slowlog-max-len配置建议:线上建议调大慢查询列表,记录慢查询时 Redis会对长命令做截断操作,并不会占用大量内存。增大慢查询列表可以减缓慢查询被剔除的可能,例如线上可设置为 2000 以上(5.0.5版本默认为128)。

slowlog-log-slower-than配置建议:默认值超过10毫秒判定为慢查询,需要根据Redis并发量调整该值。由于Redis采用单线程响应命令,对于高流量的场景,如果命令执行时间在1毫秒以上,那么Redis最多可支撑OPS不到1000。因此对于高OPS场景的Redis建议设置为1毫秒(OPS指每秒操作次数)。

慢查询只记录命令执行时间,并不包括命令排队和网络传输时间。因此客户端执行命令的时间会大于命令实际执行时间。因为命令执行排队机制,慢查询会导致其他命令级联阻塞,因此当客户端出现请求超时,需要检查该时间点是否有对应的慢查询,从而分析出是否为慢查询导致的命令级联阻塞。

由于慢查询日志是一个先进先出的队列,也就是说如果慢查询比较多的情况下,可能会丢失部分慢查询命令,为了防止这种情况发生,可以定期执行slow get命令将慢查询日志持久化到其他存储中,然后可以进行相关的监控、告警、分析工作。

6、Redis监控命令info

Redis本身提供的 INFO 命令会返回丰富的实例运行监控信息,这个命令是 Redis 监控工具的基础。

INFO命令在使用时,可以带一个参数 section,这个参数的取值有好几种,相应的,INFO命令也会返回不同类型的监控信息。我把INFO命令的返回信息分成5大类,其中,有的类别当中又包含了不同的监控内容,如下表所示:

重点关注一下info stat、info commandstat、info cpu和info memory这四个命令返回的结果,包含了命令的执行情况。(比如命令的执行次数和执行时间、命令使用的CPU资源),内存资源的使用情况(比如内存已使用量、内存碎片率),CPU资源使用情况等,这可以帮助我们判断实例的运行状态和资源消耗情况。

另外,当你启用RDB或AOF持久化功能时,需要重点关注下persistence参数的返回结果,你可以通过它查看到RDB或者AOF的执行情况。

如果你在使用主从集群,就要重点关注下 replication 参数的返回结果,这里面包含了主从同步的实时状态。

四、关于redis集群常见故障排查

故障案例1:节点异常导致redis cluster服务异常

恢复条件:redis pod所在节点恢复正常

处理方式:

  1. 检查节点状态 : kubectl get nodes
  2. 检查服务状态:systemctl status kubelet/systemctl status docker
  3. 检查磁盘空间占用:df -h

故障案例2:redis cluser 集群不可用 slots问题

恢复条件:分配所有slots

处理方式:

1.使用cluster info 命令排查集群状态

2.使用 cluster nodes 排查集群节点状态。

通过检查发现,集群中每个节点得reids服务都是正常得,主从状态也是正常,但是集群中slots个数不够。

3.通过上述内容做出判断,由于缺少slot 0 这个槽位导致集群不可用。

4.通过手动分配slot 0 重新加入集群 cluster addslots 0  集群恢复正常

故障案例3:reids cluster 集群不可用 ip问题

故障现象:redis日志中报conneting to master ip address:6379

恢复条件:配置正确的cluster-announce-ip

处理方式

redis日志中会出现反复连接一个master得ip地址

快速排查及应急措施,查看redis.conf配置文件确定节点配置文件中得ip信息cluster-announce-ip,然后和cluster slots得输出信息做对比,

再查看各个节点得nodes.conf文件判断节点得ip信息

可以看到redis所有节点的集群配置文件nodes.conf中是192.168.3.1:6379,与node-1节点的redis.conf文件中不一致。

批量修改所有redis节点nodes.conf文件中该节点IP配置,重启redis集群

故障案例4:redis延迟问题

故障现象:

Redis内存数据库能很高,时间使用过程中会出现访问延迟很大的情况。通过查看慢日志记录,我们就可以知道在什么时间执行哪些命令比较耗时。

排查措施:

1、查看redis慢日志。查看有哪些命令在执行时延迟比较大。用redis客户端进入redis,用命令查询SLOWLOG get 5

2、如果不是复杂度较高的命令导致的,例如都是SET、DELETE操作出现在慢日志记录中,就要怀疑是否存在Redis写入了大key的情况。可以用这个命令扫描key,redis-cli -h $host -p $port --bigkeys -i 0.01

我们需要控制扫描的频率,使用-i参数控制即可,它表示扫描过程中每次扫描的时间间隔,单位是秒。

3、fork耗时严重,需要查看fork进程

优化措施:

       不使用复杂度较高的命令,并且一次不要获取太多的数据,每次尽量操作少量的数据,让Redis可以及时处理返回

参考资料:

你真的了解Redis的持久化机制吗?

Redis集群模式学习笔记

彻底理解 Redis 的持久化机制:RDB和AOF

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词