赞
踩
海恩法则:每一起严重事故背后,必然有29次轻微事故和300起未遂先兆及1000起事故隐患
墨菲定律:如果有两种或两种以上方式去做某件事情,而选择其中一种方式将导致灾难,则必定有人会做出这种选择。
对问题要彻查,不能因为问题的现象不明显而忽略。
在生产环境发生故障时快速恢复服务,避免或减少故障造成的损失,避免或减少故障对客户的影响。
6个阶段:发现问题,定位问题,解决问题,消除问题,回顾问题,避免措施。
总体目标:尽快恢复问题,消除影响。
1.发现问题
通常通过自动化的监控和报警系统来实现,
通常会对系统层面,应用层面和数据库层面进行监控。
2.定位问题
考虑问题:
3.解决问题
每个系统会对各种严重情况设计止损和降级开关,在发生严重问题时先使用止损策略,恢复问题后再定位和解决问题
清晰定位问题根本原因,提出解决问题的有效方案。
4.消除影响
5.回顾问题
回顾事故产生原因,应急过程合理性,提出整改措施,聚焦于以下问题
6.避免措施
建立改进措施和避免措施跟进方案和机制
技术攻关目标是解决问题
考虑when 什么时候的问题,what什么问题,who谁发现的,影响了谁,where 哪里出现的问题,哪里没有出现,why为什么出现问题
根据答案判断那个系统的问题,并从这个系统入手,查日志,查数据,并结合代码定位问题根源。
最小化复现指在个人开发环境内通过模拟生产环境来重视生产环境产生的问题。最小化复现环境必须是问题产生时所涉及的组件的最小化集合,不需要包含所有组件。
定位问题后,给出最佳方案,给出选择原因。
方案需要在开发环境和QA环境下进行验证,验证能否能否解决问题,还要避免影响现有功能,需要做回归验证。
环境:
搭建原创发号器服务Vesta
查找Java进程内CPU利用率最高的线程,一般适用于服务器负载较高的场景,快速定位负载高的成因。
命令格式
用于在Jar包的包名和类名中查找某一关键字,并高亮显示匹配的包名,类名,和路径,多用于定位java.lang.NoClassDefFoundError 和 java.lang.ClassNotFoundException问题,以及类版本重复或者冲突的问题等。
命令格式
在Jar包中进行二进制内容查找,通常会解决线上出现的一些不可思议的问题,例如某些功能上线后没有生效,某些日志没有打印等,通常是上线工具或者上线过程出现的问题,可以把线上的二进制包拉下来并查找特定的关键字来定位问题。
命令格式
识别冲突的Jar包,可以在一个根目录下找到包含相同类的所有Jar包,并根据相同类的多少来判断Jar包的相似度,常用于
命令格式:
jar-conflict-detect 路径
利用Linux命令nc检查HTTP请求参数,请求头和请求体等信息,
命令格式:
http-spy
用于快速查看Mysql实例的负载情况,包括每秒查询数,每秒事物数,提交数,回滚数,连接线程数,执行线程数等
命令格式:
show-mysql-qps 用户名 密码
jad反编译工具可以将字节码的二进制类反编译为Java源代码,常常用于遇到问题但是无法在源代码中定位的场景,通过反编译字节码,可以分析程序的实际执行流程,从而定位深层次的问题。
界面版jd-gui
命令:jad AbstractIdServiceImpl.class
无法根据已有日志定位问题,需要更多的信息如参数,返回值等。btrace可以动态地跟踪Java运行时程序,将定制化的跟踪字节码切面注入运行类中,对运行代码无侵入,对性能的影响也可忽略不计。
命令格式:
btrace [-p port] [-cp classpath] pid btrace-script
运行命令前,需编写btrace的跟踪脚本:
@BTrace
public class Btrace{
@OnMethod(
clazz = "com.cloudate.controller.AdminController",
method = "sayHello",
location = "@Location(Kind.RETURN)"
)
public static void sayHello(@Duration long duration){//单位是ns,要转为ms
println(strcat("duration(ms):",str(duration/1000000)));
}
}
这个跟踪脚本对业务代码的方法进行了拦截,并打印方法的执行时间
package com.cloudate.controller;
public class AdminController{
public String sayHello(String name, int age){
return "hello everyone";
}
}
示例:
btrace -p 2020 -cp ~/servlet-api.jar 1507 ~/BTrace.java
JDK 自带的监控工具,用来查看Java进程对内存的使用情况
按照占用空间大小打印程序中类的列表,可以分析哪些类占用了比较多的内存。
按照占用空间的大小打印程序中加载的动态链接库的列表。此命令可以帮助定位Java进程占用内存较大或者底层动态链接库占用内存较大的问题,在定位Java进程导致的内存泄露场景中有很重要的作用。
Java堆的内存结构很复杂,包括新生代,老年代,持久代,直接内存等。通过jmap命令可以查看堆的概要信息。
需对Java堆的内部结构进行剖析才能进一步分析产生问题的根本原因,通过jmap命令导出Java堆的快照,然后通过其他工具甚至可视化内存分析工具等详细分析
JDK自带的监控工具。利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行监控,包括对堆大小和垃圾回收状况的监控等。更倾向于输出累积的信息与打印GC等的统计信息等。
示例:jstat -gcutil 2743 5000 10
JDK自带命令,用于打印给定的Java进程ID 的线程堆栈快照信息,从而可以看到Java进行内线程的执行状态,正在执行的任务等,可以据此分析线程等待,死锁等,
示例:jstack 2743
可以输出并修改运行时的Java进程的环境变量和虚拟机参数
示例:jinfo 38574
Java虚拟机图形界面分析工具
文本内容查找命令,可以利用它打印匹配的上下几行。在线上查找问题时,可以使用命令查找关键字,显示关键字所在行的前后多行,并给关键字着色。
grep -5 'parttern' INPUT_FILE #打印匹配行的前后5行
grep -C 5 'parttern' INPUT_FILE #打印匹配行的前后5行
grep -A 5 'parttern' INPUT_FILE #打印匹配行的后5行
grep -B 5 'parttern' INPUT_FILE #打印匹配行的前5行
grep -A 15 --color 1010061938 #查找后着色
通过文件名查找文件的所在位置,文件名查找支持模糊匹配。
find . -name FILE_NAME
查看机器的启动时间,登录用户,平均负载等情况,通常用于在线上应急或者技术攻关中确定操作系统的重启时间
uptime
当前时间,系统已运行的时间,当前在线用户,系统平均负载(最近1min,5min,15min)
系统平均负载指:在特定的时间间隔内队列中运行的平均进程数,如果一个进程满足以下条件,它就会位于运行队列中。
一般每个CPU内核对应的活动进程数不大于3,系统运行良好,即活动进程数小于CPU核心数的3倍。
eg:如果服务器的CPU有3核,那么uptime输出的一串字符数值小于9,就表示系统负载正常,但超过10,即负载过重,需定位系统执行负载超标原因。
用于列出系统当前打开的文件句柄,在linux文件系统中任何资源都是以文件句柄的形式进行管理的。对系统监控及应急排错提供重要的帮助
#查看某个进程打开的文件句柄
lsof -p 2862
#查看某个端口的使用方式
lsof -i 8080
显示当前的各种系统对用户使用资源的限制
linux系统对每个登录的用户都限制了最大进程数和打开的最大文件句柄数。
#显示当前的各种系统对用户使用资源的限制
ulimit a
#设置用户最大进程数
ulimit -u 1024
#设置用户可以打开的最大文件句柄数
ulimit -n 65530
使用Http调用时,查看返回的结果是否符合预期
curl -i "http://www.sina.com" #打印请求响应头信息
curl -v "http://www.sina.com" #打印更多的调试信息
curl -verbose "http://www.sina.com" #打印更多的调试信息
curl -d 'abc=def' "http://www.sina.com" #使用POST方法提交HTTP请求
curl -I "http://www.sina.com" #仅仅返回HTTP头
curl -sw '%{http_code}' "http://www.sina.com" #打印http响应码
文件传输命令,可以实现从本地到远程,从远程到本地的双向文件传输。
scp robert@1xx.1xx.x.x:/home/xx/xxx.txt .
scp ./xxx.txt robert@1xx.1xx.x.x:/home/robert/
文本编辑工具
用于转换Windows 和UNIX的换行符
dos2unix xxx.txt
unix2dos xxx.txt
强大的文本分析工具,在对数据分析并生成报告,把文件逐行读入,以空格为默认分隔符将每行切片,也可以以任何字符为分隔符,把切开的部分进行各种分析和处理。
用于显示系统内的所有进程
ps -elf
grep 找到目标进程
用于查看活动进程的CPU和内存信息,能够实时显示系统中各个进程的资源占用情况。
top
输出中可看到整体的CPU占用率,CPU负载,进程占用CPU和内存等资源情况。
用于监控全部或指定的进程占用系统资源的情况,包括CPU,内存,磁盘I/O,线程切换,线程数等数据
pidstat -urd -p 进程号
用于显示系统内存的使用情况,包括总体内存,已经使用的内存,
用于显示系统内核使用的缓存区,包括缓存和缓冲等
free
用来报告进程中各个模块占用内存的具体情况,显示比较底层的进程模块占用内存的信息,并可以打印内存的起止地址等。用于定位深层次JVM或者操作系统的内存问题
pmap -d 2862
显示关于内核线程,虚拟内存,磁盘I/O,陷阱和CPU占用率的统计信息
vmstat
用于实施监控系统CPU统计信息,这些信息放在/proc/stat文件中,在多核CPU系统里,不但能查看所有CPU平均使用信息,还能查看某个特定CPU信息
mpstat -P ALL
可以看到每个CPU核的占用率,I/O等待,软中断,硬中断等。
用于监控CPU占用率,平均负载值及I/O读写速度等.
命令输出包含
查看交换分区的使用情况
/sbin/swapon -s
用于查看文件系统的硬盘挂载点和空间使用情况
df -h
用于查看机器挂载的网卡情况
ifconfig -a
用于检测网络故障的常用命令,可以测试一台主机到另一台主机的网络是否连通
ping www.baidu.com
是TCP/IP 协议族的一员,是网络远程登录服务的标准协议,帮助用户在本地计算机上连接远程主机
telnet IP PORT
NetCat 可通过TCP/UDP传输数据,一款网络应用调试分析器,
Linux系统中的网络连通性测试工具,用来检测丢包率
mtr -r sina.com
检测网络中DNS服务器能否正确解析域名的工具命令,并且可以输出
nslookup sina.com
可以提供从用户的主机到互联网另一端的主机的路径,虽然每次数据包由同一出发点到达同一目的地的路径可能会不一样
traceroute sina.com
多功能监控工具,可以输出每秒网卡存取速度。
sar -n DEV 1 1
显示网络连接,端口信息等
根据进程查找端口
根据进程名查找进程ID
ps -elf | grep 进程
根据进程ID 查找进程开启的端口
netstat -nap | grep ID
根据端口查找进程
查找使用端口的进程号
netstat -nap | grep 端口号
根据进程ID查找进程的详细信息
ps -elf | grep 进程ID
实时监控网络流量的交互式的彩色文本屏幕界面,监控数据比较全面,可以输出TCP连接,网络接口,协议,端口,网络包大小等信息,但耗费的系统资源比较多且需要管理员权限
sudo ipstraf
网络状况分析和跟踪工具,可以用来抓包的实用命令。
#显示来源IP或者目的IP为xxx.xxx.x.xxx的网络通信
sudo tcpdump -i eth0 hostxxx.xxx.x.xxx
#显示来去往的所有FTP会话信息
sudo tcpdump -i eth1 'dst xxx.xxx.x.xxx and (port xx or xx)'
#显示去往xxx.xxx.x.xxx的所有http会话信息
sudo tcpdump -ni eth0 'dst xxx.xxx.x.xxx and tcp and port xxxx'
扫描某一主机打开的端口及端口提供的服务信息,通常用于查看本机有哪些端口对外提供服务,或者确定服务器有哪些端口对外开放。
nmap -v -A localhost
用于查看网卡的配置情况
ethtool 网卡名称
用来显示每个进程的本地调用栈,可以使用pstack来查看进程正在挂起的执行方法,也可以查看进程的本地线程堆栈,与JVM的jstack配合使用可以看到JVM线程运行的全部状况
pstack xxxx
系统调用工具,监控一个应用程序所使用的系统调用,通过它可以跟踪系统调用,并了解Linux程序是怎样工作的。
通过/proc文件系统查看运行时系统内核内的数据结构的能力,也可以改变系统内核的参数设置
#显示CPU信息
cat /proc/cpuinfo
#显示内存信息
cat /proc/meminfo
#显示详细的内存映射信息
cat /proc/zoneinfo
#显示磁盘映射信息
cat /proc/mounts
#显示CPU信息
cat /proc/loadavg
用于生成md5摘要,用于在文件上传和下载操作中校验内容的正确性,或者通过hmac做对称数据签名
md5sum xxx.txt
通过碰撞的方法被破解,用于文件上传和下载操作中校验正确性,或通过校验的sha256-hmac做对称数据签名
用于传输8字节码的编码方式之一,可以保证所输出的编码位全都是可读字符,base64制定了一个编码表,以便进行统一转换,变阿彪共有64个字符,被称为base64编码
产生OOM原因
两个异常与OOM有关系,但没有绝对关系
解决过程
1.产生问题
2. 解决问题
规律:晚上零点发生概率较大,偶尔其他时间发生,但都发生在整点
思考:整点是否有定时任务,有但时间不吻合。
问题本身:java.lang.OutOfMemoryError:unable to create new native thread
(1)内存计算
Java内存
从内存角度看,创建线程需要内存空间,os没有剩余内存分配给JVM进程,抛出OOM异常。
计算允许创建的最大线程数:
最大线程数=(操作系统最大可用内存 - JVM内存 - 操作系统预留内存)/线程栈大小
命令:free 内存,使用内存,剩余内存
eg:剩余内存700MB /1MB = 700 个线程
还有700 个线程可以创建,不是内存问题
(2)线程数对比
评估操作系统是否设置了应用创建线程的最大数量,并且达到了最大允许数量
命令:ulimit -a
显示当前的各种系统对用户使用资源的限制
max user processes (-u) 1024 ----- 机器允许使用的最大用户进程数为1024
命令:jstack 端口号 ---- 打印Java线程情况
命令:grep “Thread” js.log | wc -l
结果:904 ---- JVM一共创建了904个线程,但没达到最大限制1024
JVM本身可能会有一些管理线程存在,os内当前用户下可能也有守护线程在运行。
从操作系统角度统计线程数,
命令:pstack
命令:awk ‘{print $3}’ pthreads.log | grep app | wc -l
结果:1021 ------- 当前用户创建线程的线程数1021
接近了1204最大进程数
使用JVM的jstack命令,通过查看输出得知,每个线程都阻塞在打印日志的语句上,log4j中打印日志有锁,作用是让打印日志可以串行,保证日志在日志文件中的正确性和顺序性。
每日凌晨零点的日志切割导致磁盘I/O被占用,于是堵塞打印日志,日志阻塞时线程池阻塞,进而导致线程池被撑大,线程池线程数接近或超过1024就报错。
日志切割导致I/O增大分析
命令:vmstat查看I/O等待数据
问题发生时CPU I/O等待59%
脚本切割cat命令先把日志文件cat后,通过管道打印到另外一个文件,再清空原文件,一定会导致I/O增加。
平台服务化架构使用了两个服务化框架,一个是基于Dubbo,一个是点对点的RPC,用于在紧急情况下Dubbo出现问题,服务降级使用
每个服务都配置了点对点的RPC服务,并且独享一个线程池。
对Dubbo服务框架进行定制化时,设计了自动降级原则,如果Dubbo服务负载增加或者注册中心宕机,会自动切换到点对点的RPC框架(失效转移)。
一旦一部分服务切换到了点对点的RPC,而另一部分没有切换,会导致两个线程池都被撑满,超过1024
最小化重现问题
通过实践来验证产生问题原因
解决方法
偶尔发生没有规律
开始自建简单的调用链跟踪系统,通过应用层将日志推送到另一个类型运营后台的服务器上,由运营后台的服务器来收集整理日志,然后显示在运营后台的界面上
调用链跟踪系统设计
业务服务的发送逻辑,异步推送
伪代码:
public class AsyncEventSender<T>{
//默认设置的缓存事件的最大允许数量
private static final long MAX_BUFFER_SIZE = 10000000;
//使用并发的队列缓存消息
private ConcurrentLinkedQueue<T> bufferQueue = new ConcurrentLinkedQueue<T>();
//发送事件消息
public void sendEventAsync(T event){
//根据队列是否已满,判断是抛弃还是发送
if (bufferQueue.size() < MAX_BUFFER_SIZE){
bufferQueue.add(event);
}
}
}
问题:ConcurrentLinkedQueue 判断队列占用情况,判断抛弃还是发送
命令:jstack
结果:大部分线程工作在buffer.Queue.size()代码上
Concurrent 集合类使用分桶策略减少集合的线程竞争,在获取其整体大小时需要进行统计,而不是直接返回一个预先存储的值,时间复杂度O(n)
推送服务从缓存中提取事件并发送给运营后台,运营后台机器少,业务量有些峰值的时候,运营后台的机器负载就会攀升,导致瓶颈。另一个场景,运营后台部署时单机房,如果跨机房的网络抖动,导致推送服务延时,推送进程会被阻塞,导致缓存的数据积压过多,缓存数据量越大,size计算时间越长,导致CPU占用率100%
改进方案:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。