某小公司自動化智能監控平臺的實踐

前言

首先介紹下背景:咱們公司的產品,會直接部署在甲方,由於甲方比較多,且他們包含個性化需求較多,因此,每一個甲方能夠理解爲咱們產品的一條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

相關文章
相關標籤/搜索