目录
压测出现过什么问题?
线程等待时使用用户态程序,没有使用sleep空闲态,导致CPU idle过低
cpu.idle很低会出现什么问题?
什么是cpu.idle
cpu.idle指的是CPU处于空闲状态时间比例
CPU利用率主要分为用户态,系统态和空闲态,分别表示CPU处于用户态执行的时间,系统内核执行的时间,和空闲系统进程执行的时间,三者之和就是CPU的总时间
cpu.idle过低排查方式
- top 或者 jps 或者 ps -ef | grep java,假定我们找到的是java 进程 PID=9527
- 使用命令:top -H -p 9527,找到java进程中的线程情况
- 找到占用cpu较高的排名靠前的几个线程 PID 假如找到的耗CPU较高的线程 PID=95271
- 查看该线程的堆栈信息,使用命令:jstack -l 95271 或者 jstack -F 95271
- 分析堆栈的信息,进一步进行排查代码逻辑
为什么查看线程的栈信息可以看到当前程序的执行路径
假设程序调用C函数模块,先保存C函数的地址和变量,执行到C函数中的B函数时循环模块时执行时间过长,栈中一直保存以上信息,栈是先进后出的,执行到C中B函数时时间太长,则判定这段代码有问题。
CPU idle是如何统计的
假设两个进程,进程A在sleep()时,执行B进程,当两个进程都在sleep()时,则执行系统空闲任务,idle增加。
程序中执行i++这种类似程序时(用户逻辑),是用户态的,用户执行的时间增长(线程状态:运行态)
程序中执行read()这种类似的程序时(系统调用),是系统态的,系统内核执行时间增长(线程状态:运行态)
程序中执行sleep()这种类似的程序时(休眠动作,等待锁),是空闲态的,空闲系统进程执行时间增长(线程状态:阻塞态)
一个傻逼等待如下
delay()
{
for(i=0;i<10000000;i++);
for(i=0;i<10000000;i++);
for(i=0;i<10000000;i++);
for(i=0;i<10000000;i++);
for(i=0;i<10000000;i++);
for(i=0;i<10000000;i++);
for(i=0;i<10000000;i++);
for(i=0;i<10000000;i++);
for(i=0;i<10000000;i++);
}
}
main ()
{
for(j=0;i<10;j++) {
print(j);
delay();//一直在跑CPU,也能实现等待,但是idle是超低的,CPU负载大,不释放CPU
sleep(2);//释放CPU了,idle大
}
}
除了cpu.idle,还用什么衡量
cpu.load被定义为在特定时间间隔内运行队列中(在CPU上运行或者等待运行多少进程)的平均进程数
进程分为三种状态,一种是阻塞的进程blocked process,一种是可运行的进程runnable process,另外就是正在运行的进程running process
系统的load是指正在运行和准备好运行的进程的总数
如何评估cpu.load
如果cpu.load过大则表示有部分线程在等待获得cpu资源,过小表示cpu资源比较空闲。
对于cpu.load多少开始出现性能问题,外界有不同的说法,有的认为cpu.load/cores最好不要超过1,有的认为cpu.load/cores最好不要超过3,有的认为cpu.load不超过2*cores-2即可。
针对技术商服务进行压测时,发现load低时,接口TP999响应时间<50ms,而cpu.load/cores>4时,TP999响应时间约为200ms左右,多出来的时间可以理解为线程等待cpu处理的时间,可见cpu.load/cores过高时是影响接口响应时间的。
因此可以结合预期的接口响应时间,来定义每个服务的cpu.load/cores不超过多少。比如要求接口响应时间尽可能快的,最好确保cpu.load/cores不超过1,而对时间敏感性要求不太高时,一般要求cpu.load/cores不超过3。
说明:cores是几核,也就是几个CPU
如果load过大怎么处理
弹性扩容处理、手动扩容处理
什么是堆栈
堆是堆,栈是栈,堆是需要在程序执行时申请内存的(比如JAVA中new对象),并且内存在申请后不能自动释放的,JAVA中依靠GC清除废弃的内存的;
栈是程序执行时保存程序的执行路径的,包括函数地址,变量和函数的参数,栈是先进后出的,当前函数执行完毕,就把当前函数的变量等信息都弹出;所以栈时实时的去更新CPU的,不需要人为的清理
什么是垃圾回收机制GC
复制、标记清除、标记压缩
线程和进程的区别是什么?
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个