某小公司自动化智能监控平台的实践

前言

首先介绍下背景:咱们公司的产品,会直接部署在甲方,由于甲方比较多,且他们包含个性化需求较多,因此,每一个甲方能够理解为咱们产品的一条git分支。 因为甲方的机器环境、网络环境各不相同,时常出现一些运行时的问题,因而,我设计了这套简易的智能监控系统,用来实时监测各个甲方接口状况。css

适用范围

该套方案衍生的适用范围以下:前端

  1. docker下多容器运行项目,且暂不具有接口健康检测,该套方案可实施检测多个运行点状态状况。
  2. 公司同一套代码有多个运行环境,须要监控各个环境状态。
  3. 项目分支化后,部署在各个甲方(含个性化需求)------咱们是这个。

效果图

鼠标移到某个接口,可看某节点产生的时间和当时接口的出参。[这里只显示变更节点]

其中200为出参json的一个状态码,咱们项目广泛采用。如出参没法解析出状态码(好比服务器500错误),则不显示。

单击节点能够再次模拟该次节点,在浏览器中显出出参。java

双击某个节点能够复制该节点出参。mysql

主体分析

由于咱们产品已经完成了先后端分离(前几篇文章有介绍),因此,咱们重点监控接口。git

个人方案是:sql

  1. 每隔必定时间,好比3分钟,主动get(或者post)一下http接口(含用户信息),得到接口出参。
  2. 比对这次出参和前一次该接口出参是否相同,若是不通则标记下。
  3. 前端展现,每一个接口对应每一个项目全部变更的节点,并排列一张节点差别图。
  4. 这里,咱们监控并不关心接口出参的内容,不对节点出参进行校验是否合法,由于咱们面向全部接口。

对某个接口分析

这里由于每一个公司的各个接口,入参、出参加密方式不通,并且身份认证也是不相同,咱们会在独立写一个方法来实现加解密,因此,我只介绍未加密、已解密的参数;关于出参下文以{"code":"200","data":null,"message"::"success"}为例,身份认证我以简单token进行讲解本文。docker

某个获取新闻列表接口:数据库

http://*.com/v1/news?token=2c789e34dc81d79feba6a005ad63902b
复制代码

解密后的出参:json

{"code":"200","data":[{"id":"1","title":"这是一条假新闻","url":"http://"},{"id":"2","title":"这是一条假新闻","url":"http://"}],"message"::"success"}
复制代码

由接口可知

  1. GET 方法
  2. 入参token=2c789e34dc81d79feba6a005ad63902b
  3. 出参为{"code":"200","data":[],"message"::"success"}
  4. 其中*.com对于各个环境可能各不相同,好比容器下为10.0.0.一、10.0.0.2多个地址
  5. 其中token在各个甲方不相同。

添加新闻获取接口时:

相对url:后端

v1/news
复制代码

请求类型:

get
复制代码

body主体:

token={token}
复制代码

corn表达式:

0 0/3 * * * ?(每隔3分钟执行一次)
复制代码

添加A环境时:

host(必填)

http://a.com
复制代码

参数(list)

token 2c789e34dc81d79feba6a005ad63902b
复制代码

添加B环境时:

host(必填)

http://b.com
复制代码

参数(list)

token 4297f44b13955235245b2497399d7a93
复制代码

绑定接口和环境

  1. 一个接口可绑定多个环境
  2. 一个环境可绑定多个接口
  3. 数据库中只记录单向绑定,逻辑上是双向的。

好比在新闻获取接口绑定A、B环境,则每隔3分钟请求一轮接口。

A:

A环境host+相对url=

http://a.com/v1/news
复制代码

请求类型:

get
复制代码

body主体:

token=2c789e34dc81d79feba6a005ad63902b
复制代码

B:

B环境host+相对url=

http://b.com/v1/news
复制代码

请求类型:

get
复制代码

body主体:

token=4297f44b13955235245b2497399d7a93
复制代码

咱们框架自己并不会关心有几个参数,只会遍历接口中带占位符的,把占位符中字段替换为环境里的参数list中变量。 好比一个body为token=2c789e34dc81d79feba6a005ad63902b&type=1&mobile=2

则添加接口时,body填入:

token={token}&type={type}&mobile={mobile} 其中占位符能够随便起名字
复制代码

配置环境时参数(list)以下:

k v
token 2c789e34dc81d79feba6a005ad63902b
type 1
mobile 2

参数和占位符里的对应,和url其余变量不相关。

前端展现

横轴表明时间,每一个变更的节点都是一次出参变动,节点包含,当时的入参,出参,单击左键能够再次模拟请求得出解密后的出参;双击能够复制出参。

对于不一样的状态码,咱们有不一样的颜色,对应本身产品中错误码选择合适颜色便可,错误等级越高,颜色越显眼。

某个节点右键能够查看历史解决方案,以及新增新的解决方案,好比解决了这个错误代码为999,是重启服务解决的,则,输入重启服务,再点添加。 下次其余人就能够看到这个问题怎么解决的,优先参照作。

不一样的展示

包含两种不一样的纬度,能够直接点击进入,查看A环境全部接口的监控状况,或者查看接口1全部环境的监控状况。

或者:

环境编辑界面:

