美文网首页程序员专栏互联网科技
企业级别Redis监控,细化到每个项目实例

企业级别Redis监控,细化到每个项目实例

作者: 享学课堂 | 来源:发表于2020-12-02 14:32 被阅读0次

    享学课堂特邀作者:老顾
    转载请声明出处,谢谢!!!

    前言

    文章中还提到了几点问题:

    • 如何区分业务
    • 如何发现异常
    • 如何截断异常
    • 如何优雅扩容

    今天老顾这篇文章就重点介绍如何发现异常,为什么从这个点去讲,因为这个点是前期的基础,只有具备发现一些问题,才能够有后续行为。

    redis监控

    在我们现在公司redis监控中,是对整个redis集群进行监控,如:内存使用情况,客户端连接数,有多少keys等从整体集群纬度上面去监控redis的使用情况。当然这些监控也是非常重要的。

    现在常规的方案就是利用Prometheus采集数据,并用Grafana进行展示,如下图

    null

    可以这些只是个从整体纬度上面的监控,因为我们企业很多项目都在用一个公共的redis集群,那如何监控在每个项目,以及每个项目实例的对公共redis集群的请求情况呢?

    公共Redis集群监控需求

    我们先看下面的图:

    null

    现在公司很多都是微服务架构了,会涉及到会有很多服务实例了。上图中就是多个项目,多个服务实例在请求公用redis集群。

    这种情况下,我们需要一个底线,就是一定要保证我们的公共redis集群是稳定的,一旦不稳定会导致我们所有的项目服务不稳定

    但是这种架构会出现研发风险,因为在真实的开发过程中,我们是没法保证我们所有的开发人员不会出错,万一有个开发人员,在写一些业务时,用到了redis组件,写了个死循环导致了我们redis请求猛增,导致redis不稳定。或者对redis进行滥用,什么业务都放到redis中,导致内存崩溃。在这种情况下,我们都没法知道是哪个项目,哪个实例导致的。我们的运维会处在排查问题的混乱之中。那我们能不能提前设防呢?

    我们整理一下需求:

    1)我们是否可以提前分配某个项目占用redis内存的大小,指定每个实例的单位时间最大请求数,最大容忍的异常数。

    2)实时监控项目占用的redis内存情况

    3)实时监控项目中每个实例的请求情况

    4)一旦项目占用redis内存大于分配的,就报警;甚至可以自动让这个项目进入黑名单

    5)一旦项目中的实例的请求数,异常数,大于分配的,就报警;甚至可以自动让这个项目进入黑名单

    解决方案

    既然需求过来,那我们作为开发人员,就要项目如何设计我们的方案。因为需求还是比较多的,我们来梳理一下这些需求业务流程:

    null

    项目分配规则其实是比较简单的,只要设计一下mysql,以及开发一个web服务,在界面进行操作;就是一些基本的CRUD。这边老顾就不讲了。

    监控是这篇文章的重点,后面涉及到的监控后的策略,老顾放到后续文章里面介绍。

    监控项目内存使用情况

    如果要监控整个redis的内存使用情况,是比较简单的,上面就介绍了Prometheus+Grafana的方案,当然还可以配合alert报警策略做一些后续流程

    基本原理就是利用redis自身的info命令,以及info stats等命令输出了一些redis服务性能指标

    那我们如何细化到监控每个项目的内存占用情况呢?

    小伙伴们是否还记得redis有个持久化的概念,会把一些缓存数据持久化到dump.rdb中,这个文件就存储了每个key和value的值,以及slot的占用情况。不过这个文件是二进制的,小伙伴们不能直接打开。

    我们的方案就是来解析dump.rdb文件,分析项目内存的使用情况,因为我们会规定每个项目都会有唯一的项目名称,会对key有个固定的格式【项目名称:key名称】

    projectName1:userprojectName2:order
    

    即每个key前面都会带上项目名称。这样有利于我们在解析dump.rdb后,通过项目名称前缀进行统计项目使用的内存大小。

    原理小伙伴们应该知道了吧,但是怎么去解析dump.rdb文件呢,难度太大了吧;还好有开源社区的贡献,我们不需要重复造轮子。老顾采用了go语言解析dump.rdb的工具。

    git地址为:

    https://github.com/sripathikrishnan/redis-rdb-tools https://gitee.com/gujiachun/rdr(这个是老顾用的,上面的工具也可以考虑,功能更多)

    那dump.rdb文件怎么获取到呢?redis配置文件中有对应的配置,当然我们解析dump.rdb这个操作要在redis从节点做,相对安全可靠,也可以覆盖所有业务的 Redis 集群。

    整体流程如下:

    null

    这个开源的工具需要一些go语言相关的知识,当然老顾已经打包了一个bin,可以直接用

    执行命令

    ./macos_start dump dump.rdb >> 111.txt
    

    我们可以看到导出来的数据,key表示设置的可以,Bytes就是这个key存储的value的占用的字节数,Type表示这对key-value的类型。

    null

    我们可以设置定时任务去执行dump操作,当然如果小伙伴会go语言的,可以在这个项目中自行添加业务。这样我们就可以获取到所有key占用内存的情况,再通过分析key的项目前缀,这样就可以算出来项目占用内存的情况。

    小伙伴们会问,dump.rdb文件很大,那解析需要要多久啊。老顾尝试了一下,80几万的key,dump文件300M左右,用这个工具分析只要 5秒;还是蛮强大的,Go语言实现

    实例请求监控

    上面我们已经解决了项目内存的占用情况,这边我们在解决一下如何监控每个服务实例的请求情况,需要知道请求数,成功数,异常数,最大耗时,最小耗时,平均耗时指标

    这块是参考了限流降级框架Sentinel的源代码中,实时统计请求指标。

    Sentinel是以Bucket(桶)为单位记录一段时间内的请求总数、异常总数、总耗时的,而一个Bucket可以是记录一秒内的数据,也可以是10毫秒内的数据,我们称这个时间区间为Bucket的统计单位,是由使用者自定义的:

    null

    Bucket存储一段时间内的请求数、异常数等这些数据用的是一个LongAdder数组,LongAdder保证了数据修改的原子性,数组的每个元素分别代表一段时间内的请求总数、异常数、总耗时。

    null

    用枚举类型MetricEvent的ordinal作为下标。LongAdder被我替换为j.u.c包下的atomic类了。

    null

    当需要获取Bucket记录的总的成功请求数、或者异常总数、或者总的请求处理耗时时,可以通过MetricEvent从LongAdder数组中获取对应的LongAdder,调用sum方法。

    null

    当需要往Bucket添加1个请求、或者一个异常,或者处理请求的耗时时,可以通过MetricEvent从LongAdder数组中获取对应的LongAdder,调用add方法。

    null

    有了Bucket之后,假设我们需要让Bucket存储一秒钟的数据,这样我们就能够知道每秒处理成功的请求数(成功QPS)、每秒处理失败的请求数(失败QPS),以及处理每个成功请求的平均耗时(avg RT)。但是我们如何才能确保Bucket存储的就是精确到1秒的数据呢?最low的做法就是启一个定时任务每秒创建一个Bucket,但统计出来的数据误差绝对很大。

    而Sentinel是这样实现的。它定义一个Bucket数组,根据时间戳来定位到数组下标。假设我们需要统计每1秒处理的请求数等数据,且只需要保存最近一分钟的数据。那么Bucket数组的大小就可以设置为60,每个Bucket的windowLengthInMs窗口大小就是1000毫秒(1秒)。

    null

    由于每个Bucket存储的是1秒的数据,那么就可以将当前时间戳去掉毫秒部分,就能得到当前的秒数,假设Bucket数组的大小是无限大的,那么得到的秒数就是当前要获取的Bucket所在的数组下标。

    但我们不能无限的存储Bucket,一秒一个Bucket得要多大的内存才能存一天的数据。所以,当我们只需要保留一分钟的数据时,Bucket数组的大小就是60,将得到的秒数与数组长度取余数,就得到当前Bucket所在的数组下标。这个数组是循环使用的,永远只保存最近1分钟的数据。

    null null

    取余数就是循环利用数组。如果想要获取连续的一分钟的Bucket数据,就不能简单的从头开始遍历数组,而是指定一个开始时间和结束时间, 从开始时间戳开始计算Bucket存放的数组下标,然后循环每次将开始时间戳加上1秒,直到开始时间等于结束时间。

    整体原理如上,还是比较挠的,直接上案例代码,看效果如何。

    请求案例

    null

    上面是业务中加入监控埋点,下面我们直接输出

    null

    小伙伴们看到了FlowHelper这个类,就在老顾的开源项目中;

    git地址:https://gitee.com/gujiachun/rb-qps-helper

    通过这样的方式,我们就可以改造我们的redis请求client方法了,进行监控埋点就行了。

    现在还剩下一个问题,就是我们监控到的数据如何给监控平台?

    如何上报监控数据

    一开始老顾想着用定时任务的方式,提交给监控平台;最后想了想,那监控平台地址是什么呢?太耦合了。然后想到了我们spring boot中就有一些监控指标。

    通过访问http://localhost:1100/actuator/metrics就可以看到监控的指标,再通过http://localhost:1100/actuator/prometheus直接可以看到指标数据。

    null

    我们也是可以参考一下的,我们每个实例只要暴露出来,让prometheus自己来拿,而且又是标准流程。具体实现:

    引入依赖

    null

    实现MeterBinder接口

    null

    在利用Gauge 监控类实现就ok了

    null

    这样就可以把我们redis实例的请求指标,展现在http://localhost:1100/actuator/prometheus中了

    null

    是不是很酷啊?

    总结

    这篇文章的知识点很多,想要完成我们文章开头的需求,需要这些知识一起组合起来,就能够实现监控的目标了;当然我们需要搭建一个DashBoard界面查看监控数据

    我们看每个项目的内存占比请求,以及有没有达到阀值,以及对哪些Key占用比较多的内存,进行排名。也可以监控到每个实例的请求情况,请求数排名,异常数排名等。

    可以极大的帮助我们运维和开发人员更多的了解我们的redis使用情况。文章里面只是介绍了核心思想。老顾已经全部实现了,小伙伴们需要源码,可以联系老顾。

    img

    相关文章

      网友评论

        本文标题:企业级别Redis监控,细化到每个项目实例

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