云监控发布事件监控功能,助力开发者快速提升业务稳定性-阿里云开发者社区

开发者社区> 阿里云SAP上云> 正文
登录阅读全文

云监控发布事件监控功能,助力开发者快速提升业务稳定性

简介: 服务在运行过程中,难免出现异常情况,严重异常甚至会中断您的业务。传统方法是通过开源的ELK(ElasticSearch, Logstash, Kibana)等收集和查询异常,并对接消息网关发送报警。但这些开源系统往往是由多个复杂的分布式系统组成,自行搭建和维护面临着技术门槛高、时间和人力成本高的问题。

应用场景

服务在运行过程中,难免出现异常情况,有些异常通过重试等手段可以自动恢复,有些则不能,严重异常甚至会中断客户业务。所以我们需要一个系统来记录这些异常,并且在满足特定的条件时触发报警。传统方法是打印文件日志,通过收集日志到特定的系统,例如开源的ELK(ElasticSearch, Logstash, Kibana)中。 这些开源的系统往往是由多个复杂的分布式系统组成,自行维护面临着技术门槛高、时间和人力成本高的问题。

云监控提供了一个开箱即用的事件监控功能,能很好解决这些问题。 下面通过几个例子简单说明下如何使用事件监控功能。

实战案例

第一步:上报异常

事件监控提供了JAVA SDK和Open API两种上报数据的方式,这里介绍通过JAVA SDK 上报数据。

Step1 添加 Maven 依赖

<dependency>
    <groupId>com.aliyun.openservices</groupId>
    <artifactId>aliyun-cms</artifactId>
    <version>0.1.2</version>
</dependency>

Step2 初始化SDK

// 这里的118代表云监控的应用分组ID,可以以应用的角度来对事件归类, 可以到云监控应用分组列表中查看分组的ID。
CMSClientInit.groupId = 118L;

// 这里的地址是事件系统上报的入口,目前是公网地址。accesskey和secretkey用于身份识别。
CMSClient c = new CMSClient("https://metrichub-cms-cn-hangzhou.aliyuncs.com", accesskey, secretkey);

Step3 考虑是否异步上报数据

云监控事件默认提供了同步的上报策略。 好处是编写代码简单、 保证每次上报事件的可靠,不丢失数据。

但是同步策略也带来一些问题。因为要在业务代码中嵌入事件上报代码,如果网络出现波动,可能会出现阻塞代码执行,影响正常的业务。
有很多业务场景并不需要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;
    }


    // 批量上报事件到云监控, 这里并未重试, SDK也没有重试, 如果对事件可靠度要求高需要自己加重试策略。
    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);
    }
}

Step4 事件上报Demo

Demo1:http controller的异常监控

主要目的是监控http请求是否有大量异常,如果每分钟异常次数超过一定数量就报警。

实现原理是通过spring的拦截器或者servlet filter等技术对HTTP请求拦截,如果出现异常就记录日志,最后通过配置报警规则来达到报警的目的。

上报事件的demo如下:

// 每个事件应该有丰富的信息来帮助我们搜索和定位问题,这里使用的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

Demo2:后台定时任务执行情况的监控与消息消费情况的监控

同上面的http事件,有很多类似的业务场景需要报警,例如后台任务与消息队列消费等,都可以通过类似的方式上报事件达到监控的目的。当异常发生时,第一时间收到报警。


//消息队列的事件组织:

Map<String, String> eventContent = new HashMap<String, String>();
eventContent.put("cid", consumerId);  // 代表消费者的身份
eventContent.put("mid", msg.getMsgId()); // 消息的id
eventContent.put("topic", msg.getTopic()); // 消息的主题,
eventContent.put("body", body); // 消息的主体
eventContent.put("reconsume_times", String.valueOf(msg.getReconsumeTimes())); // 消息失败重试的次数
eventContent.put("exception", e.getClass().getName()); // 发生异常时的异常类名
eventContent.put("error", e.getMessage()); // 异常信息
eventContent.put("stack_trace", ExceptionUtils.getStackTrace(e)); // 异常堆栈

// 最后上报事件
put("metaq_error", JsonUtils.toJson(eventContent)); 

上报后查看事件
message

对队列消息消费异常设置报警:
alert

Demo 3:记录重要事件

事件还有一种使用场景是用来记录一些重要的业务发生,但是不需要报警,方便日后翻看。 例如重要业务的操作日志,改密码,修改订单,异地登录等。

查询事件

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享: