一、优化方向

1,性能指标

  从应用负载的视角出发,考虑“吞吐”和“延时”

  从系统资源的视角出发,考虑资源使用率、饱和度等

  

2,性能优化步骤

  • 选择指标评估应用程序和系统的性能;
  • 为应用程序和系统设置性能目标;
  • 进行性能基准测试;
  • 性能分析定位瓶颈;
  • 优化系统和应用程序;
  • 性能监控和告警。

3,Linux性能工具图谱

二、平均负载

1,stress

安装命令:apt install stress
  stress 是一个linux系统压力测试工具,这里我们用作异常进程模拟平均负载升高场景
#模拟一个CPU使用率 100%  stress -c N 会让stress生成N个工作进程进行开方运算,以此对CPU产生负载。
stress --cpu 1 --timeout 600
#模拟I/O密集进程 stress -i N  会产生N个进程,每个进程反复调用sync()将内存上的内容写到硬盘上, --timeout 600 表示600秒后退出 stress -i 1 --timeout 600

2,sysstat

安装命令:apt install sysstat
sysstat 是一个常用的linux性能工具,用来监控和分析系统的性能。
  • mpstat 是一个常用的多核cpu性能分析工具,用来实时查看每个CPU的性能指标,以及所有CPU的平均指标
  • mpstat -P ALL 5
    其中-P ALL 表示监控所有CPU
    数字5,表示每间隔5秒输出一组数据
  • pidstat 是一个常用的进程性能分析工具,用来实时查看进程的CPU、内存、IO以及上下文切换等性能指标
  • pidstat -u 5 1
    每间隔5秒输出一组数据

3,场景模拟

a>CPU密集

  stress

#模拟一个CPU使用率 100%  stress -c N 会让stress生成N个工作进程进行开方运算,以此对CPU产生负载。--timeout 600 表示600秒后退出
stress --cpu 1 --timeout 600

  监控uptime,负载在升高

  mpstat,发现一个CPU的使用率高达100%,但是iowait为0,说明平均负载的升高由于CPU的使用率为100%

  pidstat,发现是stress进程导致CPU使用率升高

b>I/O密集

  stress

#模拟I/O密集进程  stress -i N  会产生N个进程,每个进程反复调用sync()将内存上的内容写到硬盘上
stress -i 1 --timeout 600

  监控uptime,负载在升高

  mpstat,发现一个系统CPU使用率升至23.87%,iowait高达67.53% 。说明平均负载的升高由于iowait的升高

  pidstat,发现是由于stress进程导致

c>大量进程的场景

  stress

stress -c 8 --timeout 600

  uptime

  pidstat,发现8个进程在争抢2个CPU,每个进程等待CPU的时间高达75%,导致CPU过载

三、CPU的上下文切换

1,基本概念

  CPU寄存器:CPU内置的容量小、但速度极快的内存

  程序计数器:用于存储CPU正在执行的指令位置、或者即将执行的下一条指令位置

  CPU上下文:CPU寄存器和程序计数器所必须的依赖环境

  CPU上下文切换:先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

2,分类

a>进程上下文切换

  Linux按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应CPU特权等级的 Ring 0 和Ring 3

  • 内核空间(Ring 0)具有最高权限,可以直接访问所有资源
  • 用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入内核中,才能访问这些特权资源

  

  换个角度,也就是进程既可以在用户空间运行,又可以在内核空间运行。进程在用户空间运行时,被称为进程的用户态,而陷入内核空间的时候,被称为进程的内核态。

  在进程切换时才需要切换上下文,也就是进程调度时。Linux为每个CPU都维护了一个就绪队列,将活跃进程按照优先级和等待CPU的时间排序,然后选择最需要CPU的进程,也就是优先级最高和等待CPU时间最长的进程运行。涉及到的场景包括:

  • 为了保证所有进程可以得到公平调度,CPU时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其他正在等待CPU的进程运行
  • 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并有系统调度其他进程运行
  • 当进程通过睡眠函数sleep这样的方法将自己主动挂起时,自然也会重新调度
  • 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行
  • 当发生硬件中断时,CPU上的进程会被中断挂起,转而执行内核中的中断服务进程

b>线程上下文切换

  线程是调度的基本单位,而进程则是资源拥有的基本单位

  • 当进程只有一个线程时,可以认为进程就等于线程
  • 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时不需要修改
  • 线程也有自己的私有数据,比如栈和寄存器,这些在上下文切换时也需要保存

  线程上下文切换:1,前后两个线程属于不同进程,由于资源不同就是进程上下文切换;2,前后两个线程属于同一个进程,此时虚拟内存共享,切换时只需要切换线程的私有数据、寄存器等不共享的数据。

