IT技术博客大学习 共学习 共进步

如何快速实现一个基于 Nginx 网站的监控场景

Linux.中国 - 开源社区 2017-10-15 10:03:55 浏览 2,602 次

小明所在的一家小型互联网创业公司一直将应用运行在阿里云上。该应用采用通用的分布式 Nginx+App 架构为用户提供电商数据统计的 webservice 服务。应用运行至今除偶发各类 Bug,性能问题以外,情况还算良好。

最近,小明的老板给小明布置了一个任务,希望把应用服务监控起来,以提高应用运行质量。老板的需求有三点:

  1. 先以应用服务监控为抓手,能

    • 实时统计应用各类服务的调用次数

    • 基于 a,实时统计各类服务各类返回值的次数,如 200,404,500,等。

    • 基于 b,如果某类返回值调用超限,进行实时报警。

  2. 提供历史查询功能,能返回任意时段任意服务任意返回值调用次数统计。

  3. 以后未来公司各类定制的业务监控能快速扩展到该系统上,如各接口响应统计时间,用户特征统计等。

“方案尽量多快好省,而且搭建的监控平台最好就在阿里云上,数据不要外放在第三方云上,主要是为了公网流量成本和以后大数据分析作准备”,老板最后提到。

技术选项

小明接到任务以后开始着手进行技术选型。摆在他面前貌似可行的有三个选择,传统 OLAP 式处理方式,搜索引擎,以及实时计算方式。

在调研现状和众多技术后,他发现,

  1. 由于公司业务规模不小,白天峰段的平均 QPS 已经上百,而且业务还在快速增长,因此将每秒上百次调用信息每次直接存放到数据库中再实时查询肯定不合适,成本太高且不适合扩展。

  2. 阿里云提供搜索引擎服务,错误统计功能基本能满足老板需求。但是不确定因素有两个。一方面搜索引擎价格存储成本偏高(搜索引擎需要引入索引存储),而且各类聚合查询如接口响应时间统计等查询响应时间不太好保证,另一方面考虑到实时报警还需要编写 API 不停进行各类调用的错误次数的轮询,性能和成本都不太确定。

  3. 基于实时计算的架构,可以将线上所有日志通过服务,返回值错误类型,和时间等维度在内存中进行实时的聚合计算,然后再持久化到存储中。一方面实时计算效率高,聚合后的结果大小会比原始数据大大减少,因此持久化成本低,实时能保证;另一方面还可以在内存中实时校验报警策略,让报警的性能开销足够小。

综上考虑,基于实时计算的架构看来最能满足当前公司的需求。决定了以后,小明开始思考进一步架构设计。

架构设计

决定了基于实时计算的技术以后,小明开始进行架构设计。通过参考各类技术网站,他发现要架构一个靠谱的网站监控方案,需要的组件以下缺一不可。

  • 数据通道:负责将数据从 Nginx 拉取出来,传送到搜索引擎。数据通道同时肩负数据堆积和数据重算的任务。

  • 计算引擎:基于 Nginx 服务,错误码,时间的维度的聚合实时计算逻辑需要基于选定的引擎进行编写。计算引擎最好能同时负责一些报警的逻辑。

  • 存储:存放最终 Nginx 监控结果的地方。考虑到监控结果虽然表结构简单,但是各种维度查询比较多,最好是类似于 OLAP 的存储类型。

  • 展示门户:针对所有 Nginx 监控结果作各类维度的快速分析和展示。

好在针对前三个组件,阿里云提供了一些现成的产品组件,小明不需要自己手动一个个去搭建,因此入门门槛还不算高。

  • 数据通道这块,小明在阿里云上选取了一款类似于 Kafka 的数据通道,在支持性能和消息堆积等特性的同时,在数据接入上提供了一定的简便性。

  • 计算引擎上,小明为了简易入手,选择了一款基于 spark-stream 计算引擎组件,可以上面直接写 SQL 语句进行实时计算编排而不需要自己写流式计算程序。

  • 存储方面,由于没有太强事物需求,而且在容量上要求较高,小明选择了一款类似 Hbase 的云上存储产品。

  • 展示门户方面,没有直接对应产品。小明挠了挠头,决定还是只能自己突击一下前段编程技术,基于开源展示框架来编写一个简单的查询门户。

跟老板申请了预算以后,小明开始陆续开通各类产品进行开发测试。预计一个月完成任务,

漫漫开发路程

开通流程很简单。花了半天不到,kafka、storm、hbase 的租户集群到手。可惜常言道,开发项目 80% 的时间花费在最终 20% 的坑上。项目过了一个月,但是功能尚未完成 70%。小明在自己的技术博客上默默的记录下以下踩过的坑。

集成故障排查成本

由于需要集成的组件包括数据通道,实时计算层,后台存储,并在代码中集成推送数据逻辑以及报警查询逻辑。每个环节稍有出错将造成整个链路阻塞,调试成本显得非常高。

日志清洗

开发期间为了获取到相关应用为了调整对于日志的推送逻辑,需要在每台 Nginx 日志内容变更以后再在每个服务端变更 API 的推送逻辑,变更过程冗长且容易出错。

