1. 端上访问
1.1. APP
- 崩溃率:崩溃指的是应用在运行过程中出现强制关闭的现象。崩溃会打断了用户操作的体验,造成业务中断。崩溃率过高还会导致用户的留存率下降,品牌口碑变差,等等。
- 卡顿率:App 中的卡顿率指的是 UI 刷新时出现卡顿的情况。如果卡顿率过高,会让用户感觉 App 运行很慢,降低用户的使用体验。
- 卸载率:卸载说明用户很难适应你的产品,卸载率可以算是最能检测用户在使用一个产品时是否满意的一个指标了。卸载率的升高可能是各个方面导致的,比如推送过多打扰到用户,有严重的 bug 影响到使用体验,等等。
1.2. 网页
- 白屏时间:指的是用户访问页面时,从用户输入地址栏之后到首次出现内容的时间,也叫作首次渲染时间。白屏时间的长短会影响用户的使用体验,白屏时间长会导致用户认为网站比较慢。如果出现较长时间的空白,有可能是服务器响应慢或是网络波动等原因造成的。
- 首屏时间:指的是用户输入地址栏之后到首个屏幕渲染完成,即完全显示了页面内容的时间。首屏时间会受资源下载速度影响,首屏渲染的速度越快,用户的使用体验也会更好。
1.3. 通用指标
端上的资源请求,一般都会经历以下几个步骤:DNS 寻找,建立与服务器的链接,发送请求,请求响应。这几个步骤是可以被监控起来。
- DNS 响应时间:通常用来记录访问地址向 DNS 服务器发起请求,到 DNS 返回服务器 IP 地址信息的时间。
- 建立连接时间:客户端通过 TCP 与服务器建立的时间。
- SSL 握手时间:SSL 握手指的是与 HTTPS 服务器端进行建立链接的整个过程,其耗时就是 SSL 握手时间。
- 首字节时间:从客户端发送请求,到接收服务器首个字节的时间。因此,它包含了服务器的响应耗时信息。
- 下载内容时间:接收到内容后,内容被完整下载完成的时间。
通用指标并不限于 App 或是网页。通过这些指标,你可以更加了解客户端从请求发起到接收完整内容的耗时情况。通用指标前 3 项(DNS 响应时间、建立连接时间、SSL 握手时间)是基础功能,在优化时更偏向运维层面;首字节时间和下载内容时间,则更多的是后端开发人员来优化。
2. 应用程序
2.1. 请求
请求指的是端上通过 HTTP 等方式发起的请求,与请求相关的指标有以下几个需要关注:
-
QPS:QPS 代表了请求数量,它是我们能最快了解这个系统使用情况的一个指标。
- 状态码:针对 HTTP(S) 的请求,一般会细化响应状态码的数量指标。
- 2xx:响应被正常处理。一般系统中会使用 JSON 来返回数据,而 JSON 可能会有不同的业务状态码,监控时可以依据具体的情况定制。
- 3xx:请求被重定向。如果出现了大量的重定向,一般就表明该网页存在一定的问题,而且也存在降低用户使用体验的风险。
- 4xx:无法访问,比如我们常见的 403 无权限、404 未找到。4xx 说明业务边界存在问题,可能会导致身份信息出现问题或者页面访问异常。
- 5xx:这个在后端比较常见,如果服务器内部出现了错误,通常也会伴随着访问出现错误。
- 请求时间:从服务器发起请求,到服务器返回数据内容的总计时间,一般也叫响应耗时。响应耗时可以帮助我们了解具体某个接口或者页面的执行情况。
- SLA:在 HTTP 请求层面,SLA 一般可以通过总共的请求数与 5xx 请求数之间的运算获得。
- 独立用户数:指的是总共有多少个用户访问。用户数越多,说明产品使用的人数越多,用户基数越大。通过查看独立用户数也可以发现一些问题,比如爬虫在爬取你的数据,就可能会导致 QPS 偏高,而用户数很少的情况。
2.2. 数据处理
数据处理和一些第三方框架的交互居多,在请求数据处理时,会涉及很多的内容,其中有以下几个比较关键的指标类型:
- RPC:如果系统之间存在 RPC 调用,就可以分别记录消费者和提供者的调用次数、成功率、耗时等信息。为什么要分别记录?以成功率来说,消费者一般会有超时设置。假设超时设置是 2 秒,提供者第 3 秒才返回数据,它认为自己成功了,但消费者可能早将其认定为超时。所以我们在统计数据时,消费者的成功率是更能提现执行情况的,提供者的数据则更多的是参考。
- 熔断限流降级:熔断/限流/降级的次数、阈值,其实也是一个很好的观测指标,我们可以通过这些指标,更清楚地了解阈值是否正确、触发后的处理是否正确,等等。
- 数据源:你的系统肯定会涉及各种各样的第三方数据源,比如最经常使用的 MySQL、ElasticSearch、MongoDB。在这里,我们会更加关注与这些系统交互时的执行耗时、调用频次。如果你在和数据库操作时,出现耗时较高的情况,就代表业务逻辑也出现了问题。
- 自定义业务指标:以上所介绍的这些固有指标早已不能满足我们对指标的要求,因此我们经常会自定义业务指标,以便能更细化地了解系统。更多是倾向于开发人员在编写代码时需要自定义控制的指标内容
2.3. 组件协作资源
我们的应用程序会和各种的第三方框架进行资源利用,对于它们的资源利用的效率,很大程度上决定了应用的执行效率。
- RPC:和数据处理中提到的 RPC 类似,组件协作资源中的 RPC 一样会涉及资源利用。以国内使用最多的 Dubbo 为例,Dubbo 的每一次发送请求和接收请求,都是利用线程池完成的。在使用 Dubbo 的时候,你可以通过监控线程池的资源信息掌握系统运行的状态,这其中的指标有总计的线程数、活跃线程数等。
- 数据库:业务系统与数据库之间的交互一般会有专门的 TCP 链接资源保持并处理,每个数据库都有各自的数据协议。因此,我们通常将链接池化,以提高资源使用效率,不浪费资源。并监控活跃数、闲置数和总共的资源数。当资源缺少时,我们需要注意,是否是配置不足导致的资源减少。
- 队列:对于异步和大量需要处理的任务,我们通常会使用队列,以起到削峰的作用。所以我们也会监控任务的发送量、处理量、Lag 值、处理耗时,确保不会出现大面积的延迟进而影响业务处理的情况。
- 缓存:缓存框架也经常会在系统中使用,正确使用它可以减少部分数据库查询的压力,从而提升我们接口的响应性能。在缓存中,我们通常会更加关注命中率、内存使用率、数据量等指标。尤其是命中率,命中率越高表明接口性能越高,而接口性能可以缩短响应耗时。
- 请求:系统经常会依赖于其他需要进行 HTTP 请求等方式的第三方服务,像微信的创建订单,就需要通过 HTTP 的请求,创建订单后再返回数据。在这里同样要监控其请求数、耗时情况等指标。虽然这是个常见的现象,但在与第三方服务通信的时候,我们一定要做好熔断降级策略,最好不要因为第三方服务的不稳定导致自己业务的主流程受到阻碍。
2.4. VM 监控
- GC:我们通常会收集 GC 的次数、每次 GC 时收集了多大的内存空间数据。
- 内存:内存可以分为年轻代、老年代、堆外、Meta 区这 4 个部分。如果老年代长期占有率较高,则有可能存在内存泄漏的问题。我们可以分别观测上面 4 个部分的当前值和最大值,来了解内存的使用量。
- CPU 占用率:这里指的是进程启动时 CPU 占用率,通过这个值我们可以看出这个应用是否会频繁地使用 CPU。出现问题时,如果 CPU 占用率居高不下,可能它并不是问题的根源,而仅仅是任务处理不过来。
- 类加载:程序启动后,一定会进行一定类的加载和卸载。监控当前总共的类加载和类卸载的数量,也是很好地观察问题的方式。如果持续出现大量的类被加载的情况,有可能是使用动态代码生成框架时出现了问题。大量的类被加载会不停地占用 Meta 区,最终导致堆溢出。
- 线程:线程数据也是必不可少的观察指标之一。程序代码都是运行在线程上的,如果当前活跃的线程数过多,会使 CPU 资源过高,最终因为资源占用问题,导致任务执行缓慢。我们一般会监控线程中的活跃线程数、总计线程数、等待线程数等指标。
3. 组件
组件在开发中是必不可少的内容,它们既是数据最终存储的位置,也是数据中转的地方。组件的好坏,很大程度决定了我们应用程序的好坏。
3.1. 数据库
- QPS:每秒查询次数。可以说每个数据库都会涉及查询请求。通过观测这个指标,我们可以很快了解到系统对数据库的查询量,以及是否需要优化查询语句。
- 查询耗时:查询耗时可以了解到系统的查询效率是否处于正常的区间,如果出现了“慢查询”现象,可以及时地处理,比如 MySQL 中可以通过增加索引来解决部分查询效率的问题,ElasticSearch 则需要筛选出查询慢的语句再逐个优化。
- TPS:每秒事务数。这里一般指的是对数据的添加/删除/修改操作的处理速度。TPS 不同于 QPS,它涉及修改数据,因为大多数的数据库在设计时的初衷都是以查询为主,所以 TPS 在处理时会花费更多的时间。
- 主从延迟数:主从的架构可以说是很多数据库都会有的一种集群方式,主从架构中有许多实现方式是基于从机器到主机器上同步数据的方式来完成的,比如 MySQL。所以同步时的主从延迟数是一个十分关键的指标。延迟数高说明业务系统在读取数据时,如果恰好读到了延迟比较高的数据节点,此时系统有可能出现错误。
- 连接数:如果业务系统与数据库的连接达到了一定的数量,则可能造成数据库处理缓慢。因此,资源的连接数也是一个很重要的指标,一般这个指标和这个数据库的最大连接数会有一个的对比,通过这个对比可以体现出这个数据库的资源分配是否均衡。
- 数据量:如果数据库中单个表的数据量大于某个数值,同样会出现性能问题,比如阿里巴巴在《Java 开发手册》中规定,单表超过 500 万条数据后就要分库分表处理。一个表的数据量过大会影响查询、插入的效率,这个规定同样适用于当下的很多数据库。
- VM 监控:某些组件是基于某些语言开发的,因此它们还会有相对应开发语言的指标监控,比如 ElasticSearch 基于 Java 开发,所以还要监控 JVM 的信息。
3.2. 队列
- Lag:目前待消费的数据量的大小。如果这个值持续增长并且过大,则说明消费者的能力已经不能够满足生产者的生产速度了。这时候一般会考虑减少生产者生产的内容,或者加快消费者速度,如果可以的话加机器来运行也不失是一个好的选择。
- 发送数量:生产者生产数据的内容大小。如果这个值增长的速度越快则代表生成内容的数量越多。如果值突然飙升得比较高,也应该注意,是否存在无用内容的发送。
- 消费数量:消费端消费生产者内容的数量。一般的队列中间件中都会有分区的概念,通过消费数量可以清楚看到每个分区的消费情况,如果出现了某个分区消费数量明显不足的情况,则需要针对某个分区的消费实例做特殊观察。
- 分区数:一般在 1 个 topic 中,我们会将数据分区来提高并行消费的速度,这个分区的数量就是分区数。分区数同样是一个很关键的概念,如果一个 topic 的分区数相对较少,说明可以交给消费者消费的线程数也不多。
3.3. 缓存
- 响应时间:说到缓存中的关键指标,首先就要说到响应时间。一般这个指标的值都很低,因为缓存大多数时候是存储在内存中的。如果这个值偏高,说明使用方或者缓存出现了问题,这时就需要从更细的维度跟踪问题的原因了。
- 缓存命中率:命中率其实就是请求中查询到数据的请求除请求总数,最终获得的百分比。百分比越高说明命中率越高,程序也会有更好的性能;如果命中率相对较低,则要考虑是否是写法出现了问题,或者是这个内容适不适合使用缓存。如果不适合的话可以考虑不用缓存,因为引入了一个新的组件,会增加运维和开发的成本。
- 网络延迟时间:对缓存来说,如果交互中出现了较高的延迟会影响到业务系统,因为缓存一般的调用频率都不低,如果延迟较高的话,会影响接口的性能,所以保证网络延迟低也是一个很关键因素。
- 已使用内存:缓存一般是存储在内存中的,所以对于内存的使用量有严格的要求,如果没有满足要求,缓存系统会执行淘汰策略,比如 LRU。执行淘汰策略之后可能会导致缓存命中率下降,而如果内存使用过高,缓存系统则被系统 kill。
- 资源链接:除了与数据库,业务系统还会与缓存系统有链接的情况,所以我们也需要监控它们的链接情况。我们常被用作缓存的 Redis,它其实也是一种 KV 类型的 NoSQL 数据库。
- 缓存数量:数据库中已有的缓存数量也是一个很好的指标。如果出现了使用内存达到配置阈值,导致缓存使用了一定的算法来淘汰缓存。通过缓存数量也可以清楚地看到我们系统中新增的缓存或是被移除缓存的数量对比,了解我们的系统是否是一直在有效地利用缓存提高性能。
3.4. 网关层
- 请求相关:在网关层你也需要关注 QPS、状态码、请求耗时等信息。网关层里往往会记录请求整体的执行情况。这里的数据肯定是最全、最准的。
- 错误数:如果网关层出现了错误请求信息,由于网关层是高于应用层的,所以应用层中的请求一般是由网关层转发,信息根本不会进入应用层。所以当在网关层出现错误数飙升的问题时,在应用层可能根本无法定位问题的原因。
- 请求处理:网关层有相关的请求处理机制,所以监控请求处理相关的数据也十分关键,比如总请求数、正处于“读”状态的请求数、正处于“写”状态的请求数、正在排队的请求数。如果出现大量的排队现象,则说明网关层已经处理不过来了,这时候一般可以通过增加网关机器来解决。
4. 机器信息
- CPU:CPU 的运行情况肯定是应用程序中最重要的。我们一般会比较关注 CPU 的整体使用率,然后再细分为系统侧、用户侧的使用率。同样,我们也会关注系统的 Load 情况,如果 Load 值越高说明系统承受的处理任务越多,系统执行也会更缓慢。
- 内存:内存的大小会影响程序的可使用内存空间,除了重内存使用程序。内存中我们也会关注内存的整体使用率,以及 swap 区的使用率。如果 swap 区的使用率较高,可以考虑将其关闭,通过升级内存来提高程序性能。
- 磁盘:在一般的应用程序中,磁盘更多的是用于日志记录和临时缓存文件记录。同 CPU 和内存一样,关注磁盘的使用率即可。
- 网络:网络情况可以说是现在应用中的重中之重,无论是链接组件还是微服务中的 RPC,到处都有服务器之间的通信。一般我们会更关注出/入流量,如果当到达网卡限制的大小后,则一般只能考虑扩容服务来解决,因为网卡的提升是有限的。在此之外,我们还会监控网络丢包率、连接错误数等信息,这些信息可以帮助我们的程序在网络出现问题时,判断是否是网卡的原因。
- I/O:在 Linux 平台中,任何的网络请求、消息或是其他内容都是基于文件来构成的,所以 I/O 在 Linux 中无处不在。我们会更关注 I/O 的文件读取/写入中的速度、耗时、次数等信息,这些都是最能直观体现出写入和读取速度的内容。同时我们还会关注使用率(util),如果磁盘的使用率过高,则说明应用对磁盘的使用量很大,很有可能会因为磁盘的问题而导致应用程序上的问题。
- 句柄:随着 I/O 的使用,我们也需要关注句柄的使用量。如果程序中出现了资源流未关闭的情况,则有可能会导致句柄数激增,最终导致句柄耗尽,影响程序执行。
CPU有几个重要的概念:上下文切换、运行队列和使用率。这也是我们CPU监控的几个重点指标。通常情况,每个处理器的运行队列不要高于3,CPU 利用率中用户态/内核态
比例维持在70/30,空闲状态维持在50%,上下文切换要根据系统繁忙程度来综合考量。针对CPU常用的工具有:Htop、Top、Vmstat、Mpstat、Dstat、Glances。
内存通常我们需要监控内存的使用率、SWAP使用率。针对内存常用的工具有:Free、Top、Vmstat、Glances。
IO分为磁盘IO和网络IO。除了在做性能调优我们要监控更详细的数据外,日常监控只关注磁盘使用率、磁盘吞吐量、磁盘写入繁忙程度,网络也是监控网卡流量即可。常用工具有:Iostat、iotop、df、iftop、SAR、Glances。
TCP监控:在很多情况下有必要监控TCP的状态,可以使用netstat或者ss来获取所有的TCP连接,来展现11种不同的TCP连接状态的数量,可以在大并发中及时发现TCP的相关故障。
5. 参考资料
《分布式链路追踪实战 》