NOS服务监控实践

叁叁肆2018-10-16 09:31

本文来自网易云社区

作者:王健


一、  背景

此处所说的服务监控程序,是通过模拟用户的请求,对一个系统的服务质量进行监控的程序。服务监控程序的主要目的是,从用户的角度出发,通过发送端到端的请求,确认系统对外提供的服务是否正常。

简单来说,一个好的服务监控程序应该具备以下功能:

1. 检测服务是否存活

2. 检测服务质量是否正常

3. 检测服务质量的变化趋势

4. 对每日的监控数据做统计报表

5. 运维友好的

6. ……

需要首先说明的是,监控一个系统服务是否正常是一个全方位的工作,需要进行如进程监控、请求错误率监控、网络流量监控,日志监控等工作。然而服务监控程序通常有着不可替代的作用,例如,通过将服务监控程序部署在用户的机器上,就可以从用户的角度对系统的服务质量进行监控,包括请求响应时间,请求错误率等等。

本文接下来首先分析在开发一个服务监控程序时需要考虑的方方面面,接着介绍在部署和运维一个服务监控程序的时候需要注意的问题。

二、    监控目标

要实现一个服务监控程序,首先需要明确要对服务可能出现的哪些异常情况进行监控,以下列举了一些可能出现的服务异常:

1. Dead – 服务已经挂掉(如进程异常退出,系统异常重启等)

2. Unreachable – 服务不可达(如DNS异常,网络中断等)

3. Unresponsive – 请求可以正常发送,但是服务无响应(如服务器内部异常等)

4. Slow – 服务可以正确响应,但是响应时间过长(如服务器过载等)

5. Wrong – 服务可以及时响应,但是结果不符合预期(如服务器内部数据库异常等)

6. ……(以下还有很多异常)

对于以上的一些错误,如服务进程异常退出等,可以通过进程监控等及时发现。然而对于服务不可达,或者服务响应时间变长等,通常服务内部的监控并不能及时发现,此时就需要部署服务监控程序。部署服务监控程序的一个重要目标,就是当由于系统内部的错误、或者系统外部依赖的环境的异常导致用户的请求受到影响时,可以在短时间(1分钟)发现并及时处理。

同时,通过及时分析服务监控程序的请求记录,也可以对系统可能出现的瓶颈及时预警。举例来说:当服务监控程序的请求响应时间逐渐变长时,则说明系统可能需要扩容了。

三、    服务监控程序的实现

实现一个服务监控程序相对容易:只要模拟用户的请求发送到服务器,当请求超时或失败时则进行报警通知管理员即可。然而要实现一个好的监控程序,达到报警及时、准确——出问题是马上报警,不出问题不误报警,并不是一件容易的事情。

以下介绍实现一个好的服务监控程序时需要注意的一些问题。

3.1. 服务监控程序对系统的影响要尽量小

服务监控程序对被监控系统的影响要尽量小,被监控系统不能为了因为处理服务监控程序的探测请求而消耗太多资源,这里的资源包括:网络资源、计算资源、存储资源等。举例来说,我们的NOS(Netease Object Storage,网易对象存储)对用户提供了以下功能:

1. 用户可以向自己的存储空间中上传和下载对象

2. 用户可以对一个图片对象进行图片处理相关操作(如裁剪,给图片加水印等)

3. 用户可以对一个视频对象进行视频处理相关操作(如截取视频帧,视频转码等)

4. 还提供了其他一些操作,如List自己存储空间中的对象,批量删除对象等操作

我们的每一种服务都由一个相对独立的集群提供:

1. 上传下载服务有数据库和存储集群

2. 图片处理服务有图片处理集群

3. 视频处理服务有视频处理集群

对于NOS,我们的服务监控程序在实现时有以下考虑:

1. 为了检测服务上传下载服务,需要模拟用户发送对象上传下载请求。这里要注意的是,上传下载的对象不能太大,原因有两个:一是服务器处理逻辑对于大对象和小对象是一样的;二是避免因为上传或下载一个大对象出现的网络波动或磁盘负载抖动。

2. 为了检测图片处理服务,只需要对一个小图片进行最简单的图片处理即可。避免对一个大图片进行过于复杂的图片处理带来的CPU消耗。

3. 为了检测视频处理服务,只需要发送对一个小视频截取第一帧的请求即可。如果截取一个大视频的任意帧,程序可能需要将整个视频全部读到本地才能完成,这会带来巨大的网络和磁盘开销。

4. 我们实现的服务监控程序不会执行一些复杂的操作,如批量删除对象等。原因是批量删除对象实际上最终是调用删除单个对象的接口,而我们会在检测上传下载服务中对删除对象的接口进行调用(上传 >下载 >删除)。

这里所要强调的是:在写服务监控程序的时候,要明确需要如何监控自己的系统,并且用最小的代价来进行探测。

3.2. 及时发现系统异常

