当前位置: 首页 > 科技观察

61秒搞定Linux健康状况!_0

时间:2023-03-18 22:50:19 科技观察

操作系统作为所有程序的载体,对应用程序的性能有着非常重要的影响。然而,计算机各个组件之间的速度非常不平衡。以CPU和硬盘的速度为例,兔子和乌龟的速度差距就更大了。下面将简要介绍CPU、内存、I/O的一些基本知识,以及一些评估它们性能的命令。1.CPU首先介绍计算机中最重要的计算部件:中央处理器。一般我们可以通过top命令来观察它的性能。1.1top命令top命令可以用来观察CPU的一些运行指标。如图,输入top命令后,按1键可以看到各个CPU核心的详细状态。CPU使用率有多个维度的指标,解释如下:us用户态占用CPU的百分比。sy内核模式占用的CPU百分比。如果这个值过高,需要配合vmstat命令查看上下文切换是否频繁。ni高优先级应用程序使用的CPU百分比。wa等待I/O设备使用的CPU百分比。如果这个值很高,可能是输入输出设备存在非常明显的瓶颈。hi硬件中断使用的CPU百分比。sisoftirqs占用的CPU百分比。st这通常发生在虚拟机上,指的是虚拟CPU等待实际CPU时间的百分比。如果此值太高,则您的主机可能处于压力之下。如果您是云主机,您的服务提供商可能超卖了。id空闲CPU百分比。一般我们更关注空闲CPU的百分比,它可以反映CPU整体的利用率。1.2什么是负载?我们还需要评估CPU任务执行的排队情况。这些值就是负载(load)。top命令显示CPU负载,即最近1分钟、5分钟和15分钟的值。如图,以单核操作系统为例,CPU资源被抽象成一条单向路。会出现三种情况:路上只有4辆车,车辆畅通无阻,载重0.5左右。路上有8辆车,他们可以安全地首尾相接。此时负载大约为1,路上有12辆车。除了路上的8辆车外,还有4辆车在路外等候,需要排队。此时负载约为1.5。1的负载代表什么?关于这个问题,还有很多误解。很多同学认为当负载达到1时,系统就会达到瓶颈,这是不完全正确的。load的值与cpu核数密切相关。举例如下:单核的负载达到1,总负载的值约为1。双核的每个核心的负载都达到1,总负载约为2。四核达到1,总负载4左右。所以,对于负载为10个但16个内核的机器,您的系统远远没有达到负载限制。通过uptime命令,还可以看到负载状态。1.3vmstat取决于CPU的繁忙程度,也可以使用vmstat命令。下面是vmstat命令的一些输出信息。我们比较关心以下几列:b等待队列中存在的内核线程数,比如等待I/O。如果数字太大,则CPU太忙。cs表示上下文切换的次数。如果进行频繁的上下文切换,则需要考虑线程数是否过多。si/so显示了交换分区的一些用法。swap分区对性能影响很大,需要特别注意。$vmstat1procs--------内存---------------swap-------io-----system--------cpu-----rbswpd免费buff缓存si所以biboincsussyidwast34002008897927370859182800056109613003200200889920737085918602828210401003200200890112737085918600000950121549910032003712737125918560048119002459990003273712737125918604844098100^C2.内存2.1观察命令要了解内存对性能的影响,就需要从操作系统层面来看内存的分布情况。我们通常在写完代码之后,比如C++程序,如果我们查看它的汇编,我们看到的是里面的内存地址,而不是实际的物理内存地址。那么应用程序使用的就是逻辑内存。学过计算机结构的同学都知道这一点。逻辑地址可以映射到物理内存和虚拟内存。例如,如果您的物理内存为8GB,并且您分配了一个16GB的SWAP分区,那么应用程序可用的总内存为24GB。从top命令中,您可以看到几列数据。注意方块包围的三个区域。解释如下:VIRT是虚拟内存,一般比较大,不用太在意。RES我们通常会关注这一列的值,它代表了进程实际占用的内存。通常在做监控的时候,主要是监控这个值。SHR指的是共享内存,比如一些可以复用的so文件。2.2CPU缓存由于CPU核心内存之间的速度差异非常大,解决方法是加缓存。事实上,这些缓存往往有多层,如下图所示。Java的大部分知识点都是围绕多线程展开的,因为如果一个线程的时间片跨越多个CPU,就会出现同步问题。在Java中,最典型的与CPU缓存相关的知识点就是并发编程中Cacheline的伪共享问题。伪共享是指在这些缓存中,以缓存行为单位进行存储。即使你修改了缓存行中的一小块数据,它也会被完全刷新。因此,当多个线程修改某些变量的值时,如果这些变量在同一个缓存行中,就会造成频繁刷新,无意间影响彼此的性能。可以通过以下命令查看当前操作系统的缓存行大小。cat/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size通过以下命令可以看到不同级别的缓存大小。[root@localhost~]#cat/sys/devices/system/cpu/cpu0/cache/index1/size32K[root@localhost~]#cat/sys/devices/system/cpu/cpu0/cache/index2/size256K[root@localhost~]#cat/sys/devices/system/cpu/cpu0/cache/index3/size20480K在JDK8以上的版本中,通过启用参数-XX:-RestrictContended,可以使用注解@sun.misc.Contended来补气,避免虚分享的问题。在并发优化中,我们会详细讲解。2.3HugePage回头看我们最长的一张图,上面有一个叫TLB的组件。虽然它的速度很高,但它的容量是有限的。这意味着如果物理内存很大,映射表中的条目就会很多,影响CPU的检索效率。默认内存以4K页为单位进行管理。如图所示,为了减少映射表中的条目,唯一的办法就是增加页面大小。像这样增加PageSize的技术就是HugePage。HugePage有一些副作用,比如增加竞争,Redis也有专门的研究(https://redis.io/topics/latency),但是在一些内存比较大的机器上,开启后会有一定的性能提升在。2.4预加载另外,一些程序的默认行为也会影响性能。比如JVM的-XX:+AlwaysPreTouch参数。默认情况下,虽然JVM配置了Xmx、Xms等参数,但它的内存只有在实际使用时才会分配。但是如果加上这个参数,JVM会在启动的时候预分配所有的内存。这样虽然启动速度慢了,但是runtime的性能会提高。3.I/O3.1观察命令I/O设备可能是计算机中最慢的组件。它不仅指硬盘驱动器,还包括所有外围设备。硬盘有多慢?我们不探究不同设备的实现细节,直接看其写入速度(数据未经过严格测试,仅供参考)。可见,普通磁盘的随机写入和顺序写入的区别是非常大的。但是,随机写入与CPU内存不在一个数量级。缓冲区仍然是解决速度差异的唯一工具。在断电等极端情况下,会产生太多的不确定性。这些缓冲区很容易丢失。最能反映I/O繁忙度的是top命令和vmstat命令中的wa%。如果您的应用程序写入大量日志,则I/O等待可能会非常高。对于硬盘,可以使用iostat命令查看具体的硬件使用情况。只要%util超过80%,你的系统就基本无法运行。具体如下:%util最重要的判断参数。一般来说,如果该参数为100%,则表示设备正在接近满负荷运行,Device表示它发生在哪个硬盘上。如果你快,会显示多行avgqu-sz这个值是请求队列的饱和度,也就是请求队列的平均长度。当然,队列长度越短越好。await响应时间应该小于5ms,如果大于10ms就比较大了。这个时间包括排队时间和服务时间svctm表示每个设备I/O操作的平均服务时间。如果svctm的值非常接近await,说明几乎没有I/O等待,磁盘性能非常好。如果await的值远高于svctm的值,说明I/O队列等待时间过长,系统运行应用程序会变慢。3.2零拷贝Kafka速度更快的一个原因是零拷贝的使用。所谓零拷贝,就是在操作数据时,不需要将数据缓冲区从一个内存区复制到另一个内存区。因为少了一份内存,所以提高了CPU的效率。我们来看看它们的区别:通过socket发送一个文件的内容,传统的方法需要经过以下几个步骤:将文件的内容复制到内核空间。将内核空间的内容复制到用户空间内存中,比如Java应用程序。用户空间将内容写入内核空间的缓存中。socket读取内核缓存中的内容并发送出去。零拷贝有多种方式,我们用sendfile来说明。如上图所示,有了内核的支持,零拷贝就少了一步,即内核缓存到用户空间的拷贝。即节省了内存,也节省了CPU调度时间,效率非常高。4、网络除了iotop和iostat命令外,sar命令也可以方便的查看网络运行状态。下面以一个简单的例子来描述入站流量和出站流量。$sar-nDEV1Linux3.13.0-49-generic(titanclusters-xxxxx)07/14/2015_x86_64_(32CPU)12:16:48AMIFACErxpck/stxpck/srxkB/stxkB/srxcmp/stxcmp/srxmcst/s%ifutil12:16:49AMeth018763.005032.0020686.42478.300.000.000.000.0012:16:49AMlo14.0014.001.361.360.000.000.000.0012:16:49AMdocker00.000.000.000.000.000.000.000.0012:16:49AMIFACErxpck/stxpck/srxkB/stxkB/srxcmp/stxcmp/srxmcst/s%ifutil12:16:50AMeth019763.005101.0021999.10482.560.000.00lo0.00AM:0.6:0501.6:01220.003.253.250.000.000.000.0012:16:50AMdocker00.000.000.000.000.000.000.000.00^C当然我们也可以选择性的只看TCP的一些状态。$sar-nTCP,ETCP1Linux3.13.0-49-generic(titanclusters-xxxxx)07/14/2015_x86_64_(32CPU)12:17:19AMactive/spassive/siseg/soseg/s12:17:20AM1.000.0010233.0018846.0012:17:19AMatmptf/sestres/sretrans/sisegerr/sorsts/s12:17:20AM0.000.000.000.000.0012:17:20AMactive/seg/passive/sissoseg/s12:17:21AM1.000.008359.006039.0012:17:20AMatmptf/sestres/sretrans/sisegerr/sorsts/s12:17:21AM0.000.000.000.000.00^C5.Enddon'不希望根据这些指标,能够立刻帮助我们定位性能问题。这些工具只能帮助我们粗略的猜测问题出在哪里,对于定位性能问题只是起辅助作用。要分析这些瓶颈,需要收集更多信息。如果想获得更多的性能数据,就得使用更专业的工具,比如基于eBPF的BCC工具。我们将在其他文章中扩展这些很棒的工具。阅读本文后,希望您能快速了解Linux的运行状况,对您的系统有更多的掌控。作者简介:品味小姐姐(xjjdog),一个不允许程序员走弯路的公众号。专注于基础架构和Linux。十年架构,每天百亿流量,与你探讨高并发世界,给你不一样的滋味。