本文只是简单介绍了下监控系统实现的思路,具体还需根据自己需求实现。

前言:

目前存在一个后台服务系统,此时需要配套一个监控系统,对这个后台服务系统进行监控。下面会涉及到两个系统,后台服务系统(这是已经存在的系统),监控系统(此次需要进行开发的系统)。注意:后面统一将后台服务系统称作服务系统

具体需求:

1、监控服务系统的运行状态,服务系统是否存活,采用模拟数据进行访问接口,如果已down则需要发送告警邮件;

2、监控服务系统的所有接口是否正常运行,采用模拟数据进行访问接口,如果有问题需要发送告警邮件,邮件内容是模拟访问接口返回的响应;(注:后台服务系统中自定义了相关响应状态码和对应的响应描述)

3、监控部署了服务系统的服务器的磁盘、CPU、内存的使用情况,会提前设置好使用阀值,如果超过阀值,则要发送告警邮件;

4、数据采集功能:采集每日服务系统的总访问量、日最大并发量,记录入库,后期做图表展示;

5、除了上面几个需求外,监控系统还需要具备一些配置页面,用来配置一些监控系统使用的参数:
①、添加报警邮件配置参数页面,用于配置报警邮件的发送人、收件人等参数;
②、添加服务器使用阀值的配置参数页面,页面中可以设置服务器(部署后台服务系统的服务器)的磁盘、CPU、内存使用阀值,超过 阀值时需要进行报警;
③、添加服务器配置页面,这些服务器就是部署了服务系统的机器,它们的ip地址及端口号参数;


注意:知道了大概的需求后,还要结合服务系统的实际部署方案进行构思具体的开发;
前提:服务系统的部署是以集群(集群:就是将后台服务系统部署在多态服务器中,然后使用Nginx或F5进行请求的转发和负载均衡)的形式进行部署的。

开发构思:

定时任务、报警邮件发送所使用工具:
1、监控系统首先需要实时监控的,所以说会需要定时任务,定时任务使用Quartz来实现。

2、发送告警邮件可以使用Hutool这个工具包中的邮件工具类来实现,非常简单方便。

在服务系统中添加一个filter请求过滤器,这个过滤器主要作用:
3、服务系统改造:
①、统计服务系统日总访问量,将每日的日总访问量数据放到redis中,redis存储的key为:当前服务器ip地址+当前日期;每当来一个 请求,就将redis中存储的数据加一;

②、统计实时的日最大并发访问量也是在该过滤器中,并且将最大并发访问量也是存在redis中,key为:当前服务器ip地址+ “max” + 当前日期;服务系统每来一个请求,就将redis中存储的数据加一,请求处理完成就将redis中存储的数据再减一;

监控系统中的定时任务:

4、监控系统中的定时任务:
①、获取服务器的cpu、内存、磁盘使用情况可以使用shell脚本获取,然后Java操作shell脚本执行并获取到当前服务器的磁盘、CPU、内存的使用率,然后与配置页面中提前配置的使用阀值进行比较,大于阀值的话就需要发送报警邮件。(定时任务,每隔30分钟执行一次)

②、使用定时任务监控后台服务系统是否存活,以及监控所有接口是否正常,根据响应状态码判断出现问题进行报警邮件发送。(定时任务,每隔5分钟执行一次)

③、使用定时任务统计每日最大并发访问量,因为服务系统过滤器中已经统计了服务系统集群中每个节点实时的日最大访问量并存在了redis中,而此时需要一个定时任务将集群的总日最大访问量进行汇总,并存入redis中,此时key为:”max”+当前日期,后面定时任务在每次执行时,都需要先将集群的总日最大并发访问量进行汇总后,与上次 定时任务的统计的日最大并发访问量进行对比,如果比上次统计的大,则将redis中存储的集群总日最大并发访问量更新为当前的;这时操作redis需要至少两步,先读取,然后判断大小,如果大还会去更新,为了保证操作的原子性,需要使用Lua脚本;(定时任务,每隔5秒执行一次,即使这样的话,统计的最大访问量也可能不是准确的,但是也可作为参考)

Lua脚本伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* lua 脚本:
* 1、判断key是否存在,key不存在,则新增key-value,value默认为0;
* 2、如果key存在,则取出value,然后与输入参数进行比较,输入参数大的话就将key的value值更新为输入参数值,否则不进行任何操作
*/
String luaScript = "local flag = redis.call('exists',KEYS[1])\n"
+ "if (flag == 0) then\n"
+ "redis.call('set', KEYS[1], 1)\n"
+ "else \n"
+ "if tonumber(redis.call('get', KEYS[1])) < tonumber(ARGV[1]) then\n"
+ "redis.call('set', KEYS[1], ARGV[1])\n"
+ "end\n"
+ "end";

④、使用定时任务将每台服务器在redis中对应的每日总访问量取出汇总,存入数据库中,以及日最大并发访问量入库。(定时任务,每天的凌晨一分时执行,是统计前一天的总访问量)

开发构思解析:

1、为什么使用redis存放总访问量以及最大访问量呢?因为服务系统是以集群的形式部署的,所以需要统计集群中所有节点的访问量,将其存入redis这种第三方的地方是比较方便的,注意,存在redis中的这些访问量数据需要设置过期时间的,否则redis中数据会导致越来越多,占用内存;

2、由于使用到了shell脚本获取服务器的磁盘、CPU、内存的使用率,那么集群中的每台服务器都需要存放、运行提前写好的shell脚本,那么也是需要在集群中每台服务器中也要部署 监控系统的;监控系统在部署了集群后,为了保证同一时刻只有一台监控系统运行着定时任务,所以在每个定时任务运行前先设置分布式锁,使用redis设置,设置分布式锁失败的话,就说明集群中有监控系统在执行了,防止定时任务重复执行以及重复数据统计。

3、在监控系统中配置页面配置的各种参数,是存入在数据库中,集群中所以监控系统连接同一个数据库,当在系统启动时使用监听器从数据库中加载进来的;那么当如果在运行阶段更新了配置参数怎么办呢,因为监控系统是部署的集群,怎么提醒集群中的监控系统去数据库中重新加载新配置数据呢?还是使用redis,key随便,value为时间戳,当集群中的所有监控系统在初始加载配置参数时,会在各自本地设置一个时间戳,redis中也设置了相同的时间戳,当在配置页面修改配置参数时,需要更新时间戳,那么监控系统在使用配置参数时,会对比一个redis中存储的时间戳和本地的时间戳是否一致,不一致说明配置参数更新了,需要到数据库重新加载读取参数。

开发中遇到的问题:

1、使用Hutool这个工具包中的邮件工具类发送报警邮件出现了一个小问题,邮件配置参数重新去数据库中读取加载了,但是这个工具类使用到的参数还是原来的旧参数,这里是由于工具类中的默认使用的是全局session,所以导致新配置参数不生效;

2、在多台服务器进行部署服务系统时,监控系统也跟随进行部署多台,那么在数据采集的定时任务由于设置了redis分布式锁,所以不会导致定时任务重复进行采集;但是由于多台服务器的系统时间不一致导致了在每台服务器上部署的监控系统的定时任务会重复执行,就会导致数据库中日最大并发访问量、日总访问量的重复数据产生。即使使用了分布式锁也没有用了。所以在定时任务统计数据入库操作前需要加上校验,校验是否已经存在了这条数据即可。


谢谢大家阅读,鉴于本人水平有限,如有问题敬请提出。