导语
本文将结合工作,描述一下前端监控系统Sentry搭建过程中,背景、设计、实现、思考四个方面的感悟及问题。
监控从字面含义来看包含两方面内容:监,监测的是代码;控,控制的是质量。监控是工具而不是目的,不是为了具有功能而监控,而是要通过监控,真正了解页面运行情况,以达到代码运行质量可控的目的。
监控不同于统计,统计关注的是一段时间内访问情况的一个总和,对于实时性要求并不那么高,可以延迟上报、累计上报;监控则恰恰相反,关注的是页面运行时的情况。
整个大前端角度来讲,监控的场景很多。比如:服务端监控接口的稳定性和性能;客户端监控crash和APP性能;对Web前端来讲,更加关注线上运行时的性能和报错。
监控对于线上线下来说都是有意义的,线下我们可以支持自动化测试,上线前就发现代码运行时的一些明显错误,这个可以做为线下防退化的参考依据。线上环境则更加复杂,不同的地域、设备、网络、浏览框架等诸多因素,导致同样的代码不同环境中运行时,结果可能会良莠不齐。我们希望了解这些情况,评估页面哪里需要优化。
公司内部现有统计平台,如thunder,spy等通用的平台,即可以收集性能指标,也可以收集前端异常信息,但是收集的异常信息大多做统计用途,关注有多少报错信息,或者某类错误有多少类别,一般不会包含具体报错的详细信息。
前端还有一个特点,静态资源会混淆后压缩,如果运行错误,拿到的报错堆栈信息没有太大含义,只会报第一行报了xx错误,假设有sourcemap,我们也只能借助Chrome Devtools来看具体是哪儿错误,但往往线上的报错,我们很难复现。
通过前面提到的两个问题的收集:统计平台报错信息收集不够详细,无法根据报错反解源码错误行数,我们选择基于开源Sentry在百度云上搭建了一套前端异常监控服务。
Sentry是一个集中式日志管理系统。可以做以下事情,而且是相比于其他系统做的不错的地方。
丰富的SDK。不同语言、不同项目通过集成SDK。拿JS举例,不仅仅收集详细的用户设备信息,而且记录了用户的操作行为,通过点击了XX按钮,导致的报错根据收集的数据,进行报警配置,进而实现监控的闭环。支持标签功能,比如我们可以通过给错误统一拦截,增加标记CUID,后期在后台平台中通过CUID进行错误过滤易于操作的后台。Sentry提供了一套后台管理系统,简单易行API支持。所有操作接口都提供了API服务,用户可以基于API进行界面自定义活跃的社区。Sentry小组在Github上非常活跃,之前提Issuse 基本都是当天回复解决的。
首先提一下当下流行的Docker(是一个开源的应用容器引擎),Docker有一句口号:Build Once , Run Anywhere. 也就是说一个环境可以通过一次编译发布,在任何支持Docker的环境中可以快速跑起来,这解决我们日常部署环境的痛苦。但是大家实践的时候发现,如果想要将Docker应用于具体的业务实现,是存在困难的——编排、管理和调度等各个方面,都不容易。所以K8S(全称:kubernetes,基于容器的集群管理平台)应运而生,应用于广大的实际项目中
广告一波自家的提供的云服务平台:百度云。百度云提供了丰富的基础服务支持,比如强大的容器服务CCE,域名解析分发服务ITM,数据分析服务Sugar等。我们可以基于百度云提供的服务快速达成想要实现的内容。
CCE提供基础的K8S容器环境ITM 智能域名解析调度,支持根据不同地域、网络选择不同机房机器Sugar 可以根据数据库数据,进行定制化报表拖拽式构建
本身Sentry支持源码部署和容器(Docker、K8S)部署两种方式,考虑到稳定性,想要实现多机器多机房部署、负载均衡、智能调度等实际问题,基于百度云提供的K8S服务,容器化部署了Sentry,如图1。
图1 :Sentry 百度云部署架构
结合业务,继续看一下Senty在整体项目中地位置,如图2。
图2 :项目整体架构图
这种架构下的Sentry服务,有几个优势:
节省大量人力。基于百度云K8S运维省去了 日常机器运维、数据库、流量调度等人力成本;节省大量机器。K8S运维,可以机器动态根据业务运行的情况,进行扩缩容;基于开源项目,社区丰富,问题有群体讨论,问题解决迅速;覆盖业务广,核心的服务提供了数据收集和分析的能力,接入层可以自定义实现。
平台在梳理清楚了上面流程的基础上,很快就搭建了起来。但是在平台试运行过程中,监控的每个环节,不同程度的暴露除了一些问题。针对监控的每个流程环节,再次做了进一步的分析和优化。下面针对主要环节进行说明。
监控信息上报,主要依赖于SDK。以前端为例,Sentry本身提供了一个SDK,需要在页面加载过程中,优先加载,进而实现尽可能多的错误捕获。
…
实践过程中,发现打包后的sentry.js 有20K左右,如果放到顶部,对于追求页面性能的页面来讲,是灾难性的,因为JS放在顶部加载会阻塞页面的渲染。于是这对这种情况,进行了SDK后置优化。
自定义拦截error和promise错误,页面加载结束后,统一进行错误上报扩展sentry.js,升级为sentry.plus.js ,支持发现原有错误的收集,进行数据详细上报。
通过SDK的改造,大大减少了页面对于性能方面的担忧,更加放心的使用Sentry服务。
SDK集成之后,日志采集通过一个POST接口请求实现。页面运行时,如果报错,会自动触发通过接口发送数据。
这时候是否需要支持采样,成了一个需要考虑的问题。因为如果没有采样,同时赶上较大的业务量,极大概率触发日志采集功能,大量日志上报,而有用信息较少。这时候采样就解决了这个问题。SDK本身是支持采样的,初始化的时候,只需要进行简单的配置
Sentry.init({
dsn:‘xxx’,
sample: 0.5
});
这个抽样,指的是古玩论坛项目运行时,每次触发报错后,是否要进行错误上报的一个概率。但是对于追求页面性能的页面来讲,通常往往希望的是,SDK小流量接入。尽可能少的去影响所有页面。我们目前页面基于Php的Smarty模板进行的首屏渲染,所以改造了上报采集的方法:
{%assign var=“random” value="{%math equation=rand(1,100)/100%}"|string_format:"%.2f"%}
{%assign var=“sample” value=“0.5”|string_format:"%.2f"%}
{%if $random < $sample%}
{%/if%}
通过改造,又跟进一步减少了监控代码对业务的影响,业务更加方便的接入。
本身Sentry使用的是PostgreSQL,K8S部署时,数据库这里通过配置,使用百度云提供的数据库服务。
postgresql:
enabled: false
nameOverride: sentry-postgresql
postgresqlDatabase: sentry
postgresqlHost: 192.168.1.1
postgresqlPassword: xxx123
postgresqlPort: 3306
postgresqlUsername: sentrydb
数据库的费用也是挺贵的,占据了整体1/3资源的消费。业务接入的越多,存储数据量越大,一开始买的50G空间,很快就满了。
数据到底要不要,我分析了一下:对于报错本身的数据,尤其是每个错误的详细信息,没必要存储那么久,但是对于报表性质的内容,如报错总体情况的同环比,需要存储更早以前结果的。
第一种方法,土豪的做法:数据库扩容,继续增加投入购买。这种就是资金预算投入;
第二种做法:根据现有,收集错误的内容,把需要做报表的结果计算后单独存储,然后定期数据库清理,比如可以起一个脚本,进行定期请里10天前数据。
这里有一个小插曲,Sentry官方其实提供了清理数据库的API,可以通过命令进行清理:
// 进入容器
docker exec -ti xxxx /bin/bash
// 清理
sentry cleanup --days 0
数据虽然清理了,但是发现PG数据库的容量没有释放,这是因为cleanup的使用delete命令删除postgresql数据,但postgrdsql对于delete, update等操作,只是将对应行标志为DEAD,并没有真正释放磁盘空间。通过以下命令,彻底清空。
sudo -u postgres vacuumdb -U postgres -d sentry -t nodestore_node -v -f --analyze
前面也提到过,Sentry提供了简单友好的后台管理系统。项目概况中,可以体现数据的报表展现。如图3。
图3:大盘展现
实践过程中,尤其是给老板汇报的时候,发现只有这样的一个展现报表是不够的。经过调研发现百度云提供Sugar服务。可以直接链接数据库,对想要的数据自定义进行数据聚合,产出对应报表。这个产出需求还在调研中,不过产出的效果是非常令人期待的。配置内容如图4,预期效果如图5。
图4:配置内容
图5:预期效果
做为监控的闭环,我们可以在Sentry后台中,根据不同的规则,设置邮件报警。Sentry官方建议的邮件服务也不停在变更,最初的Exim4改为了mailgun,综合考虑费用的问题,我们最终还是选择docker搭建Exim4,然后邮件内容通过申请公司邮件安全组,白名单放开发送邮件的机器。最终实现了错误信息及时通知业务的功能。效果如图6。
图6:监控效果
以上就是在具体实践过程中,关键路径遇到的一些问题,分享给大家。
公司的目的是盈利。一方面公司要控制成本,我们可以看到投入QA人力日益削减,另一方面又需要我们线上运行的代码更加稳定,有什么办法可以做到呢?一个高效的方法就是加强监控。
通过监控,可以快速自主地发现问题。
可以将收集上来的数据进行分类筛选,然后设置报警告知。根据我们监控内容,设定不同的阈值,当达到阈值的时候,第一时间有效的通知到对应的研发人员,进行分析和修复。
通过监控,可以全方位了解页面运行情况。
通过信息收集,可以获取到用户访问的区域、机型、APP版本等基础用户信息,同时也可收集到页面运行时的性能,要知道性能就是金钱(打开速度一定程度上会影响用户的去留)。
通过监控,可以指导后期项目开发。
经过一段时间的沉淀,我们收集过的错误,可以绘制出一个报表,统计出我们某段时间内问题产生的原因、报错、解决方案。
从研发流程上来看(如下图所示),我们的项目不是完成上线就万事大吉。需要监控页面线上运行情况,根据监控的数据及时进行复盘,循环迭代优化,形成持续的研发闭环生态。
以上这些监控的意义,是日后流程机制的指南,是研发同学的行为准则,也是老板、高工某些关键时刻做决策的参考内容之一。通过监控,更加直观地、全方位立体化地了解产品。
中台是公司内部最近技术方面的战略方向。在我看来: 监控可以输出一个中台的方案,各部门基于中台服务进行定制化扩展 。
其实我们这里分享的Sentry系统,就可以作为公司内部的一个中台服务进行输出。各部门可以根据业务去定制SDK,也可以根据数据需求,自定义报表和报警。整个Sentry黑盒对外提供API服务,因为K8S带来的便利性,只需要对应部门提供预算,申请机器,往K8S上面增加缩减即可。
市面上其实已经存在很多不同种类的监控工具。比如:frontjs、arms、岳鹰等,但是很遗憾,发现大多是收费的。公司层面的产品,数据体量相对较大(但这方面的投入往往是值得的),有时数据产出较慢,结果往往阶段性地被新产品替代,厂内现在有一些针对前端的监控平台,诸如:天幕等,可能数据的采集、存储、过滤、展现、报警等监控过程中的每个环节,都需要需要耗费的人力和财力,这些都还缺少一些中台的思路。
通过搭建和实现监控的整个过程,一方面充分体会到了云服务提供的技术给产品带来的便利,一定是未来的方向;另一方面,脱离业务的技术是不靠谱的,技术服务于业务,我们实现的技术一定要在业务中进行验证,才会促进技术更加完善,更加解决业务的实际问题。