前端监控系统Sentry搭建

7,141 阅读13分钟

导语


本文将结合工作,描述一下前端监控系统Sentry搭建过程中,背景、设计、实现、思考四个方面的感悟及问题。


背景

监控是什么

监控从字面含义来看包含两方面内容:监,监测的是代码;控,控制的是质量。监控是工具而不是目的,不是为了具有功能而监控,而是要通过监控,真正了解页面运行情况,以达到代码运行质量可控的目的。

监控不同于统计,统计关注的是一段时间内访问情况的一个总和,对于实时性要求并不那么高,可以延迟上报、累计上报;监控则恰恰相反,关注的是页面运行时的情况。

整个大前端角度来讲,监控的场景很多。比如:服务端监控接口的稳定性和性能;客户端监控crash和APP性能;对Web前端来讲,更加关注线上运行时的性能和报错。

监控对于线上线下来说都是有意义的,线下我们可以支持自动化测试,上线前就发现代码运行时的一些明显错误,这个可以做为线下防退化的参考依据。线上环境则更加复杂,不同的地域、设备、网络、浏览框架等诸多因素,导致同样的代码不同环境中运行时,结果可能会良莠不齐。我们希望了解这些情况,评估页面哪里需要优化。

搭建的缘由

公司内部现有统计平台,如thunder,spy等通用的平台,即可以收集性能指标,也可以收集前端异常信息,但是收集的异常信息大多做统计用途,关注有多少报错信息,或者某类错误有多少类别,一般不会包含具体报错的详细信息。

前端还有一个特点,静态资源会混淆后压缩,如果运行错误,拿到的报错堆栈信息没有太大含义,只会报第一行报了xx错误,假设有sourcemap,我们也只能借助Chrome Devtools来看具体是哪儿错误,但往往线上的报错,我们很难复现。

通过前面提到的两个问题的收集:统计平台报错信息收集不够详细,无法根据报错反解源码错误行数,我们选择基于开源Sentry在百度云上搭建了一套前端异常监控服务。


设计

方案选择

先来介绍一下Sentry功能。

Sentry是一个集中式日志管理系统。可以做以下事情,而且是相比于其他系统做的不错的地方。

  1. 丰富的SDK。不同语言、不同项目通过集成SDK。拿JS举例,不仅仅收集详细的用户设备信息,而且记录了用户的操作行为,通过点击了XX按钮,导致的报错
  2. 根据收集的数据,进行报警配置,进而实现监控的闭环。
  3. 支持标签功能,比如我们可以通过给错误统一拦截,增加标记CUID,后期在后台平台中同过CUID进行错误过滤
  4. 易于操作的后台。Sentry提供了一套后台管理系统,简单易行
  5. API支持。所有操作接口都提供了API服务,用户可以基于API进行界面自定义
  6. 活跃的社区。Sentry小组在Github上非常活跃,之前提Issuse 基本都是当天回复解决的。


再来看下K8S

首先提一下当下流行的Docker(是一个开源的应用容器引擎),Docker有一句口号:Build Once , Run Anywhere. 也就是说一个环境可以通过一次编译发布,在任何支持Docker的环境中可以快速跑起来,这解决我们日常部署环境的痛苦。但是大家实践的时候发现,如果想要将Docker应用于具体的业务实现,是存在困难的——编排、管理和调度等各个方面,都不容易。所以K8S(全称:kubernetes,基于容器的集群管理平台)应运而生,应用于广大的实际项目中


介绍一下百度云。

广告一波自家的提供的云服务平台:百度云。百度云提供了丰富的基础服务支持,比如强大的容器服务CCE,域名解析分发服务ITM,数据分析服务Sugar等。我们可以基于百度云提供的服务快速达成想要实现的内容。

  1. CCE提供基础的K8S容器环境
  2. ITM 智能域名解析调度,支持根据不同地域、网络选择不同机房机器
  3. Sugar 可以根据数据库数据,进行定制化报表拖拽式构建


整体架构

本身Sentry支持源码部署和容器(Docker、K8S)部署两种方式,考虑到稳定性,想要实现多机器多机房部署、负载均衡、智能调度等实际问题,基于百度云提供的K8S服务,容器化部署了Sentry,如图1。



图1 :Sentry 百度云部署架构


结合业务,继续看一下Senty在整体项目中地位置,如图2。


图2 :项目整体架构图

这种架构下的Sentry服务,有几个优势:

  1. 节省大量人力。基于百度云K8S运维省去了 日常机器运维、数据库、流量调度等人力成本;
  2. 节省大量机器。K8S运维,可以机器动态根据业务运行的情况,进行扩缩容;
  3. 基于开源项目,社区丰富,问题有群体讨论,问题解决迅速;
  4. 覆盖业务广,核心的服务提供了数据收集和分析的能力,接入层可以自定义实现。


实现

平台在梳理清楚了上面流程的基础上,很快就搭建了起来。但是在平台试运行活成中,监控的每个环节,不同程度的暴露除了一些问题。针对监控的每个流程环节,再次做了进一步的分析和优化。下面针对主要环节进行说明。

打点上报

监控信息上报,主要依赖于SDK。以前端为例,Sentry本身提供了一个SDK,需要在页面加载过程中,优先加载,进而实现尽可能多的错误捕获。

<html>
	<head>
	<title>监控报警</title>
	<script src="https://xx/sentry.js"></script>
	</head>

	<body>
	......
	<body>
</html>



实践过程中,发现打包后的sentry.js 有20K左右,如果放到顶部,对于追求页面性能的页面来讲,是灾难性的,因为JS放在顶部加载会阻塞页面的渲染。于是这对这种情况,进行了SDK后置优化。

<html>
	<head>
	<title>监控报警</title>
	<script>
		let estack = err => {
			return win[ers].length < 10 ? win[ers].push(err) : false;
		};

		win.onerror = (a, b, c, d, error) => {
			estack(error);
			return true;
		};

		win.addEventListener('unhandledrejection', error => {
			error.preventDefault();
			estack(error);
			return true;
		});
	<script>
	</head>

	<body>
	<script src="https://xx/sentry.plus.js" async ></script>
	<body>
</html>



  1. 自定义拦截error和promise错误,页面加载结束后,统一进行错误上报
  2. 扩展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%}
<script type="text/javascript" src="https://xx/sentry.plus.js?v={%$smarty.now%}" crossorigin="anonymous"></script>
{%/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、岳鹰等,但是很遗憾,发现大多是收费的。公司层面的产品,数据体量相对较大(但这方面的投入往往是值得的),有时数据产出较慢,结果往往阶段性地被新产品替代,厂内现在有一些针对前端的监控平台,诸如:天幕等,可能数据的采集、存储、过滤、展现、报警等监控过程中的每个环节,都需要需要耗费的人力和财力,这些都还缺少一些中台的思路。

总结

通过搭建和实现监控的整个过程,一方面充分体会到了云服务提供的技术给产品带来的便利,一定是未来的方向;另一方面,脱离业务的技术是不靠谱的,技术服务于业务,我们实现的技术一定要在业务中进行验证,才会促进技术更加完善,更加解决业务的实际问题。