全部產品
Search
文件中心

CloudMonitor:自訂事件監控最佳實務

更新時間:Jan 27, 2024

CloudMonitor自訂事件功能可以協助您實現系統在運行過程中出現異常時,自動記錄異常情況並在滿足特定條件時發送警示通知。

背景資訊

服務在運行過程中,難免出現異常情況,有些異常通過重試等方法可以自動回復,有些則不能,嚴重異常甚至會中斷客戶業務。因此需要一個系統來記錄這些異常,且在滿足特定的條件時觸發警示。傳統方法是列印記錄檔,並收集日誌到特定系統,例如開源的ELK(Elasticsearch、Logstash和Kibana)。 這些開源系統由多個複雜的分布式系統組成,自我維護面臨著技術門檻高、成本高的問題。 CloudMonitor提供的事件監控功能,能夠很好的解決這些問題。

準備工作

自訂事件監控提供了Java SDK和OpenAPI兩種上報資料的方式,本文為您介紹通過Java SDK上報異常資料的處理方法。

  1. 添加Maven依賴。
    <dependency>
        <groupId>com.aliyun.openservices</groupId>
        <artifactId>aliyun-cms</artifactId>
        <version>0.1.2</version>
    </dependency>
  2. 初始化SDK。
    //118代表CloudMonitor的應用分組ID,可以從應用的角度來對事件進行歸類, 可以在CloudMonitor的應用分組列表中查看分組ID。
    CMSClientInit.groupId = 118L;
    //地址是事件系統上報的入口,目前是公網地址。accesskey和secretkey用於身份識別。
    CMSClient c = new CMSClient("https://metrichub-cms-cn-hangzhou.aliyuncs.com", accesskey, secretkey);
  3. 是否非同步上報資料。

    CloudMonitor事件預設提供了同步的上報策略。 雖然編寫代碼簡單,但是可以保證每次上報事件的可靠性,不遺失資料。

    同步策略存在的問題:因為要在業務代碼中嵌入事件上報代碼,如果網路出現波動,可能會阻塞代碼執行,影響正常的業務。由於部分情境無需事件100%不丟失,因此需要非同步上報封裝,先將事件寫入LinkedBlockingQueue,再通過ScheduledExecutorService非同步批量上報。

    //初始化queue與Executors:
    private LinkedBlockingQueue<EventEntry> eventQueue = new LinkedBlockingQueue<EventEntry>(10000);
    private ScheduledExecutorService schedule = Executors.newSingleThreadScheduledExecutor();
    //上報事件:
    //每一個事件都包含事件的名稱與事件的內容,名稱用於識別事件,內容是事件的詳細資料,支援全文檢索搜尋。
    public void put(String name, String content) {
        EventEntry event = new EventEntry(name, content);
        //事件隊列滿後直接丟棄,可以根據自己的情況調整該策略。
        boolean b = eventQueue.offer(event);
        if (!b) {
            logger.warn("事件隊列已滿,丟棄事件:{}", event);
        }
    }
    //非同步提交事件,初始化定時任務,每秒執行Run方法批量上報事件。您可以根據自己的情況調整上報間隔。
    schedule.scheduleAtFixedRate(this, 1, 1, TimeUnit.SECONDS);
    public void run() {
        do {
            batchPut();
        } while (this.eventQueue.size() > 500);
    }
    private void batchPut() {
        //從隊列中取出99條事件,用於批量上報。
        List<CustomEvent> events = new ArrayList<CustomEvent>();
        for (int i = 0; i < 99; i++) {
            EventEntry e = this.eventQueue.poll();
            if (e == null) {
                break;
            }
            events.add(CustomEvent.builder().setContent(e.getContent()).setName(e.getName()).build());
        }
        if (events.isEmpty()) {
            return;
        }
        //批量上報事件到CloudMonitor且未重試。如果您對事件可靠度要求高,則需要自己加重試策略。
        try {
            CustomEventUploadRequestBuilder builder = CustomEventUploadRequest.builder();
            builder.setEventList(events);
            CustomEventUploadResponse response = cmsClient.putCustomEvent(builder.build());
            if (!"200".equals(response.getErrorCode())) {
                logger.warn("上報事件錯誤:msg: {}, rid: {}", response.getErrorMsg(), response.getRequestId());
            }
        } catch (Exception e1) {
            logger.error("上報事件異常", e1);
        }
    }

上報例外狀況事件模板

  • 模板1:HTTP Controller的異常監控

    主要監控HTTP請求是否有大量異常,如果每分鐘異常次數超過指定數量,則警示。

    實現原理:通過Spring攔截器或Servlet filter技術對HTTP請求攔截,如果出現異常就記錄日誌,通過配置警示規則來實現警示。

    上報事件的模板如下。

    //每個事件都有豐富的資訊來協助我們搜尋和定位問題,這裡使用Map來組織事件,最後將其轉換成JSON格式作為事件的Content。 
    Map<String, String> eventContent = new HashMap<String, String>();
    eventContent.put("method", "GET");  // HTTP要求方法。
    eventContent.put("path", "/users"); // HTTP的Path。
    eventContent.put("exception", e.getClass().getName()); //異常類名,方便搜尋。
    eventContent.put("error", e.getMessage()); //異常報錯資訊。
    eventContent.put("stack_trace", ExceptionUtils.getStackTrace(e)); // 異常堆棧,方便定位問題。
    //最後使用已封裝的非同步上報方法提交事件,當前是非同步上報,且未重試,可能會小機率丟事件,但已滿足HTTP未知異常警示情境。
    put("http_error", JsonUtils.toJson(eventContent));
    ![image.png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/864cf095977cf61bd340dd1461a0247c.png)
  • 模板2:記錄重要事件

    自訂事件監控用來記錄重要的業務發生情況,但是不需要警示,方便日後查看。例如:重要業務的動作記錄、修改密碼、修改訂單、異地登入等。

    查看重要事件