任务编辑界面:

核心技术

既然是周期性监控,天然少不了使用cron表达式,咱们又是java项目,因此采用了quartz框架。

quartz核心代码

public class QuartzSchedule {

    private static SchedulerFactory sf = new StdSchedulerFactory();
    private static Scheduler sched;
    final static String groupName = "task";


    public static void init() throws IOException, SchedulerException {
        //查询全部须要执行的任务和项目列表
        // 使用类加载器,加载mybatis的配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        // 构造sqlSession工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        MprojectTaskDao mprojectTaskDao = sqlSession.getMapper(MprojectTaskDao.class);
        sched = sf.getScheduler();
        //只查询全部在m_project_include表里面的任务
        List<MprojectTask> mprojectTaskList = mprojectTaskDao.findList();
        for (MprojectTask mprojectTask : mprojectTaskList) {
            startJob(mprojectTask);
        }
    }

    public static void stopTask(MprojectTask mprojectTask) {
        TriggerKey triggerKey = TriggerKey.triggerKey(mprojectTask.getId(), groupName);
        try {
            sched.pauseTrigger(triggerKey);// 中止触发器
            sched.unscheduleJob(triggerKey);// 移除触发器
            sched.deleteJob(JobKey.jobKey(mprojectTask.getId(), groupName));// 删除任务
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     中止和暂停都可使用
     */
    public static void startTask(MprojectTask mprojectTask) {
        //不管是否关闭,先关闭任务再开启。
        stopTask(mprojectTask);
        startJob(mprojectTask);
    }


    private static void startJob(MprojectTask mprojectTask) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(TaskQuzrtzJob.class).withIdentity(mprojectTask.getId(), groupName).build();
            // 触发器
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            // 触发器名,触发器组
            triggerBuilder.withIdentity(mprojectTask.getId(), groupName);
            triggerBuilder.startNow();
            // 触发器时间设定
            triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(mprojectTask.getCron()));
            // 建立Trigger对象
            CronTrigger trigger = (CronTrigger) triggerBuilder.build();
            // 调度容器设置JobDetail和Trigger
            sched.scheduleJob(jobDetail, trigger);
            // 启动
            if (!sched.isShutdown()) {
                sched.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
复制代码

job核心代码

public class TaskQuzrtzJob implements Job {

    public TaskQuzrtzJob() throws IOException {
    }

    //JobExecutionContext context传递参数值
    public void execute(JobExecutionContext context) {
        //经过context获得该任务的全部环境
        //遍历全部环境
            //拼凑出请求地址
            //使用封装的框架加密发送请求
            //得出出参解密后的结果
            //与上次进行比对,不相同则标记,入节点表
            //入记录表
    }
}
复制代码

数据量

由于咱们这个监控每一个接口(任务)有多个环境,假设100个接口100个环境,每3分钟监控一次,则天天记录量为

100 * 100 * 20 * 24=4800 000条记录,这个记录比较惊人,因此咱们分了两张表,一张表只记录记录,另一张表记录变动,展现节点的时候只查询变动表,可解决性能上的问题。

前端

前端采用css来画圆和颜色

round {
    border-radius: 50%;
    text-align: center;
    width: 25px;
    height: 25px;
    line-height: 25px;
}

.on {
    border: 1px solid #7CBA23;
}
复制代码

线条使用line画线

line {
    border-bottom: 1px solid gainsboro;
    height: 2px;
    width: 20px;
}
复制代码

总体采用angular js渲染列表

数据库

咱们使用mysql数据库,mybatis框架链接。

异常提醒

咱们会对每一个接口和状态码进行关联,异常时,发送邮件,测试人员核实问题后反馈给开发,开发解决后,录入解决方案,以便下次查询。

总结

这个平台已经试行1个多月了,整体知足咱们的需求,以往,咱们跑测试脚本,每每不能实时监测服务器健康状态,如今,任何一个环境有问题,咱们都实时,而且能够统计出某个环境从什么时间到什么时间接口处于异常。

这套平台,功能很少,但极大的简化了咱们的对环境稳定性的评估,也收集了大量的数据信息便于后期统计分析。 其次,该方案稍做改造,可运用于多种监测场景中。

展望

将来,我会融入一些智能化的分析,好比下文是某次邮件提醒的内容:

(智能监控) 发现《A客户私有环境》中 【获取新闻列表】 接口异常,异常代码为102; 出参为{"data":null,"message":"成功","state":102}

历史解决方案有:

  1. 到管理端重启容器。
  2. xx表中有异常脏数据。 根据历史统计,方案1可能性为80%,方案2为10%。

该环境接口在5分钟前是正常的,出参为{"data":null,"message":"暂无数据","state":200}

发现有另外2个其它环境异常,分别为XXX、YYY环境。但异常状态和该校不类似,排除接口war包bug的缘由。

因为《XXX环境》其余接口在5分钟内某次监控均为异常,因此(智能监控) 已自主调用容器自愈模块,目前已恢复服务,本次收集数据耗时5分钟,分析问题耗时100毫秒,自愈耗时60秒,该环境中断服务时间为6分钟,本月中断服务总时长为15分钟,高可用性为98.33%。

over

相关文章
相关标签/搜索