美文网首页redis
Redis(十二):Redis数据倾斜及监控

Redis(十二):Redis数据倾斜及监控

作者: 雪飘千里 | 来源:发表于2023-02-20 20:23 被阅读0次

    1 数据倾斜

    1.1 定义

    对于集群系统,一般缓存是分布式的,即不同节点负责一定范围的缓存数据。我们把缓存数据分散度不够,导致大量的缓存数据集中到了一台或者几台服务节点上,称为数据倾斜。一般来说数据倾斜是由于负载均衡实施的效果不好引起的。

    1.2 危害

    如果发生了数据倾斜,那么保存了大量数据,或者是保存了热点数据的实例的处理压力就会增大,速度变慢,甚至还可能会引起这个实例的内存资源耗尽,从而崩溃。这是我们在应用切片集群时要避免的。

    1.3 分类

    • 数据量倾斜(bigkey导致倾斜)

      某个实例上正好保存了 bigkey。bigkey 的 value 值很大(String 类型),或者是 bigkey 保存了大量集合元素(集合类型),会导致这个实例的数据量增加,内存资源消耗也相应增加。

    • 数据访问倾斜(读取倾斜-热key问题)

      虽然每个集群实例上的数据量相差不大,但是某个实例上的数据是热点数据,被访问得非常频繁

    Redis(五):常见面试题目详解 中写过关于bigkey和hotkey的生产问题,但是只治标不治本,数据倾斜还是需要监控起来,这样在生成环境遇到问题时,才不至于措手不及。

    2 BigKey

    2.1 定义

    通常以Key的大小和Key中成员的数量来综合判定,例如:

    • Key本身的数据量过大:一个String类型的Key,它的值为5 MB。

    • Key中的成员数过多:一个ZSET类型的Key,它的成员数量为10,000个。

    • Key中成员的数据量过大:一个Hash类型的Key,它的成员数量虽然只有1,000个但这些成员的Value(值)总大小为100 MB。

    2.2 产生原因

    • 在不适用的场景下使用Redis,易造成Key的value过大,如使用String类型的Key存放大体积二进制文件型数据;

    • 业务上线前规划设计不足,没有对Key中的成员进行合理的拆分,造成个别Key中的成员数量过多;

    • 未定期清理无效数据,造成如HASH类型Key中的成员持续不断地增加;

    • 使用LIST类型Key的业务消费侧发生代码故障,造成对应Key的成员只增不减。

    bigkey的产生主要是由于程序的设计不当所造成的,如以下几种常见的业务场景

    • 社交类:粉丝列表,如果某些明星或者大v不精心设计下,必是bigkey。

    • 统计类:例如按天存储某项功能或者网站的用户集合,除非没几个人用,否则必是bigkey。

    • 缓存类:将数据从数据库load出来序列化放到redis里,这个方式经常常用,但有两个地方需要注意:第一,是不是有必要把所有字段都缓存;第二,有没有相关关联的数据。

    由此可见,在程序设计中,我们要对数据量的增长和边界有一个基本性的评估,做好技术选型和技术架构。

    2.3 危害

    • 1.内存空间不均匀

      在集群模式中,由于bigkey的存在,会造成主机节点的内存不均匀,这样会不利于集群对内存的统一管理,存在丢失数据的隐患。

    • 2.超时阻塞

      由于redis单线程的特性,操作bigkey通常比较耗时,也就意味着阻塞redis可能性越大,这样会造成客户端阻塞或者引起故障切换。慢查询通常就会有它们的身影。

    • 3.网络拥塞

      bigkey也就意味着每次获取要产生的网络流量较大。假设一个bigkey为1MB,客户端每秒访问量为1000,那么每秒产生1000MB的流量,对于普通的千兆网卡(按照字节算是128MB/s)的服务器来说简直是灭顶之灾。

    • 4.阻塞删除

      有个bigkey,对它设置了过期时间,当它过期后会被删除,如果使用Redis 4.0之前的版本,过期key是同步删除,就会存在阻塞redis的可能性,而且这个过期删除不会从慢查询发现(因为这个删除不是客户端产生的,是内部循环事件)。4.0之后的版本会采用异步删除。

    2.4 优化方案

    2.4.1 拆分Bigkey

    优化Bigkey的原则就是string减少字符串长度,list、hash、set、zset等减少元素数量。当我们知道哪些key是Bigkey时,可以把单个key拆分成多个key,比如以下拆分方式可以参考。

    • big list:list1、list2、...listN

    • big hash:可以做二次的hash,例如hash%100

    • 按照日期拆分多个:key20220310、key20220311、key202203212

    如果bigkey不可避免,也要思考一下要不要每次把所有元素都取出来(例如有时候仅仅需要hmget,而不是hgetall),删除也是一样,尽量使用优雅的方式来处理。

    2.4.2 选择适合的数据类型。

    例如:实体类型(要合理控制和使用数据结构,但也要注意节省内存和性能之间的平衡)

    反例:

    set user:1:name tom 
    set user:1:age 19
    set user:1:favor football </pre>
    

    正例:

    hmset user:1 name tom age 19 favor football
    

    2.4.3 控制key的生命周期,redis不是垃圾桶

    建议使用expire设置过期时间(条件允许可以打散过期时间,防止集中过期)。

    2.5 监控并预警

    Bigkey首先需要重源头治理,防止Bigkey的产生;其次是需要能够及时的发现,发现后及时处理。分析Bigkey的方法不少,这里介绍两种比较常用的方法,也是Daas平台分析Bigkey使用的两种方式,分别是Bigkeys命令分析法、RDB文件分析法。

    2.5.1 scan命令分析

    Redis4.0及以上版本提供了--Bigkeys命令,可以分析出实例中每种数据结构的top 1的Bigkey,同时给出了每种数据类型的键值个数以及平均大小。执行--Bigkeys命令时候需要注意以下几点:

    • bigkeys 是以 scan 延迟计算的方式扫描所有 key,因此执行过程中不会阻塞 redis,但实例存在大量的 keys 时,命令执行的时间会很长,这种情况建议在 slave 上扫描

    • 建议在节点本机执行,这样可以减少网络开销。

    • 如果没有从节点,可以使用--i参数,例如(--i 0.1 代表100毫秒执行一次)。

    • --Bigkeys只能计算每种数据结构的top1,如果有些数据结构有比较多的Bigkey,是查找不出来的。

    • string 类型统计的是 value 的字节数;另外 4 种复杂结构的类型统计的是元素个数,不能直观的看出 value 占用字节数(元素个数少,不一定 value 不大;元素个数多,也不一定 value 就大),所以 --bigkeys 对分析 string 类型的大 key 是有用的,而复杂结构的类型还需要一些第三方工具。

    redis-cli -h 127.0.0.1 -p 6379 -a "password" --bigkeys
    

    2.5.2 RDB文件分析

    借助开源的工具,比如rdb-tools,分析Redis实例的RDB文件,找出其中的Bigkey,这种方式需要生成RDB文件,需要注意以下几点:

    • 建议在slave节点执行,因为生成RDB文件会影响节点性能。

    • 需要生成RDB文件,会影响节点性能,虽然在slave节点执行,但是也是有可能造成主从中断,进而影响到master节点。

    Rdbtools 是 python写的 一个第三方开源工具,用来解析 Redis 快照文件。除了解析 rdb 文件,还提供了统计单个 key 大小的工具。

    1、安装

    git clone https://github.com/sripathikrishnan/redis-rdb-tools
    cd redis-rdb-tools sudo && python setup.py install
    

    2、使用

    从 dump.rdb 快照文件统计, 将所有 > 10kb 的 key 输出到一个 csv 文件

    rdb dump.rdb -c memory --bytes 10240 -f live_redis.csv
    

    2.5.3 使用 memory 命令查看 key 的大小(仅支持 Redis 4.0 以后的版本)

    redis-cli -h 127.0.0.1 -p 6379 -a password
    
    MEMORY USAGE keyname1
    (integer) 157481
    
    MEMORY USAGE keyname2
    (integer) 312583
    

    3 HotKey

    3.1 定义

    通常以其接收到的Key被请求频率来判定,例如:

    • QPS集中在特定的Key:Redis实例的总QPS(每秒查询率)为10,000,而其中一个Key的每秒访问量达到了7,000。

    • 带宽使用率集中在特定的Key:对一个拥有上千个成员且总大小为1 MB的HASH Key每秒发送大量的HGETALL操作请求。

    • CPU使用时间占比集中在特定的Key:对一个拥有数万个成员的Key(ZSET类型)每秒发送大量的ZRANGE操作请求。

    也就是说虽然每个集群实例上的数据量相差不大,但是某个实例上的数据是热点数据,被访问得非常频繁

    image.png

    3.2 产生原因

    预期外的访问量陡增,如突然出现的爆款商品、访问量暴涨的热点新闻、直播间某主播搞活动带来的大量刷屏点赞、游戏中某区域发生多个工会之间的战斗涉及大量玩家等。

    3.3 危害

    • 占用大量的CPU资源,影响其他请求并导致整体性能降低。

    • 集群架构下,产生访问倾斜,即某个数据分片被大量访问,而其他数据分片处于空闲状态,可能引起该数据分片的连接数被耗尽,新的连接建立请求被拒绝等问题。

    • 在抢购或秒杀场景下,可能因商品对应库存Key的请求量过大,超出Redis处理能力造成超卖。

    • 热Key的请求压力数量超出Redis的承受能力易造成缓存击穿,即大量请求将被直接指向后端的存储层,导致存储访问量激增甚至宕机,从而影响其他业务。

    3.4 优化方案

    3.4.1 备份热key

    可以把热点数据复制多份,在每一个数据副本的 key 中增加一个随机后缀,让它和其它副本数据不会被映射到同一个 Slot 中。

    这里相当于把一份数据复制到其他实例上,这样在访问的时候也增加随机前缀,将对一个实例的访问压力,均摊到其他实例上

    3.4.2 本地缓存

    如果我们可以预测到hotkey发生,比如秒杀这类,那我们就可以在活动上线前提前把缓存数据 写入到本地内存。

    3.4.3 本地缓存+动态计算自动发现热点缓存

    处理突发的hotkey就只能通过 动态计算然后缓存进行热点缓存

    3.5 监控并预警

    3.5.1 基于流式计算技术的缓存热点⾃动发现

    框架如下图,具体介绍见 Redis(五):常见面试题目详解

    img

    3.5.2 京东开源框架JD-hotkey

    JD-hotkey框架如下图,git地址 https://gitee.com/jd-platform-opensource/hotkey

    img

    流程介绍:

    • 客户端通过引用hotkey的client包,在启动的时候上报自己的信息给worker,同时和worker之间建立长连接。定时拉取配置中心上面的规则信息和worker集群信息。

    • 客户端调用hotkey的ishot()的方法来首先匹配规则,然后统计是不是热key。

    • 通过定时任务把热key数据上传到worker节点。

    • worker集群在收取到所有关于这个key的数据以后(因为通过hash来决定key 上传到哪个worker的,所以同一个key只会在同一个worker节点上),在和定义的规则进行匹配后判断是不是热key,如果是则推送给客户端,完成本地缓存。

    1)etcd集群 etcd作为一个高性能的配置中心,可以以极小的资源占用,提供高效的监听订阅服务。主要用于存放规则配置,各worker的ip地址,以及探测出的热key、手工添加的热key等。

    2)client端jar包 就是在服务中添加的引用jar,引入后,就可以以便捷的方式去判断某key是否热key。同时,该jar完成了key上报、监听etcd里的rule变化、worker信息变化、热key变化,对热key进行本地caffeine缓存等。

    3) worker端集群 worker端是一个独立部署的Java程序,启动后会连接etcd,并定期上报自己的ip信息,供client端获取地址并进行长连接。之后,主要就是对各个client发来的待测key进行累加计算,当达到etcd里设定的rule阈值后,将热key推送到各个client。

    4) dashboard控制台 控制台是一个带可视化界面的Java程序,也是连接到etcd,之后在控制台设置各个APP的key规则,譬如2秒20次算热。然后当worker探测出来热key后,会将key发往etcd,dashboard也会监听热key信息,进行入库保存记录。同时,dashboard也可以手工添加、删除热key,供各个client端监听。

    下面几篇文章是作者写的,对于框架理解很有意义。

    京东开源热key探测(JD-hotkey)中间件单机qps 2万提升至35万实录

    京东毫秒级热key探测框架设计与实践,已实战于618大促

    从性能上来说,明显的可以看出开源框架JD-hotkey很优秀,只是第一个方案可以自定义开发,开源框架JD-hotkey就只能使用了。

    补充

    etcd简介

    etcd 这个名字由两部分组成: etc 和 d ,即 UNIX/Linux操作系统的“/etc” 目录和分布式( distributed )首字母的“d ” 。我们都知道,/etc目录一般用于存 储 UNIX/Linux 操作系统的配置信息 因此etc和d合起来就是一个分布式的/etc 目录。etcd 的寓意是为大规模分布式系统存储配置信息。

    etcd 的官方定义是一个 Go 语言编写的分布式、高可用 的用于分布式系统重要数据存储的 一致性键值存储 系统,常用于提供可靠的分布式键值( key-value )存储、配置共享和服务发现等 功能。 etcd 具有容错能力,对于n个节点的集群,可以在n-1/2 个节点宕机(其他节点正常) 的情况下仍继续工作。

    etcd应用场景

    etcd 的定位是通用的一致性 key/value 存储,但也有 服务发现和共享配置 的功能 。 因此,典型的 etcd 应用场景包括但不限于分布式 数据库、服务注册与发现 、 分布式锁 、 分布式消息、队列 、 分布式系统选主等 。 etcd 的定位是通用的一致性 key/value 存储,同时也面向服务注册与发现的应用 场景 。

    etcd vs Zookeeper

    Zoo Keeper 的主要优势是其具有成熟、健壮以及丰 富 的特性,然而,它也 有自己的缺点,具体如下:

    • 复杂 。 ZooKeeper 的部署维护比较复杂;Paxos 强一致性算法也复杂难懂;使用也比较复杂,需要安装客户端,官方 只提供了 Java 和 C 两种语言的接口

    • Java 编写,Java 本身就偏向重型应用依赖较多,对资源的占用也比较高

    • 发展缓慢 ,Apache 基金会庞大的结构和松散的管理导致项目发 展缓慢

    与 ZooKeeper 相比,ETCD更简单,安 装、部署和使用更加容易,并且 etcd 的某些功能是 ZooKeeper 所没有的,比如:

    • etcd 更加稳定可靠,它的唯一目标就是把分布式一致性 KV 存储做到极 致,所以它更注重稳定性和扩展性

    • 服务发现,etcd 使用的是节点租约( Lease ),并且支持Group (多 key );而 ZooKeeper 使用的是临时节点,临时节点存在很多问题

    • etcd 支持稳定的 watch ,而不是 ZooKeeper 一样简单的单次触发式watch,很多调度系统需要得到完整节点历史记录,etcd 可以存储数十万个历史变更

    • etcd 支持 MVCC (多版本并发控制),因为有协同系统需要无锁操作

    • etcd 支持更大的数据规模 , 支持存储百万到千万级别的 key

    • etcd 的性能更好 。 在 一 个由 3 台 8 核节点组成的云 服务器上, etcd d 版本可以做到每秒数万次的写操作和数十万次的读操作

    • 数据持久化。etcd默认数据一更新就进行持久化。

    最后,etcd作为一个年轻的项目,正在高速迭代和开发中,这既是一个优点,也是一个缺点。优点在于它的未来具有无限的可能性,缺点是版本的迭代导致其使用的可靠性无法保证,无法得到大项目长时间使用的检验。然而,目前CoreOS、Kubernetes和Cloudfoundry等知名项目均在生产环境中使用了etcd,所以总的来说,etcd值得你去尝试。

    JD-hotkey 为什么用etcd,而不是zookeeper

    etcd里面具备一个过期删除的功能,你可以设置一个key几秒过期,etcd会自动删除它,删除时还会给所有监听的client回调,这个功能在框架里是在用的,别的配置中心没有这个功能。

    etcd的性能和稳定性、低负载等各项指标非常优异,完全满足我们的需求。而zk在很多暴涨流量前和高负载下,并不是那么稳定,性能也差的远。

    相关文章

      网友评论

        本文标题:Redis(十二):Redis数据倾斜及监控

        本文链接:https://www.haomeiwen.com/subject/iylbkdtx.html