服务监控程序周期性地向被监控系统发送探测请求,为了能及时发现系统异常,这个探测周期就需要设置的足够小。然而若探测周期设置的过小,必然对被监控系统的影响会提高。因此需要根据被监控系统的具体情况来设定该周期。例如对于我们的NOS系统来说,文件读写是核心服务,而图片和视频处理是附加服务。因此对于核心的上传下载服务,探测周期均为1分钟一次,而图片和视频则可以将周期设置为5分钟。

这里所要强调的是:为了设置合理的探测周期,要能够对被监控系统的重要程度进行区分,根据不同的重要性来设置不同的探测周期。当然,如果探测请求对系统的影响很小,那么所有的探测请求设置的足够频繁也没有问题。

3.3. 精确报警

所谓精确报警,就是做到“系统正常不报警,系统异常必报警”,做到了这一点,那一旦运维人员收到相关的报警,则需要将该报警作为第一优先级立即进行处理。此处有一个问题需要注意:即系统偶尔的小抖动(如网络丢包,或者系统偶尔负载提高导致响应时间变长等),不应该发送报警,而只需要记入日志并在次日发送邮件给运维人员即可。这就需要在开发服务监控程序时考虑相关的处理逻辑。

以下给出NOS服务监控程序探测上传下载服务的相关处理逻辑:

1. 每分钟发送1次上传、下载、删除请求,判断请求返回值是否符合预期,同时记录每次请求的响应时间;

2. 如果请求的返回值符合预期,且响应时间没有超过设置的阈值,则等待一分钟再次发送请求;否则,将错误信息记入日志,并执行第3步;

3. 连续发送5次请求,并判断这5次请求的返回结果和执行时间。如果超过2次请求出错或超时,则发送报警,否则只记日志不发送报警。该处理逻辑中所有的次数(包括发送请求次数,报警阈值等)均可以在配置文件中设置,保证运维人员可以根据实际情况配置合理的值。这种实现方式,可以有效防止偶发的错误造成的误报警。当然,对于那些出错的请求,需要好好进行分析。

3.4. 全面监控子系统

通常,一个服务由一个集群来提供,前端通过Nginx的负载均衡来将用户请求分发到该集群的各个工作节点。这里可能会出现的一个问题是:当一个工作节点出现异常时,前端用户的请求可能不会受到影响,然而系统的运维人员一定需要知道该信息。

我们的做法是,在给各个工作节点配置如进程监控,日志监控等常规监控的基础上,通过部署在内部某节点的服务监控程序将请求直接发送到该工作节点上,用于监控该节点的服务质量。我们NOS的服务监控程序同时监控了NOS的外部域名、内部域名、前端Nginx的虚拟IP、真实IP,各个服务子节点的服务端口等。

3.5. 服务监控程序的监控

服务监控程序监控系统运行状况,然而作为一个服务本身,它的状态也应该被监控起来。否则,如果服务监控程序本身已经异常退出,则无法在系统故障时及时报警。服务监控程序的监控需要从开发和运维两个方面进行保障,在这里先谈谈开发时需要考虑的因素:

1. 要考虑运维误操作可能会kill掉服务监控程序,因此程序中需要捕获kill信号并发送报警或输出一条FATAL级别日志(用于日志监控);

2. 服务监控程序可以考虑提供HTTP访问接口,供外部程序监控服务监控程序的状态。当系统部署多套服务监控程序时,也可以利用该接口查看各个服务监控程序所在机器的服务质量;

3. ……

3.6. 多重报警机制

当服务监控程序可以及时、精确发现服务异常时,需要通过短信报警(或邮件等其他报警)将问题告诉给系统运维人员。在开发时需要考虑服务监控程序需要提供至少两套报警机制,防止其中一种报警方式失灵的情况。

举例来说,服务监控程序至少可以采用以下几种方式进行报警:

1. 直接调用公共的报警短信接口(如运维平台提供的Http接口)发送报警;

2. 通过记录错误日志,进行日志监控,当日志中出现特定关键字时进行报警;

3. 将监控的数据推送到统一的监控平台,在监控平台中实现逻辑判断和报警发送

3.7. 其他若干注意事项

以下再列举一些其他在开发服务监控程序时的注意事项:

1. 报警信息要准确

发送报警信息很重要的一方面在于帮助开发和运维尽快定位问题,因此报警信息一定要准确。下面是一些推荐的报警信息:

a. “192.168.0.1上NOS读写监控程序连续5次请求超时”

b. “产品云音乐上NOS视频截图监控程序请求出错,错误码为500 Internal Error”

2. 可以对配置文件进行动态reload

例如,如果服务监控程序有一个配置文件:hosts.conf,表示该监控程序需要探测的所有服务器地址。那当该配置文件修改时,程序可以在下次探测时去探测新加入的地址。这样减少了运维关闭服务监控程序和重启的操作,也就减小了出错的风险。

3. 服务监控程序的重试

