跑步(1/1)
学习lambda stream(mapToObj, flatMap, groupingBy, patitionBy)、定位生产问题等。(下班回家倒头就睡,可能是气温骤降的缘故,困乏无力……)
一、做好监控
主机层面,对 CPU、内存、磁盘、网络等资源做监控。如果应用部署在虚拟机或 Kubernetes 集群中,那么除了对物理机做基础资源监控外,还要对虚拟机或 Pod 做同样的监控。监控层数取决于应用的部署方案,有一层 OS 就要做一层监控。
网络层面,需要监控专线带宽、交换机基本情况、网络延迟。
中间件和存储层面,都要做好监控,不仅仅是监控进程对 CPU、内存、磁盘 IO、网络使用的基本指标,更重要的是监控组件内部的一些重要指标。比如,著名的监控工具 Prometheus,就提供了大量的exporter来对接各种中间件和存储系统。
应用层面,需要监控 JVM 进程的类加载、内存、GC、线程等常见指标(比如使用Micrometer来做应用监控),此外还要确保能够收集、保存应用日志、GC 日志。通过 JVM 监控 GC 相关指标。
二、从多个方面使用工具排查问题
CPU,可以使用 top、vmstat、pidstat、ps 等工具排查;
内存,可以使用 top、ps、vmstat、cachestat、free 等工具排查;
IO,可以使用 lsof、iostat、pidstat、sar、iotop、df、du 等工具排查;
网络,可以使用 ifconfig、ip、nslookup、dig、ping、tcpdump、iptables 等工具排查。
三、分析问题排查问题
第一,考虑通过分类寻找规律。
第二,分析问题需要根据调用拓扑来,不能想当然。比如,我们看到 Nginx 返回 502 错误,一般可以认为是下游服务的问题导致网关无法完成请求转发。对于下游服务,不能想当然就认为是我们的 Java 程序,比如在拓扑上可能 Nginx 代理的是 Kubernetes 的 Traefik Ingress,链路是 Nginx->Traefik-> 应用,如果一味排查 Java 程序的健康情况,那么始终不会找到根因。
第三,考虑资源限制类问题。观察各种曲线指标,如果发现曲线慢慢上升然后稳定在一个水平线上,那么一般就是资源达到了限制或瓶颈。比如,在观察网络带宽曲线的时候,如果发现带宽上升到 120MB 左右不动了,那么很可能就是打满了 1GB 的网卡或传输带宽。又比如,观察到数据库活跃连接数上升到 10 个就不动了,那么很可能是连接池打满了。观察监控一旦看到任何这样的曲线,都要引起重视。
第四,考虑资源相互影响。CPU、内存、IO 和网络,这四类资源就像人的五脏六腑,是相辅相成的,一个资源出现了明显的瓶颈,很可能会引起其他资源的连锁反应。比如,内存泄露后对象无法回收会造成大量 Full GC,此时 CPU 会大量消耗在 GC 上从而引起 CPU 使用增加。又比如,我们经常会把数据缓存在内存队列中进行异步 IO 处理,网络或磁盘出现问题时,就很可能会引起内存的暴涨。因此,出问题的时候,我们要考虑到这一点,以避免误判。
第五,排查网络问题要考虑三个方面,到底是客户端问题,还是服务端问题,还是传输问题。比如,出现数据库访问慢的现象,可能是客户端的原因,连接池不够导致连接获取慢、GC 停顿、CPU 占满等;也可能是传输环节的问题,包括光纤、防火墙、路由表设置等问题;也可能是真正的服务端问题,需要逐一排查来进行区分。
第六,如果因为监控缺失等原因无法定位到根因的话,相同问题就有再出现的风险,需要做好三项工作:做好日志、监控和快照补漏工作,下次遇到问题时可以定位根因;针对问题的症状做好实时报警(告警系统),确保出现问题后可以第一时间发现;考虑做一套热备的方案,出现问题后可以第一时间切换到热备系统快速解决问题,同时又可以保留老系统的现场。