好大夫在线已经收录了超过 69 万医生信息,其中有 24 万医生在平台上实名注册,服务用户累计 6700 万。随着业务快速发展,伴随而来的系统复杂性和多样性也越来越多,我们发现原先的服务架构已经跟不上业务的迭代速度了。All-in-one 发版时间过长,服务耦合在一起,一出问题很容易波及全站。2018 年公司开始推进微服务拆分,由 php 转向 java,前端开始转型 node,迎来了服务快速增长的阶段,目前我们有 350 多个微服务,每隔几周会上线一个新服务。随着服务的逐渐增多,我们发现编织的微服务大网越来越大,面临微服务治理的挑战也越来越多。微服务治理包含范围非常广,主要有服务发现,服务注册,服务编排,服务配置,服务网关,服务监控预警,日志分析等等等等。其中遇到问题最多的是围绕服务的稳定性和可用性,比如如何快速定位问题和评估影响范围。接下来就针对服务的稳定性和可用性聊一下我们的应对措施,主要是日志分析和应用画像平台化。
主要从应用,中间件的稳定性和可用性两个方面分析。解决方案:构建平台,包括日志全息分析、实时告警,应用画像、配置管理。随着业务日趋复杂,All-in-one 笨重的系统很难适应敏捷开发的节奏,应用按不同的维度进行微服务架构拆分成为趋势。然而庞杂的业务系统由不同语言开发,不同团队维护,微服务治理也迅速带来新的挑战。
曾几何时,几个人关在“小黑屋”排查问题的场景历历在目。记得 2019 年初夏,一个周五,马上就要欢度周末了,临近下班的时候,有用户反馈支付失败,紧接着越来越多的用户开始投诉,医患交流失败,很多方向的业务开发围到系统组,我们如临大敌,大家一起找个会议室排查问题。一开始我们觉得是网络抖动,因为出问题就在那一分钟内,有接口超时,有接口失败。各种查登录机器,各种猜测,最后定位到一台 mq 节点内存有波动,导致部分生产者被夯住。最后发现是是新加的一台 mq 没有切割日志,导致程序内存使用过高。从开始排查问题到最后定位出问题,足足花了一晚上。这种痛只有经历过才知道,也促进我们成长,这就是所谓成长总是痛苦的。我们开始整合中间件日志,让应用和中间件产生联动。诸如此类的还有很多很多。。。
应用的可用性和稳定性越来越重要,如何降低排查问题的成本越来越重要,我们需要一双眼睛帮忙观察,一个大脑帮我们分析。
衡量服务稳定性,首要任务就是寻找合适的 SLI,设置合理的 SLO。选择衡量的标准至关重要:监控项太多,图表看不过来,出问题了不知道看哪个图表,大部分时候一出问题就蒙圈,能查问题的也就那么几个人。因此指标设计原则一定要精简精简直到无法精简。配合全局画像让大家一眼就能知道哪个环节出了问题。我们主要参考的是《Google 的 SRE 运维揭秘》,和借鉴蘑菇街赵诚老师的经验,从以下五个方面设置 SLO:
还有花哨的图表也只是辅助,大原则还是监控告警明确,快速定位出异常应用或故障节点,尝试自动故障转移或及时止损,最后通过分析画像或分析日志寻找根因。
我们来一起看一下这五条黄金法则是如何指导我们设计 SLO 的:
这五条法则是指导意见,希望能帮助大家。
平台构建最初的愿景,主要是随着微服务的推进,服务稳定性越来越重要,服务间调用出的问题越来越难以定位,排查的次数多了,各种工具脚本/Dashboard/小系统越来越多,这些经验很难传承,定制化高,推广成本大,更新迭代也不及时,普及度也是非常的低,能查问题的就那么几个人。
为了提高效率,面向全公司开发、测试全员,因此我们开始打造服务治理平台:
我们服务治理平台化演进,也经历了:人工 -> 工具化 -> 系统化 -> 平台化:
应用层、中间件的稳定性和可用性,是我们关注的两个大维度。包括节点资源信息,应用间调度信息。业内比较成熟的有:
我们的平台采用分布式前后端分离架构,可视化前台 Dany 是基于 vue(element-ui/element-admin),后端主要基于 Golang 和 Python,目前已监控 352 个业务应用,1200 多个节点,链路日志量级 30 亿左右。主要模块如下:
数据源主要包括 Promethues、Elasticsearch 和 Clickhouse,展示基于 Grafana。数据存储正逐步从 Elasticsearch 迁移到 Clikhouse,基本流程是 Gohangout 订阅 Kafka 清洗后持久化到 Clickhouse。
目前大部分服务依然部署在虚拟机上,有些指标我们通过写 shell 脚本让 zabbix 触发。随着容器化的推进,Prometheus 的生态更加适合我们,因此我们逐渐用 prometheus 替代原有的 zabbix 职责。
主要分析应用潜在风险,应用异常诊断 采用 Golang 自研系统(Snow)流式分析 Kafka 数据持久化到 Mysql。
链路追踪日志埋点我们集成到服务框架(php/node/java)中。记录所有 http 协议和 amqp 协议的请求,记录上下游,请求耗时,机器信息等,日志信息落盘本地,基于 ELK 持久化。
告警事件判定,记录告警事件处理工作流,告警应答(Ack)升级,我们基于 Python 开发了 Dolphin 系统。
我们目前记录链路的入口采用 AOP 模式植入到已有的框架中(php/node/java),业内还有无侵入解决方案类似 sidecar 模式,代理请求记录全链路。随着微服务的演进,为了加速请求,链路会同时并发请求,需要识别和准确标记时间线,推动着 APM 链路分析的演进。
微服务架构带来链路越来越深,随着业务增长慢接口,循环调用,双向依赖,慢 SQL 成为应用四大杀手,令无数开发闻风丧胆,血的教训迫使我们不能放过这些杀手。微服务架构另外的一个问题就是产生海量的日志,目前我们大约每天 30 亿次内网请求日志。为了分析四大杀手的特征,我们订阅 Kafka 日志流,分析过滤。得益于 Golang 的协程(goroutine)能力,每秒分析 5w+日志,目前只有两台虚拟机在分析,可以水平扩展分析能力。应用开发负责人会收到风险任务推送,通过给风险任务打上优先级,及时跟进解决,测试进行线上验证环节,最终平台会验证风险是否解除。分析后生成任务展示效果如下:
设计思路:整体流程依然是基于日志收集模式,业务方通过模板定义数据格式记录到日志,采集程序分析日志,映射到数据表中
触发预设的告警规则后,按优先级提供不同告警形式:邮件,微信群机器人,短信,电话。
由于目前大部分开发还处于监控意识培养的初期阶段,目前核心应用规模还是可控的,于是我们基于全应用做了兜底监控。如每秒全站请求异常状态,消费者处理异常,mysql 提交事务异常等。系统组默默的承担着全站 SRE 的职责。
为了告警的及时响应和快速处理,我们基于应用给出告警规则通用模板,业务设置相应的阈值即可,如每分钟请求异常数,应用程序产生的 sentry 异常数,MQ 发布、消费异常数等。
随着业务工程师逐渐加入,需要处理各种不同优先级的告警,一有告警就全员 All-in 排查。为了优化告警响应机制,引入主副值班 on-call 机制,按应用模块每周设置一个主值班, 主值班必须及时应答告警(ACK),尝试定位分析问题,必要的时候进行告警升级,通知团队负责人或请求其他团队协作。
我们监控核心指标,触发实时告警,推出趋势截图。精简的指标能比较客观的反映应用运行情况。画像数据来源 Clickhouse,大部分 SQL 执行都能在 1s 内返回。
机器资源饱和度也是非常关键的一项指标,应用吞吐能力根据自身情况有 CPU 密集型,有 I/O 密集型而有所不同。这些指标主要还是辅助作用,一般会反应在应用吞吐能力上。给应用容量评估提供指导意见。数据源来自 Prometheus 采集 node-exporter。
除了 RPC 请求入口,还有基于 APMQ 协议的请求,分布式任务调度中心的请求。应用依赖的中间件使用不规范,或者执行异常我们都能通过画像系统反映出来,给出优化意见。
中间件自身的稳定性也是非常重要的,可用性考核需要达到四个 9。大部分我们依赖 Prometheus 生态,如 Mysql-exporter,RabbitMQ 3.8 版本以后官方支持 prometheus 指标。针对 Mysql/MongoDB 等我们采用了 percona 的 pmm2。
随着微服务的拆分,局域网日志越来越大,每天大于 30 亿左右,对这些日志进行提炼分析时效性越来越低,加上膨胀的日志占用磁盘越来越大,从原先保留半个月到后来的 6 天。每天大约产生 800G。国内很多企业也遇到类似的问题,也尝试落地 Clickhous 替换 Elasticsearch,便捷的查询,数据压缩比高。迁移后 Dashboard 数据渲染基本上都在秒级,数据压缩比 1:4.2。
应用监控最初是基于 Zabbix 的,更多的是机器资源维度,最大的痛点是告警分组不友好,值班运维沦为了告警中转站,人工联系各业务方处理相关问题。再加上云原生的推进,Prometheus 的生态强大,接入开发成本低,成为我们现在监控的首选。
我们从蘑菇街赵诚老师那取了不少经,主要还是从应用的容量,可用性,时延,错误率,人工介入次数几个方面设计 SLO。关于 SLO 选定可以参考 Google 的设定模板。
大部分互联网公司,产品迭代速度是非常快的,应用技术质量和迭代速度相互竞争,代码质量有时候能决定产品的生死,越来越慢的接口会拖垮应用服务质量。从遇到故障问题才关心,慢慢关注点往前移,从代码坏味道,潜在风险分析,告警响应处理时长,应用稳定性和中间件稳定性都设置考核指标。好大夫实时监控告警大屏也逐渐成为一道风景线。
领取专属 10元无门槛券
私享最新 技术干货