我们之前实现的服务监控程序,内部采用JavaSDK中提供的PutObject函__________数和GetObject等函数。这些函数在某些错误的情况下会进行重试,而这个重试很有可能导致屏蔽了某种可能的系统异常。

4. 服务监控程序的日志

服务监控程序的日志也应该按照生产系统的标准,输出操作日志和错误日志等,规范的日志可以大大加速错误定位过程。

5. 防止服务监控程序导致系统过载

在系统已经过载的情况下,请求可能被拒绝或超时。此时,当服务监控程序判断系统已经过载时,则发送报警。同时应该暂停(如暂停10分钟)向服务器发送探测请求,减轻系统负担。

6. 将所有服务的监控都放在一个程序中

以NOS来举例,我们将所有服务的监控(上传下载、图片处理、视频处理)都集成在一套代码中,通过配置文件可以分别对各类监控进行配置。这样做的好处是:代码维护和运维成本低,因为只需要维护一套代码,部署一套代码即可。然而需要注意的是,所有的监控都部署在一台机器上,可能导致该机器的占用较多的带宽,因此需要特别注意采样数据不能太大。

7. 服务监控程序的代码应该纳入版本管理

需要把服务监控程序作为整个系统的一个重要部分,进行代码的管理。

四、    服务监控程序的部署与运维

开发服务监控程序只走完了长征路的第一步,而剩下的两万五千里路都依赖服务的部署和运维。以下介绍部署和运维服务监控程序的注意事项。

4.1. 多点部署

将服务监控程序进行多点部署至少有两个方面的目的:

1. 服务监控程序的高可用——防止一台服务监控程序挂掉的情况

2. 从用户角度监控服务——通过将服务监控程序部署在用户的服务器上,可以从用户的角度监控服务质量多点部署也有以下问题需要注意:

1. 服务监控程序必须能够支持多点部署,因此在开发的时候需要注意多个服务监控程序不能相互干扰;

2. 部署在用户服务器上的监控程序要占用尽量少的资源,避免对用户本身的系统产生影响,在部署时也可以通过配置若干参数:如探测周期、探测请求数量等,降低服务监控程序占用资源;

4.2. 报警阈值调节

在开发服务监控程序时,需要尽量将所有的参数做成可配置参数,同时可以动态reload,如:

1. 要监控哪些服务器

2. 要监控哪类操作

3. 监控周期是多少

4. 每个监控周期发送多少请求

5. 请求超时时间是多少

6. 一次请求出错后要连续发送多少请求

7. 报警接收人信息

8. ……

而运维人员的工作是,需要根据被检测系统的实际情况设置这些参数,并且调节这些参数为一个合理的值。参数调节应该遵循“先紧后松”的原则,即开始是可以将报警阈值设置的敏感一些,然后去分析每次报警,如果确认是误报,再将报警阈值调高一点。同时,及时不报警,也应该及时分析系统的错误日志,确保没有报警遗漏。

4.3. 报警可用性检查

所谓报警可用性检查,就是运维人员需要定期对服务监控程序的报警逻辑进行验证,确保这些报警都能正确发出并被相关人员接收。验证报警可用性并不是一件容易的事情,因为有时候可能需要主动触发一些错误逻辑,这会使该验证过程耗时费力。因此在开发服务监控程序时,需要考虑如何给运维提供方便的可用性验证接口。

例如,可以在配置文件中设置一个字段testAlarm,当该字段设为true时,服务监控程序主动触发一些错误,例如对一个文本文件进行图片缩略操作,或者下载对象时指定一个错误的文件名等,这样便可以很方便的触发一次报警,用于验证报警可用性。

4.4. 报警处理

当接收到一条报警时,运维人员应该有相对应的报警处理流程,哪怕该流程是“执行ping操作验证网络是否联通,并通知服务监控程序所在服务器的相关产品方”。有很多的文章强调报警必须要Actionable,即可被处理的报警。运维和开发需要一起确认哪些错误应该发送报警,而哪些错误只要计入日志或在次日邮件报表通知即可。如果在收到一条报警而无事可做,那设置该报警的意义不大。

4.5. 其他若干注意事项

以下再列举一些部署和运维服务监控程序时的注意事项:

1. 任何一个报警,需要发给至少两个相关人员,且有一个主要负责人员发给至少两个人,是为了确保报警不会被遗漏;而发给相关人员,是为了防止非相关人员因为经常收到与自己无关的报警短信而忽略了发给自己的重要报警短信。

2. 服务监控程序的上线流程

服务监控程序也需要执行完整的从开发到测试到部署上线的流程。尽管服务监控程序只是一个外部程序,然而我们通常会在内网部署让它可以将请求直接发送到后端各个子节点,因此也存在一定的风险,顾需要严格按照上线流程执行。


网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区



相关文章:
【推荐】 HBase - 数据写入流程解析
【推荐】 Gradle task
【推荐】 Lily-一个埋点管理工具