c>中断上下文切换

  • 为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存起来,这样在中断结束后,进程仍然可以从原来的状态恢复运行
  • 与进程上下文切换不同,中断上下文切换并不涉及进程的用户态。所以,即便中断过程打断了一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。中断上下文,其实只包括内核态中断服务程序执行所必需的状态,包括CPU寄存器、内核堆栈、硬件中断参数等

3,CPU上下文切换实战

a>vmstat

  

  • cs(context switch)是每秒上下文切换的次数
  • in(interrupt)是每秒中断的次数
  • r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待的CPU的进程数‘
  • b(Blocked)是处于不可中断睡眠状态的进程数

b>pidstat

  vmstat只给出了系统总体的上下文切换情况,要想查看每个进程的详细情况,就需要使用我们pidstat。加上-w选项,则可以查看每个进程上下文切换的情况

  

  • cswch(voluntary context switches),每秒自愿上下文切换次数。指进程无法获取所需要资源,导致的上下文切换。比如:I/O、内存等系统资源不足时,就会发生自愿上下文切换。
  • nvcswch(non voluntary context switches),每秒非自愿上下文切换。指进程由于时间片已到等原因,被系统强制调度,进程发生的上下文切换。比如:大量进程都在争抢CPU时,就容易发生非自愿上下文切换。

c>案例实操

  查看系统的上下文切换次数 

 

  采用sysbench进行压测

  

  再次查看vmstat

  

  发现cs列的上下文切换数量从之前的35骤然上升到了139万多。同时,r列:就绪队列的长度为8,远超CPU的个数2,所以判定有大量的CPU竞争;us(user)和sy(system)列:这两列的CPU使用率加起来上升到了100%,其中系统CPU使用率,也就是sy列高达84%,说明CPU主要是被内核占用了;in列:中断次数也上升到1万左右,说明中断处理也是个潜在的问题。综合这几个指标,系统的就绪队列过长,也就是正在运行和等待CPU的进程数过多,导致大量的上下文切换,而上下文切换又导致系统的CPU的占用率升高。

  采用pidstat分析

  

  

  • CPU使用率升高果然是sysbench导致的,已达100%
  • 非自愿上下文切换最高的为pidstat,自愿上下文切换频率最高的线程为kworker和sshd
  • 问题:pidstat输出的上线文切换明显小于vmstat输出的上下文切换。采用man pidstat 发现,pidstat默认显示进程的指标数据,加上-t参数后,才会输出线程指标

  

  结合两次的pidstat可以看出,sysbench(主线程)的上下文切换次数看起来并不太多,但它的子线程的上下文切换次数却很多。

  采用watch观察interrupts中断

  

  观察发现,变化速度最快的是重调度中断(RES),表示唤醒空闲状态的CPU来调度新的任务运行。这是多处理器系统(SMP)中,调度器用来分散任务到不同CPU的机制,通常也被称为处理器间中断(Inter-Processor Interrupts, IPI)。

d>总结

  如果系统的上下文切换次数比较稳定,那么从数百到一万内,都应该算是正常的。当上下文切换次数超过一万次,或者切换次数出现数量级的增长时,都很可能已经出现了性能问题:

  • 自愿上下文切换变多,说明进程都在等待资源,有可能发生了I/O等其他问题
  • 非自愿上下文切换变多,说明进程都在被强制调度,也就是都在争抢CPU,说明CPU的确成了瓶颈
  • 中断次数变多了,说明CPU被中断处理程序占用,需要查看/proc/interrupts文件来分析具体的中断类型

