框架保证方向,整体包容细节
为保证服务端运行平稳正常,owner应使得系统应保有相应的监控:系统监控,业务监控。而服务运行的平稳高效是否有保障跟监控粒度又成直接的正比关系。本文仅针对开放平台进行描述,开发语言:JAVA。
开放平台:向上承载供应商/分销商等对外统一或者差异化api接口进行交互,向下对内转换业务参数完成适配并需提供提供统一的、稳定的服务。供应商以及分销商的多样性和内部服务需要的稳定性高效性,都为监控服务提供了充分的可操作空间,以使得owner可以从整体上来把握节奏和方向。
监控则涉及到异常业务和正常业务,凡未虑胜先滤败,是以本文也先从异常的角度切入阐述。
异常区分系统异常和业务异常:系统异常有IO输入输出异常、空指针异常、SQL数据库异常等运行时异常和非运行时异常;业务异常有查询超时、验舱验价失败、重复占位等,同时又区分是否需要向上抛出中断当前业务流程还是选择记录异常信息后自行catch吞掉以保证业务的完整性。如此就需要将异常统一梳理并进行归纳处理。
首先异常的统一处理,在SPRING框架中可以通过继承SimpleMappingExceptionResolver统一定制自己的实现-ExceptionResolver,对异常进行分类处理:为异常包装错误码、日志、存储、返回友好可读的提示等,若再进一步欲要实现异常信息的国际化,也很简单辅助ResourceBundleMessageSource对i18n文件统一包装即可在框架层面完成异常信息国际化的整合,为监控为告警提供了良好的环境。
其次这种末端扎口的模式对于编程提供了很好的引导性:coder依据业务编码,会自觉的依据具体情况的不同定制业务和系统异常枚举类型并进行抛出,业务异常如:入参错误、未登录、没有对应权限、访问频率过快、供应商接口访问超时等;系统异常如:TSP异常、REST异常、PEBBLE异常、SQL数据库异常、IO输入输出异常等。当监控到短时间内有大量相同类型的异常发生时,就会很显而易见的得知是何种异常导致的业务不可以用,实现快速定位和快速定责乃至快速解决。如2019年3月6日案例,供应商XXXX假期反馈其访问订单列表页受阻,提示其OPI:FLOW:OPI.ORDER.QUERY.LIST接口访问达到上限,经查其在10小时内访问订单列表页的次数就高达19万次以上合5.2次/每秒,远高与订单业务的进单频率,触发流控业务异常30秒/次的查询上限,被监控到并予以阻塞。
象棋里有宁弃一子不舍一先的说法,所以打好地基盖高楼,正常业务的各种服务监控也应有序部署到位,不能临渴掘井。
业务流程线下转线上, 笔者倾向于SOA面向服务的设计思想,如开放平台下机票查询的常规流程:依据出发到达团期以及人数等查询符合条件的常规特价政策,再远程RPC获取AV航班仓位信息,进一步匹配FD价格信息形成完整的航班及报价后再与供应商的返回结果进行低价比较后择优露出。采取SOA设计就可以针对常规特价接口、AV接口、FD接口和供应商查询接口分别进行监控,监控方法更是会多样起来:可以是无侵入式的AOP切面编程,也可以是记录日志通过kafka图示。有的放矢真正做到业务上有路技术上有术。
信息统一收集,监控分类处理
场景 | 操作 | 一行代码植入实现 |
异常处理 | 线程异步 收集异常信息 | async(exception)//记录异常类型、code、message |
关键业务 | AOP切面 收集业务信息 | @Around(value= "target(com.ysma.aop…anyService)") Public Object statisticAround(ProceedingJoinPoint pjp) |
定时统计 | 定时任务 统计结果信息 | @Scheduled(cron = "0 0/1 * * * ?") void statistics() |
线程异步收集异常信息:上文讲到异常ExceptionResolver已经可以实现定制化处理。这使得ExceptionResolver在处理异常时可以无感知式的异步收集异常信息也变为可能,可以按异常类型、错误码和错误信息进行日志、缓存乃至db存储。
AOP切面编程收集关键业务信息:业务流程上的失败并不等同于异常,比如航班查询无结果或者占位变价等,所以也需要对关键业务进行监控,收集其成功失败数以及失败原因等。恰巧OO面向对象编程思潮的普及也使得关键业务都有自己独立的URI和处理器,这也使得AOP的切入会变的容易,例如可以通过环绕通知Around切住同一个服务下的多个业务,简单实现如下:
@Around(value = "target(com.ysma.aop.service.DiyService)")
public Object statisticAround(ProceedingJoinPoint pjp) throws Throwable {
// 拦截运价直连
String methodName = pjp.getSignature().getName();
if(methodName.equals("query")){
return processQuery(pjp); //处理查询接口耗时及结果
} else if (methodName.equals("check")) {
return processChecking(pjp); // 处理验舱验价接口耗时及结果
} else if (methodName.equals("book")) {
return processBooking(pjp); // 处理占位接口耗时及结果
} else {
return pjp.proceed();
}
}
扫描统计结果信息:热门航线信息,热门出游信息,top供应商信息,top分销商信息等成一定趋势且需要掌握的信息的收集和展示,可以一定程度上呈现出业务的稳定性。而新功能迭代上线所产生的ECharts曲线变化也通常都预示着bug的产生。简单应用如下图
掌握了异常发生的种类、详情和频率。针对异常的监控也就顺理成章的就衍生出了提示级告警,严重级告警,灾难级告警;邮件告警、钉钉告警、短信告警;分组告警、群组告警、负责人告警;可以帮助owner了解当前系统健康状态,以及是否需要紧急介入。简单应用如钉钉告警:
掌握了关键业务请求的数目,响应和速度。针对业务的监控也将会衍生出API接口服务质量:成功率、平均耗时和失败原因占比等,可以帮助决策是否需要控制流量,缓存时长,接口低服务质量降级等一系列可以保障系统和服务稳定的措施。如下图,可以快速识别到甬上供应商的查占验出全流程关键业务的服务质量以及长期的出票趋势等信息
技术做到量化,业务做到视化
监控如同等待落地的靴子,看不到消息不安,看到了消息也不安。
系统如同一个黑匣子,运行状况和性能效率是未知的,监控则如同在其上开了很多玻璃孔,可以看到其内部的运行状态,这使得人机互动有了更多的契合点。2018年11月份包机通相关所有对供应商接口均接入了API接口统计并在TNF数据链输出查占验出的服务质量全览图,2019年2月9号[大年初五],下游系统反馈验舱验价接口耗时高达19s并持续上升,其时ELK日志已宕机不能使用,改查TNF服务质量一览图快速得知为XX旅行服务不可用,如不是提前做了准备,实在难以想象春节内要如何耗时费力的远程定位并解决。
要增加系统TPS处理峰值,要增加订单并行处理规模,要增加页面渲染速度,也要增加容灾和主备份切换灵活性……但是首要的,要知道阻碍在哪里。
阻碍在哪里,监控就在哪里!