持久化表设计

除了要针对监控项做出适合的表库设计,并尽量避免索引热点以外,还需要考虑当数据结果由于实时计算层不稳定重复计算时如何保证数据库写入幂等性,这对表结构设计是一个不小的挑战。

延迟数据合并

如果由于应用原因导致 Nginx 日志数据被延迟发送,如何保证比如晚到 1 个小时的数据能被实时计算引擎准确计算并将结果合并到之前的结果。

报警

针对所有结果需要设置定时任务每分钟对数据进行遍历查询。比如针对任何返回 500 调用错误超过 5% 占比的服务,需要所有服务进行多次的调用结果进行遍历查询。如何不遗漏所有的服务错误检查的同时保证高效率查询也是个不小的挑战。

报警准确性

有的时候由于日志延迟,上一分钟部分服务器正常日志还没采集全,导致局部 500 调用错误的服务暂时超过 5%,类似错误是否需要报警?如果报警,有可能误报,不报警的话,可能漏报,怎么处理呢?

如何统计 UV、TopN

以 UV 为例。如果要跨任意时间度查询 UV,则常规手段还需要在数据库中存入每单位时间(如分钟级别)的全量 IP 访问信息。这对于存储利用率来讲显然是无法接受的。有没有更优化的方案?

针对错误场景的诊断方法

针对各类返回值 500 的调用错误,业务方提出希望出现 500 错误时能根据时间和调用服务维度查询到详细的调用入参和其他详情,其场景和日志搜索类似。对于类似新加入需求,貌似通过实时聚合计算和存储不能直接办到。需要对日志另辟蹊径另行处理。

以上问题还不包括前段展示的各类问题。

掐指一算,两个月晃眼过了。项目还没弄完一半,小明有点急了。

另外一种新的思路

小明晚上约了自己的同门师兄老丹搓串。就着小酒,小明把自己最近的烦心事从头到尾跟老丹说了一遍。

老丹听了一拍大腿:“小明,你这就奥特了。其实在阿里云上有一款云产品, 叫做业务实时监控,简称 ARMS,基本上你遇到的这些问题,在 ARMS 上已经提供了一站式的解决方案,你只需要快速接入即可。”。

“噢,是么?我们业务的监控逻辑很多都是基于 Nginx 日志定制,ARMS 具备接入 Nginx 日志的能力,并允许让我定制业务监控能力么?“小明问道。
“当然。ARMS 上不仅提供监控 Nginx 的任务模板,本身自带报警和监控报表,同时还全程开放定制能力。如果你要增加自己的业务监控逻辑,或者删除或修改自己不要的通用监控逻辑,直接在其平台上定制即可。”老丹答道。

“听起来不错。最终结果除了报表和报警外,公司的下游业务平台也能用么?”

“可以的,ARMS 提供 API, 下游系统直接对接数据 API 即可,跟你在云上直接读数据库没什么本质区别。”

“听起来不错,看来我的项目有救了,我赶紧去看看。”

实现一个基于 Nginx 的网站监控场景

1. ARMS 的 Nginx 监控方案概述和准备

目前在监控领域上比较流行的数据处理方法有很多种,例如,搜索引擎,时间序列数据库,实时计算,甚至是大数据离线计算,等。

ARMS 采用的是实时计算+列式存储。这种方案的优势是数据实时性高,而且对于固定的数据查询接口查询效率非常块。在 Nginx 的监控方案中,其架构概要如下所示, 蓝色部分为 ARMS 所集成的 Nginx 监控开箱即用的黑盒。

由于 ARMS 的分析是针对 Nginx 的 access.log 日志,因此对 Nginx 日志有一定要求,需要用户在 nginx.config 中配置出打印内容,包括:“$upstream_response_time” “$request_time” 等代表请求消耗时间的日志信息。如下例:

 log_format   main '$remote_addr - $remote_user [$time_local]  $status ''"$request" $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"''"$upstream_response_time" "$request_time" "$ user_cookie_id"' ;  

这样的话,打印出的日志,大致如下表所示。

58.211.119.29 144288 - [16/Mar/2017:21:47:07 +0800] "POST http://arms.console.aliyun.com/api/query.json?action=DataQueryAction&eventSubmitDoQueryData=1" 200 594 "https://arms.console.aliyun.com/" "127.0.0.1:8080" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4" "0.144" "0.144" "EX866MB1-Y70JO57WM37ST3HWDVFK3-JWPNH30J-Z"58.211.119.29 148219 - [16/Mar/2017:21:47:08 +0800] "POST http://arms.console.aliyun.com/api/query.json?action=DataQueryAction&eventSubmitDoQueryData=1" 200 583 "https://arms.console.aliyun.com/" "127.0.0.1:8080" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4" "0.148" "0.148" "EX866MB1-Y70JO57WM37ST3HWDVFK3-JWPNH30J-Z"

完成上述日志配置定制以后,即可开始在 ARMS 上进行配置。以下篇幅从 ARMS 数据集,报警,和交互大盘,三个部分进行配置概要描述。关于数据源如何添加到ARMS可参见文档,在此不赘述。