Linux性能优化实战(一)的更多相关文章

  1. Linux性能优化实战学习笔记:第四十五讲

    一.上节回顾 专栏更新至今,四大基础模块的最后一个模块——网络篇,我们就已经学完了.很开心你还没有掉队,仍然在积极学习思考和实践操作,热情地留言和互动.还有不少同学分享了在实际生产环境中,碰到各种性能 ...

  2. 《Linux 性能优化实战—倪朋飞 》学习笔记 CPU 篇

    平均负载 指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,即平均活跃进程数 可运行状态:正在使用CPU或者正在等待CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态 (Run ...

  3. Linux性能优化实战学习笔记:第三十一讲

    一.上节回顾 上一节,我们一起回顾了常见的文件系统和磁盘 I/O 性能指标,梳理了核心的 I/O 性能观测工具,最后还总结了快速分析 I/O 性能问题的思路. 虽然 I/O 的性能指标很多,相应的性能 ...

  4. Linux性能优化实战学习笔记:第三十二讲

    一.上节总结 专栏更新至今,四大基础模块的第三个模块——文件系统和磁盘 I/O 篇,我们就已经学完了.很开心你还没有掉队,仍然在积极学习思考和实践操作,并且热情地留言与讨论. 今天是性能优化的第四期. ...

  5. Linux性能优化实战学习笔记:第三十六讲

    一.上节总结回顾 上一节,我们回顾了经典的 C10K 和 C1000K 问题.简单回顾一下,C10K 是指如何单机同时处理 1 万个请求(并发连接 1 万)的问题,而 C1000K 则是单机支持处理 ...

  6. Linux性能优化实战学习笔记:第四十三讲

    一.上节回顾 上一节,我们了解了 NAT(网络地址转换)的原理,学会了如何排查 NAT 带来的性能问题,最后还总结了 NAT 性能优化的基本思路.我先带你简单回顾一下. NAT 基于 Linux 内核 ...

  7. Linux性能优化实战学习笔记:第四十四讲

    一.上节回顾 上一节,我们学了网络性能优化的几个思路,我先带你简单复习一下. 在优化网络的性能时,你可以结合 Linux 系统的网络协议栈和网络收发流程,然后从应用程序.套接字.传输层.网络层再到链路 ...

  8. Linux性能优化实战学习笔记:第五十二讲

    一.上节回顾 上一节,我们一起学习了怎么使用动态追踪来观察应用程序和内核的行为.先简单来回顾一下.所谓动态追踪,就是在系统或者应用程序还在正常运行的时候,通过内核中提供的探针,来动态追踪它们的行为,从 ...

  9. Linux性能优化实战学习笔记:第五十五讲

    一.上节回顾 上一节,我们一起学习了,应用程序监控的基本思路,先简单回顾一下.应用程序的监控,可以分为指标监控和日志监控两大块. 指标监控,主要是对一定时间段内的性能指标进行测量,然后再通过时间序列的 ...

随机推荐

  1. 云南农职《JavaScript交互式网页设计》 综合机试试卷②——实现轮播图效果

    一.语言和环境 实现语言:HTML,CSS,JavaScript,JQuery. 开发环境:HBuilder. 二.题目(100分): 使用JQuery淡入淡出动画,实现轮播图效果 每隔2秒钟切换一张 ...

  2. Java面向对象程序设计作业目录(作业笔记)

    持续更新中............. 我的大学笔记>>> 第1章 面向对象 >>> 1.1.5 编写Java程序,创建Dota游戏中的防御塔类,通过两个坐属性显示防 ...

  3. mongodb Windows系统下安装卡死问题

    1.操作环境 MongoBD版本:mongodb-win32-x86_64-2008plus-ssl-4.0.5-signed (4.0.5) 操作系统:Windows 2008 R2_64位 (服务 ...

  4. Docker | dockerfile 文件编写

    dockerfile 的作用 dockerfile 作用就是制作镜像,保持开发,测试,生产环境的一致性. 直接将容器制作为镜像 制作新的镜像 # 把容器按照自己的需求个性完之后,就可以创建自己的镜像的 ...

  5. Java中List与数组互相转换

    1.说明 在Java中,经常遇到需要List与数组互相转换的场景. List转换成数组,可以使用List的toArray()或者toArray(T[] a)方法. 数组转换成List,可以使用Arra ...

  6. Kafka基础教程(二):Kafka安装

    因为kafka是基于Zookeeper的,而Zookeeper一般都是一个分布式的集群,尽管kafka有自带Zookeeper,但是一般不使用自带的,都是使用外部安装的,所以首先我们需要安装Zooke ...

  7. 使用.NET 6开发TodoList应用(19)——处理OPTION和HEAD请求

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在HTTP请求中,我们还剩下两类不常使用的请求没有讲到,本文就来实现以下关于OPTIONS和HEAD请求.OPTIONS请求用 ...

  8. golang mongodb 驱动二次封装

    mongodb 官方的go驱动包 go.mongodb.org/mongo-driver 使用起来比较繁琐,最近对其进行了二次封装 github地址:https://github.com/w3liu/ ...

  9. Flask_Flask-Script脚本扩展的使用(八)

    Flask-Script扩展包提供向Flask插入外部脚本的功能,包括运行一个开发用的服务器,一个定制的Python shell,设置数据库的脚本,cronjobs,及其他运行在web应用之外的命令行 ...

  10. Centos7 安装 brctl 工具

    [root@docker-node1 ~]# brctl show -bash: brctl: command not found [root@docker-node1 ~]# yum -y inst ...