2. 基于 ARMS 的 Nginx 监控 数据集实现

在 Nginx 监控模板中,用户数据分为两类,一类是指标,相当于数据仓库中的 Measure;一类是维度,相当于数据仓库中的 Dimension。

对于Nginx监控,最常见的指标为以下几类指标:

页面的 PV, UV

  • PV: 页面的 PV 通过对 access.log 中的每一条日志做 coun t来统计,

  • UV: 通过日志中代表用户 ID 的对应的 $cookie_id 来做 count distinct 来统计。对应的 cookie_id 需要开发人员进行手动统计。

页面响应时间

  • 平均页面响应时间: 在 ARMS 中通过对$request_time做sum操作来统计出total_request_time,然后在通国际 total_request_time / pv 来得到某维度下的瓶平均响应时间。

  • 最大响应时间: 则对单条日志 request_time 进行 max 统计。

页面流量

  • 平均页面流量和最大页面流量:针对 $body_bytes_sent 来进行统计。统计方式和页面响应时间类似,不赘述。

对于 Nginx 监控,最常见的维度有以下几类:

  • 页面 URL: $request。用户可以针对特定 URL 进行访问统计,甚至可以在不同 URL 之间进行访问排行。

  • 页面返回状态:$status。用户可以针对不同的返回值维度进行统计,如仅统计 200 返回值的正常页面访问情况,或是非 200 返回值的错误页面访问情况。

  • 浏览器类型:根据 $http_user_agent 统计出的用户的浏览器客户端,如 Chrome, Sofari, IE, Firefox, 甚至 Curl 命令,等。用户可以根据此类维度统计客户端的分布情况。

  • 用户 ID:根据 $cook_id 统计出的用户的使用习惯,如哪一类页面被哪一些用户经常访问,等。

对于 ARMS 的数据集设计,其实就是针对用户感兴趣的 Nginx 监控结果,进行各类维度的排列组合。

  • 例如,以页面URL维度,统计 UV, PV,页面响应时间,则可以统计出不同页面的各自的UV, PV和页面响应时间,甚至根据例如PV进行TopN排行。

下图是一个数据集配置的例子,该数据集配置出两个维度: URL 和 Status (支持由 URL 下钻到 Status 的查询方式),分别统计两个指标:PV 和 UV。这样用户可以依次下钻页面路径和返回值来查询 PV, UV 情况。

下图是另个数据集配置的例子,该数据集配置出和上例相同但是顺序相反的两个维度: Status 和 URL (支持由 Status下钻到 URL 的查询方式),分别统计两个指标:PV,平均响应时间,最高响应时间 。其中,平均调用时间是复合指标,由总体调用时间 / PV 间接得出。

3. 基于 ARMS 的 Nginx 监控报警实现

常见的 Nginx 报警有以下几种:

  • 某类页面的响应时间过长。

  • 某类页面的错误率页面过高。
    使用 ARMS 的原生报警的一些特性天然支持 Nginx 监控报警的各种场景。以下举例。

  • 支持某类指标的维度下钻遍历
    例如检查(遍历)所有页面维度的响应时间是否超过 100ms.

  • 支持不同指标之间的复合计算
    典型如错误码为 5xx 占总调用的占比,通过不同指标复合计算而得。

  • 支持各种其他报警高级报警配置
    包括最近 N 分钟同比,环比,最大,最小值比较,等。例如,最近5分钟同比PV下跌50%这种典型的场景。

以下例子结合以上三个特点,介绍了一种如何在 ARMS 定义”任意 URL 调用一分钟 500 返回占比超过 10%”的报警定义例子,如下所示。

4. 基于 ARMS 的 Nginx 监控大盘配置

监控大盘一般有以下几个用途:

  • 挂在作战室,全面掌控运行状态。

  • 用于实时查看,并下钻分析每个具体用户或网页的网站实际使用情况。

针对 Nginx 监控,ARMS 可以基于类似用户维度,页面维度,IP 维度,甚至地域维度,展示不同的数据。以展示用户总体UV,  V 为例,假设对应的数据集为”整站 UV PV”,则配置如下:

集成各类 UV, PV,响应时间等统计的最终交互式大盘效果图如下:

5. 马上快速上手

以上各类 Nginx 监控场景,目前在 ARMS 上已有成熟商业模板支持,用户只需要在 ARMS 首页点击 “新建标准模板监控”,并选择 Nginx 高级模板,即可。


建议继续学习

  1. Mysql监控指南 (阅读 21,102)
  2. 批量添加主机到cacti+nagios的监控报警系统中 (阅读 14,683)
  3. 我常用的主机监控shell脚本 (阅读 13,104)
  4. 7 天打造前端性能监控系统 (阅读 11,063)
  5. 如何监控HP服务器硬件状态 (阅读 10,505)
  6. Cacti 添加 Nginx 监控 (阅读 10,363)
  7. Linux下三种常用的流量监控软件对比 (阅读 9,984)
  8. Cacti 添加 Memcached 监控 (阅读 9,162)
  9. Cacti 添加 Apache 监控 (阅读 8,984)
  10. 你应该知道的16个Linux服务器监控命令 (阅读 8,408)