如何提高Linux下块usb此设备可提高性能IO的整体性能

用户名:join12
文章数:30
访问量:31450
注册日期:
阅读量:1297
阅读量:3317
阅读量:445497
阅读量:1131024
51CTO推荐博文
一、影响Linux服务器性能的因素分为:操作系统级和程序应用级:
1. 操作系统级
&&& 磁盘I/O带宽
&&& 网络I/O带宽
2. 程序应用级
&二、系统性能评估标准
&&& 影响性能因素
&&& 影响性能因素 && &评判标准
&&&&&&&&&&&&&&&& 好 && && & & & & & && 坏 && &&&&&&&&&&&&&&& 糟糕
&&& CPU && &user% + sys%& 70% && &user% + sys%= 85% && &user% + sys% &=90%
&&& 内存 && &Swap In(si)=0 Swap Out(so)=0 Per CPU with 10 page/s && &More Swap In & Swap Out
&&& 磁盘 && &iowait % & 20% && && iowait % =35% && & && iowait % &= 50%
&&& 其中:
&&&&&&&& %user:表示CPU处在用户模式下的时间百分比。
&&&&&&&& %sys:表示CPU处在系统模式下的时间百分比。
&&&&&&&& %iowait:表示CPU等待输入输出完成时间的百分比。
&&&&&&&& swap in:即si,表示虚拟内存的页导入,即从SWAP DISK交换到RAM
&&&&&&&& swap out:即so,表示虚拟内存的页导出,即从RAM交换到SWAP DISK。
三、系统性能分析工具
&&& 1.常用系统命令
&&&&&&&& Vmstat、sar、iostat、netstat、free、ps、top等
&&& 2.常用组合方式
&&&&&&&& o 用vmstat、sar、iostat检测是否是CPU瓶颈
&&&&&&&& o 用free、vmstat检测是否是内存瓶颈
&&&&&&&& o 用iostat检测是否是磁盘I/O瓶颈
&&&&&&&& o 用netstat检测是否是网络带宽瓶颈
四、Linux性能评估与优化
&&& 1. 系统整体性能评估(uptime命令)
&&&&&&& [root@server ~]# uptime
&&&&&&&& 16:38:00 up 118 days, 3:01, 5 users, load average: 1.22, 1.02, 0.91
&&&& 这里需要注意的是:load average这个输出值,这三个值的大小一般不能大于系统CPU个数*核心数*0.7,例如,本输出中系统有2个4核心CPU,如果load
average的三个值长期大于5.6时,说明CPU很繁忙,负载很高,可能会影响系统性能,但是偶尔大于5.6时,倒不用担心,一般不会影响系统性能。相反,如
果load average的输出值小于CPU的个数,则表示CPU还有空闲的时间片,比如本例中的输出,CPU是非常空闲的。
&&&& 2. CPU性能评估
&&&& (1)利用vmstat命令监控系统CPU
&&&&&&&& 该命令可以显示关于系统各种资源之间相关性能的简要信息,这里我们主要用它来看CPU一个负载情况。
&&&& 下面是vmstat命令在某个系统的输出结果:
&&&&&&& [root@node1 ~]# vmstat 2 3
&&&&&&&& procs &&&-memory&&&- &swap- &-io&- -system- &-cpu&&
&&&&&&&& r b swpd free buff cache si so bi bo in cs us sy id wa st
&&&&&&&& 0 0 0 4
&&&&&&&& 0 0 0 4
&&&&&&&& 0 0 0 4
&&&&&&& r列表示运行和等待cpu时间片的进程数,这个值如果长期大于系统CPU的个数,说明CPU不足,需要增加CPU。
&&&&&&&& b列表示在等待资源的进程数,比如正在等待I/O、或者内存交换等。
&&&&&&& us列显示了用户进程消耗的CPU 时间百分比。us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期大于50%,就需要考虑优化程序或算法。
&&&&&&&& sy列显示了内核进程消耗的CPU时间百分比。Sy的值较高时,说明内核消耗的CPU资源很多。
&&&&&&&& 根据经验,us+sy的参考值为80%,如果us+sy大于 80%说明可能存在CPU资源不足。
&&& (2)利用sar命令监控系统CPU
&&&&&&& sar功能很强大,可以对系统的每个方面进行单独的统计,但是使用sar命令会增加系统开销,不过这些开销是可以评估的,对系统的统计结果不会有很大影响。
&&&& 下面是sar命令对某个系统的CPU统计输出:
&&&&&&&& [root@webserver ~]# sar -u 3 5
&&&&&&&& Linux 2.6.9-42.ELsmp (webserver) 11/28/2008 _i686_ (8 CPU)
&&&&&&&& 11:41:24 AM CPU %user %nice %system %iowait %steal %idle
&&&&&&&& 11:41:27 AM all 0.88 0.00 0.29 0.00 0.00 98.83
&&&&&&&& 11:41:30 AM all 0.13 0.00 0.17 0.21 0.00 99.50
&&&&&&&& 11:41:33 AM all 0.04 0.00 0.04 0.00 0.00 99.92
&&&&&&&& 11:41:36 AM all 90.08 0.00 0.13 0.16 0.00 9.63
&&&&&&&& 11:41:39 AM all 0.38 0.00 0.17 0.04 0.00 99.41
&&&&&&&& Average: all 0.34 0.00 0.16 0.05 0.00 99.45
&&& 对上面每项的输出解释如下:
&&& %user列显示了用户进程消耗的CPU 时间百分比。
&&& %nice列显示了运行正常进程所消耗的CPU 时间百分比。
&&& %system列显示了系统进程消耗的CPU时间百分比。
&&& %iowait列显示了IO等待所占用的CPU时间百分比
&&& %steal列显示了在内存相对紧张的环境下pagein强制对不同的页面进行的steal操作 。
&&& %idle列显示了CPU处在空闲状态的时间百分比。
&&& 问题:
&&&&&&&& 1.你是否遇到过系统CPU整体利用率不高,而应用缓慢的现象?
在一个多CPU的系统中,如果程序使用了单线程,会出现这么一个现象,CPU的整体使用率不高,但是系统应用却响应缓慢,这可能是由于程序使用单线程的原
因,单线程只使用一个CPU,导致这个CPU占用率为100%,无法处理其它请求,而其它的CPU却闲置,这就导致了整体CPU使用率不高,而应用缓慢现
象的发生。
&& 3. 内存性能评估
&&&& (1)利用free指令监控内存
&&&&&&&& free是监控linux内存使用状况最常用的指令,看下面的一个输出:
&&&&&&&& [root@webserver ~]# free -m
&&&&&&&& total used free shared buffers cached
&&&&&&&& Mem: 6 0 243 6299
&&&&&&&& -/+ buffers/cache: 643 7468
&&&&&&&& Swap: 9
&&&& 一般有这样一个经验公式:应用程序可用内存/系统物理内存&70%时,表示系统内存资源非常充足,不影响系统性能,应用程序可用内存/系统物理内
存&20%时,表示系统内存资源紧缺,需要增加系统内存,20%&应用程序可用内存/系统物理内存&70%时,表示系统内存资源基本能
满足应用需求,暂时不影响系统性能。
&&& (2)利用vmstat命令监控内存
&&&&&&& [root@node1 ~]# vmstat 2 3
&&&&&&&& procs &&&-memory&&&- &swap- &-io&- -system- &-cpu&&
&&&&&&&& r b swpd free buff cache si so bi bo in cs us sy id wa st
&&&&&&&& 0 0 0 4
&&&&&&&& 0 0 0 4
&&&&&&&& 0 0 0 4
&&& memory
&&& swpd列表示切换到内存交换区的内存数量(以k为单位)。如果swpd的值不为0,或者比较大,只要si、so的值长期为0,这种情况下一般不用担心,不会影响系统性能。
&&&& free列表示当前空闲的物理内存数量(以k为单位)
&&&& buff列表示buffers cache的内存数量,一般对块设备的读写才需要缓冲。
&&&& cache列表示page cached的内存数量,一般作为文件系统cached,频繁访问的文件都会被cached,如果cache值较大,说明cached的文件数较多,如果此时IO中bi比较小,说明文件系统效率比较好。
&&& si列表示由磁盘调入内存,也就是内存进入内存交换区的数量。
&&&& so列表示由内存调入磁盘,也就是内存交换区进入内存的数量。
&&&& 一般情况下,si、so的值都为0,如果si、so的值长期不为0,则表示系统内存不足。需要增加系统内存。
&&&& 4.磁盘I/O性能评估
&&&& (1)磁盘存储基础
&&& 熟悉RAID存储方式,可以根据应用的不同,选择不同的RAID方式。
&&& 尽可能用内存的读写代替直接磁盘I/O,使频繁访问的文件或数据放入内存中进行操作处理,因为内存读写操作比直接磁盘读写的效率要高千倍。
&&& 将经常进行读写的文件与长期不变的文件独立出来,分别放置到不同的磁盘设备上。
&&& 对于写操作频繁的数据,可以考虑使用裸设备代替文件系统。
&&& 使用裸设备的优点有:
&&& 数据可以直接读写,不需要经过操作系统级的缓存,节省了内存资源,避免了内存资源争用。
&&& 避免了文件系统级的维护开销,比如文件系统需要维护超级块、I-node等。
&&& 避免了操作系统的cache预读功能,减少了I/O请求。
&&& 使用裸设备的缺点是:
&&& 数据管理、空间管理不灵活,需要很专业的人来操作。
&&& (2)利用iostat评估磁盘性能
&&&&&&&& [root@webserver ~]# iostat -d 2 3
&&&&&&&& Linux 2.6.9-42.ELsmp (webserver) 12/01/2008 _i686_ (8 CPU)
&&&&&&& Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
&&&&&&&& sda 1.87 2.58 114.12 537372
&&&&&&& Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
&&&&&&&& sda 0.00 0.00 0.00 0 0
&&&&&&& Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
&&&&&&&& sda 1.00 0.00 12.00 0 24
&&&&&&&& 对上面每项的输出解释如下:
&&& Blk_read/s表示每秒读取的数据块数。
&&& Blk_wrtn/s表示每秒写入的数据块数。
&&& Blk_read表示读取的所有块数。
&&& Blk_wrtn表示写入的所有块数。
以通过Blk_read/s和Blk_wrtn/s的值对磁盘的读写性能有一个基本的了解,如果Blk_wrtn/s值很大,表示磁盘的写操作很频繁,可
以考虑优化磁盘或者优化程序,如果Blk_read/s值很大,表示磁盘直接读取操作很多,可以将读取的数据放入内存中进行操作。
&&& 对于这两个选项的值没有一个固定的大小,根据系统应用的不同,会有不同的值,但是有一个规则还是可以遵循的:长期的、超大的数据读写,肯定是不正常的,这种情况一定会影响系统性能。
&&&&&&& (3)利用sar评估磁盘性能
&&&&&&&& 通过&sar -d&组合,可以对系统的磁盘IO做一个基本的统计,请看下面的一个输出:
&&& [root@webserver ~]# sar -d 2 3
&&& Linux 2.6.9-42.ELsmp (webserver) 11/30/2008 _i686_ (8 CPU)
&&& 11:09:33 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
&&& 11:09:35 PM dev8-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
&&& 11:09:35 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
&&& 11:09:37 PM dev8-0 1.00 0.00 12.00 12.00 0.00 0.00 0.00 0.00
&&& 11:09:37 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
&&& 11:09:39 PM dev8-0 1.99 0.00 47.76 24.00 0.00 0.50 0.25 0.05
&&& Average: DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
&&& Average: dev8-0 1.00 0.00 19.97 20.00 0.00 0.33 0.17 0.02
&&& 需要关注的几个参数含义:
&&&&&&& await表示平均每次设备I/O操作的等待时间(以毫秒为单位)。
&&&&&&& svctm表示平均每次设备I/O操作的服务时间(以毫秒为单位)。
&&&&&&& %util表示一秒中有百分之几的时间用于I/O操作。
&&& 对以磁盘IO性能,一般有如下评判标准:
&&& 正常情况下svctm应该是小于await值的,而svctm的大小和磁盘性能有关,CPU、内存的负荷也会对svctm值造成影响,过多的请求也会间接的导致svctm值的增加。
await值的大小一般取决与svctm的值和I/O队列长度以及I/O请求模式,如果svctm的值与await很接近,表示几乎没有I/O等待,磁盘
性能很好,如果await的值远高于svctm的值,则表示I/O队列等待太长,系统上运行的应用程序将变慢,此时可以通过更换更快的硬盘来解决问题。
&&& %util项的值也是衡量磁盘I/O的一个重要指标,如果%util接近100%,表示磁盘产生的I/O请求太多,I/O系统已经满负荷的在工作,该磁盘可能存在瓶颈。长期下去,势必影响系统的性能,可以通过优化程序或者通过更换更高、更快的磁盘来解决此问题。
&5. 网络性能评估
&&& (1)通过ping命令检测网络的连通性
&&& (2)通过netstat -i组合检测网络接口状况
&&& (3)通过netstat -r组合检测系统的路由表信息
&&& (4)通过sar -n组合显示系统的网络运行状态
注明:本文转载一个网站的但修改了一些东西。源网址:http://www.rocklv.net/2004/news/article_284.html
了这篇文章
类别:┆阅读(0)┆评论(0)用户名:zhengzhou11a
文章数:28
访问量:1632
注册日期:
阅读量:1297
阅读量:3317
阅读量:445497
阅读量:1131024
51CTO推荐博文
一、概念理解linux中IO的类型分为四类:同步(sync)和异步(async),阻塞(block)和非阻塞(unblock)同步:发出一个功能调用时,在没有得到结果前会一直等待,直到返回结果。异步:当异步过程调用发出后,调用者不能立刻得到结果。在完成后,通过通知机制或回调函数来通知调用者阻塞:调用结果返回前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,CPU不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果后才返回注意:同步和阻塞是不同的,对同步调用,线程是激活的,当调用者等待的时候,线程还可以处理其它请求,而阻塞线程是会挂起的,是不会处理其它请求的。非阻塞:在结果返回前,函数不会阻塞当前线程,而会立刻返回同步IO和异步IP的区别在于:数据拷贝的时候进程是否阻塞。阻塞IO和非阻塞IO的区别在于:应用程序的调用是否立即返回二、linux下的五种I/O模型1、阻塞I/O (blocking I/O)2、非阻塞I/O (nonblocking I/O)3、I/O 复用 (I/O multiplexing)4、信号驱动I/O (signal driven I/O (SIGIO))5、异步I/O (asynchronous I/O)前四种都是同步,只有最后一种才是异步IO阻塞IO模型:进程会一直阻塞,直到数据拷贝完成应用程序调用一个IO函数,导致应用程序阻塞,等待数据准备好。数据准备好后,从内核拷贝到用户空间,IO函数返回成功指示。阻塞IO模型图如下所示:非阻塞IO模型通过进程反复调用IO函数,在数据拷贝过程中,进程是阻塞的。模型图如下所示IO复用模型主要是select和epoll,对一个IO端口,两次调用,两次返回,关键能实现同时对多个IO端口进行监听。模型如下所示信号驱动IO两次调用,再次返回首先我们允许套接口进行信号驱动IO,并安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,可以在信号处理函数中调用IO函数处理数据,模型如下所示异步IO模型数据拷贝时进程无阻塞,模型如下所示5个IO模型的比较三、select、poll、epoll简介epoll是linux所特有,而select是POSIX所规定,一般操作系统均有实现。select:查找select本质是通过设置或检查存放fd标志位的数据结构来进行下一步处理。缺点是:1、单个进程可监视的fd数量被限制,即能监听端口的大小有限。& 一般来说和系统内存有关,具体数目可以cat /proc/sys/fs/file-max察看。32位默认是1024个,64位默认为2048个&2、对socket进行扫描时是线性扫描,即采用轮询方法,效率低。&当套接字比较多的时候,每次select()都要遍历FD_SETSIZE个socket来完成调度,不管socket是否活跃都遍历一遍。会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,就避免了轮询,这正是epoll与kqueue做的&3、需要维护一个用来存放大量fd的数据结构,会使得用户空间和内核空间在传递该结构时复制开销大&poll:&poll本质和select相同,将用户传入的数据拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或主动超时,被唤醒后又要再次遍历fd&它没有最大连接数的限制,原因是它是基于链表来存储的,但缺点是:&1、大量的fd的数组被整体复制到用户态和内核空间之间,不管有无意义。&2、poll还有一个特点“水平触发”,如果报告了fd后,没有被处理,那么下次poll时再次报告该ffd。&epoll:&epoll支持水平触发和边缘触发,最大特点在于边缘触发,只告诉哪些fd刚刚变为就绪态,并且只通知一次。还有一特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一量该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。&epoll的优点:&1、没有最大并发连接的限制&2、效率提升,只有活跃可用的FD才会调用callback函数&3、内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递。select、poll、epoll区别总结:1、支持一个进程打开连接数select:32位机器1024个,64位2048个poll:无限制,原因基于链表存储epoll:有上限,但很大,2G内存20W左右2、IO效率select:IO效率低poll:IO效率低epoll:只有活跃的socket才调用callback,IO效率高。3、消息传递方式select:内核需要将消息传递到用户空间,都需要内核拷贝动作poll:同上epoll:通过内核与用户空间共享一块内存来实现。本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)&img src=&/v2-d1b944e615eb5bb48f4d4a191f371770_b.jpg& data-rawwidth=&500& data-rawheight=&308& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&/v2-d1b944e615eb5bb48f4d4a191f371770_r.jpg&&&h1&Introduction&/h1&
&p&原文地址: &a href=&/?target=https%3A//www.findhao.net/easycoding/1714& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&服务器、VPS等安全防护教程 - FindHao&i class=&icon-external&&&/i&&/a&&br&在&a href=&/?target=https%3A//www.findhao.net/res/1417& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&从搬瓦工(Bandwagon)购买VPS&i class=&icon-external&&&/i&&/a&之后,自信的在vps里使用了debian搭建ss等等。&br&过了一个多月,就收到搬瓦工邮件,说&/p&
&blockquote&&p&We have detected a large number of outgoing SMTP connections originating from this server. This usually means that the server is sending out spam.&br&我们检测到你的服务器上有大量SMTP连接,换句话说,你的服务器在发送垃圾邮件。&/p&
&/blockquote&
&p&就是说vps被黑了。被人用来滥发邮件。&br&经过一番努力之后,终于在两三个月里,被黑了三次。达到了他们的容忍上限(每个用户的每个vps有三次机会,超过三次就会被停止使用),发tickt也不给面子,就是不让用了。只能新买服务。。&br&于是新买了个vps,这里记录下使用vps需要注意的安全问题。&/p&
&h1&1.认识问题严重性&/h1&
&p&先在你机器(包括你平时用的linux的机器)上跑几个命令看看吧。&/p&
&h2&1.1查看尝试暴力破解机器密码的人&/h2&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo grep &Failed password for root& /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -nr | more
&/code&&/pre&&/div&
&p&害怕吗?&/p&
&h2&1.2查看暴力猜用户名的人&/h2&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo grep &Failed password for invalid user& /var/log/auth.log | awk '{print $13}' | sort | uniq -c | sort -nr | more
&/code&&/pre&&/div&
&p&在我实验室的机器上,看到的结果如下:&/p&
202.201.34.104
114.80.253.81
222.186.58.244
222.186.56.120
198.55.103.144
&p&&strong&感受到寒意了吗?&/strong&&/p&
&h1&2应对策略&/h1&
&h2&2.1 SSH相关&/h2&
&h3&2.1.1 不使用默认的22端口&/h3&
&p&ssh登陆默认的端口是22,而搬瓦工一般都默认是一个比较大的随机端口,&strong&不要为了方便,改回22&/strong&。&br&修改/etc/ssh/sshd_config文件,将其中的Port 22改为随意的端口比如Port 47832,port的取值范围是 0 - 65535(即2的16次方),0到1024是众所周知的端口(知名端口,常用于系统服务等,例如http服务的端口号是80)。&/p&
&h3&2.1.2 不要使用简单密码&/h3&
&p&搬瓦工默认生成的root密码是随机的,但是不要改成你自己的密码,你可以将密码记在手机上,但是一定不要改成你自己的有规律的密码。&/p&
&h3&2.1.3 禁止使用密码登陆,使用RSA私钥登陆&/h3&
&p&&strong&这条是最重要最有效的。&/strong&&br&跟之前写的&a href=&/?target=https%3A//www.findhao.net/easycoding/1652& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&debian ssh 连接android 通过termux&i class=&icon-external&&&/i&&/a&里登陆部分是一样的。rsa的原理也不再赘述,&a href=&/?target=https%3A//zh.wikipedia.org/wiki/RSA%25E5%258A%25A0%25E5%25AF%%25BC%%25AE%%25B3%2595& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&wiki上的条目&i class=&icon-external&&&/i&&/a&描述的很清楚。&br&先通过ssh-keygen -t rsa生成你的客户端的密钥,包括一个私钥和公钥,用scp id_rsa.pub root@XX.XX.XX.XX:~/把公钥拷贝到服务器上,注意,生成私钥的时候,文件名是可以自定义的,且可以再加一层密码,所以建议文件名取自己能识别出哪台机器的名字。然后在服务器上,你的用户目录下,新建.ssh文件夹,并将该文件夹的权限设为600,chmod 600 .ssh,并新建一个authorized_keys,这是默认允许的key存储的文件。如果已经存在,则只需要将上传的id_rsa.pub文件内容追加进去即可:cat id_rsa.pub && authorized_keys,如果不存在则新建并改权限为400即可。&br&然后编辑ssh的配置文件:&/p&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# vi /etc/ssh/sshd_config
RSAAuthentication yes #RSA认证
PubkeyAuthentication yes #开启公钥验证
AuthorizedKeysFile .ssh/authorized_keys #验证文件路径
PasswordAuthentication no #禁止密码认证
PermitEmptyPasswords no #禁止空密码
# 最后保存,重启
# /etc/init.d/sshd restart
&/code&&/pre&&/div&
&h3&2.1.4 禁止root用户登录&/h3&
&p&你可以新建一个用户来管理,而非直接使用root用户,防止密码被破解。&br&还是修改/etc/ssh/sshd_config&/p&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&PermitRootLogin no
&/code&&/pre&&/div&
&h2&2.2 使用denyhosts&/h2&
&blockquote&&p&Denyhosts是一个Linux系统下阻止暴力破解SSH密码的软件,它的原理与DDoS Deflate类似,可以自动拒绝过多次数尝试SSH登录的IP地址,防止互联网上某些机器常年破解密码的行为,也可以防止黑客对SSH密码进行穷举。&/p&
&/blockquote&
&p&建议不要从软件仓库里安装,而是从&a href=&/?target=https%3A///denyhosts/denyhosts& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&denyhosts的github地址&i class=&icon-external&&&/i&&/a&下载,解压,安装。&/p&
&h3&2.2.1 配置文件&/h3&
&p&复制默认的配置文件到/etc下&/p&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&cp denyhosts.conf /etc
sudo vim /etc/denyhosts.conf
&/code&&/pre&&/div&
&p&配置文件里基本不用配置,可以查看下都有什么选项。&/p&
&h3&2.2.2 守护程序&/h3&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&cp daemon-control-dist daemon-control
sudo vim ./daemon-control
sudo chown root daemon-control
sudo chmod 700 daemon-control
&/code&&/pre&&/div&
&p&主要修改执行文件所在的文件夹,改成你的denyhosts所在的地址,可以通过whereis denyhosts看到他的路径。&/p&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&DENYHOSTS_BIN
= &/usr/local/bin/denyhosts.py&
&/code&&/pre&&/div&
&p&同时修改这个守护程序的所属用户和权限。&/p&
&h3&2.2.3 运行&/h3&
&p&添加开机自动运行,编辑/etc/rc.local,在最后的exit之前添加&/p&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# 你的daemon-control在哪里就改为哪里
/usr/share/denyhosts/daemon-control start
&/code&&/pre&&/div&&p&在当前目录下通过daemon-control start来运行。&/p&
&h2&2.3 终极杀手锏 iptables&/h2&
&blockquote&&p&iptables,一个运行在用户空间的应用软件,通过控制Linux内核netfilter模块,来管理网络数据包的流动与转送。在大部分的Linux系统上面,iptables是使用/usr/sbin/iptables来操作,文件则放置在手册页(Man page[2])底下,可以通过 man iptables 指令获取。通常iptables都需要内核层级的模块来配合运作,Xtables是主要在内核层级里面iptables API运作功能的模块。因相关动作上的需要,iptables的操作需要用到超级用户的权限。&/p&
&/blockquote&
&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# 清除已有iptables规则
iptables -F
# 允许本地回环接口(即运行本机访问本机)
iptables -A INPUT -i lo -j ACCEPT
# 允许已建立的或相关连的通行
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#允许所有本机向外的访问
iptables -A OUTPUT -j ACCEPT
# 允许访问22端口,以下几条相同,分别是22,80,443端口的访问
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
#如果有其他端口的话,规则也类似,稍微修改上述语句就行
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
#禁止其他未允许的规则访问(注意:如果22端口未加入允许规则,SSH链接会直接断开。)
iptables -A INPUT -j REJECT
iptables -A FORWARD -j REJECT
&/code&&/pre&&/div&&p&开机启动项的设置可以参考Reference里关于iptables的条目&/p&
&h1&总结&/h1&
&p&安全问题实在太重要,即使设置了以上防护,也有可能被攻克,重要的是提高安全意识。&br&等我遇到了新的问题,再更新文章。。&/p&
&h1&Reference&/h1&
&p&&a href=&/?target=http%3A///vps-anti-ssh-login-attempts-attack.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&VPS 防止 SSH 暴力登录尝试攻击&i class=&icon-external&&&/i&&/a&&br&&a href=&/?target=http%3A//linux%25E9%25BB%%25AE%25A4%25E7%25AB%25AF%25E5%258F%25A3%25E8%258C%%259B%25B4%25E6%2598%25AF%25E5%25A4%259A%25E5%25B0%2591%25EF%25BC%259F-CSDN%25E8%25AE%25BA%25E5%259D%259B-CSDN.NET-%25E4%25B8%25AD%25E5%259B%25BD%25E6%259C%%25A4%25A7%25E7%259A%2584IT%25E6%258A%%259C%25AF%25E7%25A4%25BE%25E5%258C%25BA& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&linux默认端口范围是多少&i class=&icon-external&&&/i&&/a&&br&&a href=&/?target=http%3A//10%%E9%E6%259C%258D%25E5%258A%25A1%25E5%%25E5%25AE%%%25E8%25AE%25BE%25E7%25BD%25AE%25EF%25BC%258CUbuntu%25E5%25AE%%%25E8%25AE%25BE%25E7%25BD%25AE%25E5%%25E9%%%25E6%E7%25AB%25A0%%25E4%25BC%25AF%25E4%25B9%%259C%25A8%25E7%25BA%25BF& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&10 分钟服务器安全设置,Ubuntu安全设置入门&i class=&icon-external&&&/i&&/a&&br&&a href=&/?target=http%3A//tanxin./1245& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Linux下的iptables详解及配置&i class=&icon-external&&&/i&&/a&&br&&a href=&/?target=http%3A//www.vpser.net/security/linux-iptables.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Linux上iptables防火墙的基本应用教程&i class=&icon-external&&&/i&&/a&&br&&a href=&/?target=https%3A//zh.wikipedia.org/wiki/Iptables& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&iptables wiki&i class=&icon-external&&&/i&&/a&&br&&a href=&/?target=https%3A//wiki.archlinux.org/index.php/Iptables_%28%25E7%25AE%%25BD%%25B8%25AD%25E6%& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&iptables archwiki&i class=&icon-external&&&/i&&/a&)&/p&
Introduction
原文地址:
在之后,自信的在vps里使用了debian搭建ss等等。 过了一个多月,就收到搬瓦工邮件,说
We have detected a large number of outgoing SMTP connections originat…
Ubuntu的话推荐几个小插件(自己装过并且正在使用的,亲测好用~)&br&StackApplet&br&&img src=&/465c374ba57b0b08e7118_b.png& data-rawwidth=&234& data-rawheight=&292& class=&content_image& width=&234&&哈,自家的插件在AskUbuntu上被顶到了第一,不过这个是挺好用的,一有动态自动更新,自己可以设置同步的频率&br&System Load Indicator&br&&img src=&/828d2bf6a_b.png& data-rawwidth=&308& data-rawheight=&290& class=&content_image& width=&308&&&br&这个就不多说了,类似OSX的iStat&br&Indicator Synapse&br&&img src=&/47b3e9d3a236fc0216365_b.png& data-rawwidth=&750& data-rawheight=&356& class=&origin_image zh-lightbox-thumb& width=&750& data-original=&/47b3e9d3a236fc0216365_r.png&&&img src=&/05a0a96c6d4cc04be01ad_b.png& data-rawwidth=&750& data-rawheight=&216& class=&origin_image zh-lightbox-thumb& width=&750& data-original=&/05a0a96c6d4cc04be01ad_r.png&&简直是x86的神器,功能堪比OSX下的Spotlight,让你再也不用忍受慢慢吞吞的Unity Lens了~ps14.04LTS不能直接设置keybindings了 要下一个xdotool来模拟鼠标操作~&br&&br&Mutate(&a href=&///?target=https%3A///qdore/Mutate& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/qdore/Mutate&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&)&br&要是x64的可以装个Mutate,功能更好更强大&br&&img src=&/8e4aa884dd45d901d60467c_b.png& data-rawwidth=&700& data-rawheight=&584& class=&origin_image zh-lightbox-thumb& width=&700& data-original=&/8e4aa884dd45d901d60467c_r.png&&&img src=&/ed9e_b.png& data-rawwidth=&700& data-rawheight=&584& class=&origin_image zh-lightbox-thumb& width=&700& data-original=&/ed9e_r.png&&&img src=&/4bee6ad7adac19ed9f6bb_b.png& data-rawwidth=&1250& data-rawheight=&304& class=&origin_image zh-lightbox-thumb& width=&1250& data-original=&/4bee6ad7adac19ed9f6bb_r.png&&&img src=&/f934acdb4a74c73d8615892_b.png& data-rawwidth=&700& data-rawheight=&584& class=&origin_image zh-lightbox-thumb& width=&700& data-original=&/f934acdb4a74c73d8615892_r.png&&&img src=&/c2beed803c4bbd897100aaa_b.png& data-rawwidth=&700& data-rawheight=&227& class=&origin_image zh-lightbox-thumb& width=&700& data-original=&/c2beed803c4bbd897100aaa_r.png&&&img src=&/b4ce6d434a06ee782bbbfeb498f820b2_b.png& data-rawwidth=&700& data-rawheight=&533& class=&origin_image zh-lightbox-thumb& width=&700& data-original=&/b4ce6d434a06ee782bbbfeb498f820b2_r.png&&&br&caffeine&br&&img src=&/4a58afd213abfe_b.png& data-rawwidth=&513& data-rawheight=&500& class=&origin_image zh-lightbox-thumb& width=&513& data-original=&/4a58afd213abfe_r.png&&顾名思义,让你的屏幕跟你一起打鸡血,可以在需要的时候始终保持屏幕亮着,不用每次去system setting里设~话说AskUbuntu上有个问题专门讨论各种神器&a href=&///?target=http%3A///questions/30334/what-application-indicators-are-available%23& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&/questions&/span&&span class=&invisible&&/30334/what-application-indicators-are-available#&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&br&&br&最后安利一个轻量级的发行版 基于debian的crunchbang 让我那3G小内存的X200顺畅得不行不行的~( ̄▽ ̄~)~
Ubuntu的话推荐几个小插件(自己装过并且正在使用的,亲测好用~) StackApplet 哈,自家的插件在AskUbuntu上被顶到了第一,不过这个是挺好用的,一有动态自动更新,自己可以设置同步的频率 System Load Indicator 这个就不多说了,类似OSX的iStat Indicator…
&p&==介绍== &br&&/p&&p&本Blog开始介绍一下在Linux分析性能瓶颈的基本方法。主要围绕一个基本的分析模型,介绍perf和ftrace的使用技巧,然后东一扒子,西一扒子,逮到什么说什么,也不一定会严谨。主要是把这个领域的一些思路和技巧串起来。如果读者来讨论得多,我们就讨论深入一点,如果讨论得少,那就当作一个提纲给我做一些对外交流用吧。&/p&==基本模型== &p&我们需要有一套完整的方法来发现系统的瓶颈。“瓶颈”这个概念,来自业务目标,不考虑业务目标就没有“瓶颈”这个说法。从业务目标角度,通常我们的瓶颈出现在业务的通量(Throughput)和时延(Latency)两个问题上。(手机等领域常常还会考虑功耗这个要素,但那个需要另外的模型,这里暂时忽略)&/p&&p&比如一个MySQL数据库,你从其他机器上对它发请求,每秒它能处理10万个请求,这个就是通量性能,每个请求的反应时间是0.5ms,这个就是时延性能。&/p&&br&&p&通量和时延是相互相承的两个量,当通量达到系统上限,时延就会大幅提高。我们从下面这个例子开始来看这个模型(图1):&/p&&p&&img data-rawheight=&262& data-rawwidth=&546& src=&/814ea20a301ee45f40f1d_b.png& class=&origin_image zh-lightbox-thumb& width=&546& data-original=&/814ea20a301ee45f40f1d_r.png&& 请求从客户端发到计算机上,花t1的时间,用t2的时间完成计算,然后用t3的时间把结果送回到客户端,这个时延是t1+t2+t3,如果我们在t3发过来后,发下一个请求,这样系统的通量就是1/(t1+t2+t3)。&/p&&p&当然,现实中我们不可能使用这样的方法来处理业务请求,这样处理通量肯定是很低的。因为t2和t1/t3作用在两个不同的运行部件上,完全没有必要让他们串行(在同一个会话中有必要,但整体上没有必要。其原理就是CPU流水线)。所以这个模型应该这样来实现(图2):&/p&&p&&img data-rawheight=&217& data-rawwidth=&545& src=&/9eaa6e9310ffb3dd8d5e41_b.png& class=&origin_image zh-lightbox-thumb& width=&545& data-original=&/9eaa6e9310ffb3dd8d5e41_r.png&& t2变成一个队列的处理,这样时延还是会等于t1+t2+t3,但t2的含义变了。只要调度能平衡,而且认为通讯管道的流量无限,通量可以达到1/t2(和CPU流水线中,一个节拍可以执行一条指令的原理相同)。1/t2是CPU清队列库存的速度,数据无限地供给到队列上,如果瞬时队列的长度是len,CPU处理一个包的时间是ti,t2=len*ti,如果请求无限上升,len就会越来越长,时延就会变大,所以,通常我们对队列进行流控,流控有很多方法,反压丢包都可以,但最终,当系统进入稳态的时候,队列的长度就会维持在一个稳态,这时的t2就是可以被计算的了。&/p&&p&对于上面这样一个简单模型,如果CPU占用率没有到100%,时延会稳定在len*ti。len其实就等于接收线程(或者中断)一次收入的请求数。但如果CPU达到100%,队列的长度就无限增加,时延也会跟着无限增加。所以我们前面说,当通量达到上限的时候,时延会无限增加,直到发生流控。 &br&&/p&&p&现代CPU是一个多核多部件系统,这种队列关系在整个系统中会变得非常复杂,比如,它有可能是这样的(图3):&/p&&img data-rawheight=&341& data-rawwidth=&1734& src=&/c6ec53eed43f065c5a666c_b.png& class=&origin_image zh-lightbox-thumb& width=&1734& data-original=&/c6ec53eed43f065c5a666c_r.png&&虽然很多系统看起来不是这样一个接一个队列的模型,但其实如果你只考虑主业务流,几乎大部分情形都是这样的&p&对这样的系统,我们仍有如下结论:系统的时延等于路径上所有队列的len[i]*t[i]的和。其实你会发现,这个模型和前一个简单模型本质上并没有区别。只是原来的原则作用在了所有的队列上。&/p&&p&也就是说:如果CPU没有占满,队列也没有达到流控,则时延会稳定在len[i]*t[i]上。我们只要保证输入短可以供数据到系统中即可&/p&&p&这个结论为我们的性能优化提供了依据。就是说,我们可以先看CPU是否满载,满载就优化CPU,没有满载就找流控点,通过流控点调整时延和通量就可以了。&/p&&p&在多核的情况下,CPU无法满载还会有一个原因,就是业务线程没有办法在多个CPU上展开,这需要通过增加处理线程来实现。&/p&&p&==全系统的线程模型== &br&&/p&&p& 我们一般看系统是从“模块”的角度来看的,但看系统的性能模型,我们是从线程的角度来看的。&/p&&p&这里的线程是广义线程,表示所有CPU可以调度以使用自己的执行能力的实体,包括一般意义的线程,中断,signal_handler等。 &br&&/p&&p&好比前面的MySQL的模型,请求从网卡上发送过来。首先是中断向量收到包请求,然后是softirq收包,调用napi的接口来收包,比如napi_schedule。这时调用进入网卡框架层了,但线程上下文还是没有变,napi_schedule回过头调用网卡的polling函数,网卡收包,通过napi_skb_finish()一类的函数向IP层送包,然后顺着比如netif_receive_skb_internal-&__netif_receive_skb-&__netif_receive_skb_core-&deliver_skb-&...这样的路径一路进去到某种类型的socket buffer中,这个过程跨越多个模块,跨越多个协议栈的层,甚至在极端情况下可以跨越内核态和用户态。但我们仍认为是一个线程搬移,是softirq线程把网卡上的buffer,搬移到CPU socket buffer的一个过程。调整网卡和socket buffer之间的大小,流控时间,部署给这些队列的线程的数目和调度时间,就可以调整好整个系统的性能。&/p&&p&从线程模型上看性能,处理模型就会比较简单:我们如果希望提高一个队列清库存的效率,只要增加在这个队列上的搬移线程,或者提高部署在上面的线程(实际上是CPU核)的数量,就可以平衡它的流控时间。如果我们能平衡所有队列的效率和长度,我们就比较容易控制整个系统的通量和时延了。&/p&&p&这其中当然还会涉及很多细节的设计技巧,但大方向是这个。&/p&&p&在线程这个问题上,最后要补充几句:线程是为了驱动系统的运行。不少新手很容易把线程和模块的概念搞到一起,甚至给每个模块配备一个线程。这是不少系统调度性能差的原因。初学者应该要时刻提醒自己,线程和模块是两个独立的,正交的概念,是不应该绑定的。模块是为了实现上的内聚,而线程是为了:&/p&&p&1. 把计算压力分布到多个核上&/p&&p&2. 匹配不同执行流程的速率&/p&&p&3. 当线程的执行流程中有同步IO的时候,增加线程以便减少在同步IO上的等待时间(本质上是增加流水线层次提升执行部件的同步效率)&br&&/p&&p&后面我们谈具体的优化技巧的时候我们会重新提到线程的这些效果。&/p&&br&&p&==一般操作方法== &br&&/p&&br&&p&所以,当我们遭遇一个通量性能瓶颈的时候,我们通常分三步来发现瓶颈的位置:&/p&&p&1. CPU占用率是否已经满了,这个用top就可以看到,比如下面这个例子:&/p&&p&&img data-rawheight=&295& data-rawwidth=&1099& src=&/de56cff36db76fffcb828_b.png& class=&origin_image zh-lightbox-thumb& width=&1099& data-original=&/de56cff36db76fffcb828_r.png&& 有两个CPU的idle为0,另两个基本上都是接近100%的idle,我们基于这个就可以决定我们下一步的分析方向是什么了。&br&&/p&&p&如果CPU没有满,有三种可能:&/p&&p&1.1 某个队列提早流控了。我们通过查看每个独立队列的统计来寻找这些流控的位置,决定是否需要提升队列长度来修复这种流控。例如,我们常常用ifconfig来观察网卡是否有丢包:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&wlan0
Link encap:以太网
硬件地址 7c:7a:91:xx:xx:xx
inet 地址:192.168.0.103
广播:192.168.0.255
掩码:255.255.255.0
inet6 地址: fe80::7e7a:91ff:fefe:5a1a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST
接收数据包:113832 错误:0 丢弃:0 过载:0 帧数:0
发送数据包:81183 错误:0 丢弃:0 过载:0 载波:0
碰撞:0 发送队列长度:1000
接收字节: &span class=&o&&(&/span&47.8 MB&span class=&o&&)&/span&
发送字节: &span class=&o&&(&/span&18.9 MB&span class=&o&&)&/span&
&/code&&/pre&&/div&&p& 在高速网卡场景中,我们常常要修改/proc/sys中的网络参数保证收包缓冲区足够处理一波netpolling的冲击。 &/p&&p&我们自己写业务程序的时候,也应该对各个队列的水线,丢包数等信息进行统计,这样有助于我们快速发现队列的问题。 &br&&/p&&p&1.2 调度没有充分展开,比如你只有一个线程,而你其实有16个核,这样就算其他核闲着,你也不能怎么样。这是需要想办法把业务hash展开到多个核上处理。上面那个top的结果就是这种情形。&/p&&p&1.3 配套队列的线程有IO空洞,要通过异步设计把空洞填掉,或者通过在这个队列上使用多个线程把空洞修掉。具体的原理,后面谈分析方法的时候再深入介绍。 &br&&/p&&p&2. 如果CPU占用率已经占满了,观察CPU的时间是否花在业务进程上,如果不是,分析产生这种问题的原因。Linux的perf工具常常可以提供良好的分析,比如这样:&img data-rawheight=&172& data-rawwidth=&811& src=&/9a3eac0ef4e_b.png& class=&origin_image zh-lightbox-thumb& width=&811& data-original=&/9a3eac0ef4e_r.png&&&/p&&p&这里例子中的CPU占用率已经全部占满了。但时间中只有15.43%落在主业务流程上,下面有大量的时间花在了锁和调度上。如果我们简单修改一下队列模式,我们就可以把这个占用率提升到23.39%:&/p&&img data-rawheight=&335& data-rawwidth=&867& src=&/cb3a611da01_b.png& class=&origin_image zh-lightbox-thumb& width=&867& data-original=&/cb3a611da01_r.png&&&p&当我们发现比如schedule调度特别频繁的时候,我们可以通过ftrace观察每次切换的原因,比如下面这样:&/p&&p&&img data-rawheight=&443& data-rawwidth=&1707& src=&/8aadba9c4bceffec20c3_b.png& class=&origin_image zh-lightbox-thumb& width=&1707& data-original=&/8aadba9c4bceffec20c3_r.png&&你可以看到业务线程执行3个ns就直接切换为Idle了,我们可以在业务线程上加mark看具体是什么流程导致这个切换的(如果系统真的忙,任何线程都应该用完自己的时间片,否则就是有额外的问题引起额外的代价了)&br&&/p&&p&3. 如果CPU的时间确实都已经在处理业务的,剩下的问题就是看CPU执行系统是否被充分利用(比如基于例如Top Down模型分析系统CPU的执行部件是否被充分利用) 或者软件算法是否可以优化了。这个也可以通过perf和ftrace组合功能来实现。&/p&&p&在后面几篇博文中,我们会逐一看看Linux的perf和ftrace功能如何对这些分析提供技术支持的。&/p&&p&&br&==关于流控==&/p&&p&流控是个很复杂的问题,这里没有准备展开,但需要补充几个值得考量的问题。&/p&&p&第一,流控应该出现在队列链的最前面,而不是在队列的中间。因为即使你在中间丢包了,前面几个队列已经浪费CPU时间在这些无效的包上了,这样的流控很低效。所以,中间的队列,只要可能,一般不设置自身的流控&/p&&p&第二,在有流控的系统上,需要注意一种很常见的陷阱:就是队列过长,导致最新的包被排到很后才处理,等完成整个系统的处理的时候,这个包已经被请求方判断超时了。这种情况会导致大量的失效包。所以,流控的开始时间要首先于每个包的超时时间。 &/p&&p&&br&==总结==&/p&&p&性能分析应该是一个有针对性的工作,我们大部分情况都不可能通过“调整这个参数看看结果,再调整调整那个参数看一个结果,然后寄望于运气。我们首先必须从一开始就建立系统的运行模型,并有意识地通过程序本身的统计以及系统的统计,对程序进行profiling,并针对性地解决问题。 &/p&
==介绍== 本Blog开始介绍一下在Linux分析性能瓶颈的基本方法。主要围绕一个基本的分析模型,介绍perf和ftrace的使用技巧,然后东一扒子,西一扒子,逮到什么说什么,也不一定会严谨。主要是把这个领域的一些思路和技巧串起来。如果读者来讨论得多,我们就讨…
&p&==介绍== &br&&/p&&p&在我们进一步介绍更多模型分析技巧前,我们先要对基本工具有一些了解。这一篇先介绍ftrace的基本用法。&/p&&p&ftrace在内核的Documentation目录下已经有文档了,我这里不是要对那个文档进行翻译,而是要说明这个工具的设计理念和使用策略。细节的东西读者要自己去看手册。 &/p&&br&&p&ftrace通过一个循环队列跟踪内核的执行过程。这个循环队列在内存中,大小是固定的(可以动态设置),所以写入的速度可以很快,在没有ftrace的时候,我经常通过类似的方式人工跟踪系统的执行过程,以便定位调度引起的各种问题。调度的问题对执行时间非常敏感,所以进行跟踪需要尽量避免把IO,等待等各种额外的要素加进来。而直接写内存就成为影响最小的一种模式了,ftrace很好地满足了这个要求。所以基本上现在我已经不需要再写额外的人工跟踪代码来跟踪系统的执行序列了。&/p&&p&ftrace通过debugfs对外提供接口,所以不需要额外的工具进行支持。ftrace在内核中的配置选项是CONFIG_FTRACE,除了这个基本选项外,下面还有很多子特定可以单独选,用户可以自己去看对应的Kconfig文档,一般的发行版都会开启这个特性,所以大部分情况下你也不需要为了使用这个功能重新编译内核。debugfs在大部分发行版中都mount在/sys/kernel/debug目录下,而ftrace就在这个目录下的tracing目录中。如果系统没有mount这个文件系统,你也可以手工mount。作为虚拟文件系统,它和procfs一样,给定类型就可以mount,比如你可以这样:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&mount -t debugfs none /home/kenneth-lee/debug
&/code&&/pre&&/div&&p& tracing目录中的内容有点乱:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&available_events
current_tracer
function_profile_enabled
saved_cmdlines_size
set_ftrace_pid
stack_trace
trace_options
tracing_on
available_filter_functions
dyn_ftrace_total_info
set_graph_function
stack_trace_filter
trace_pipe
tracing_thresh
available_tracers
enabled_functions
kprobe_events
printk_formats
set_event_pid
set_graph_notrace
trace_stat
uprobe_events
buffer_size_kb
kprobe_profile
set_ftrace_filter
trace_clock
tracing_cpumask
uprobe_profile
buffer_total_size_kb
free_buffer
max_graph_depth
saved_cmdlines
set_ftrace_notrace
stack_max_size
trace_marker
tracing_max_latency
&/code&&/pre&&/div&&p&里面虽然有一个README文件在解释,但这个文档更新得不快,很多时候和实际的内容对不上。但不要紧,只要我们抓住重点逻辑,就很容易理解了。ftrace的目录设置和sysfs类似,都是把目录当作对象,把里面的文件当作这个对象的属性。所以,虽然这个目录中的文件众多,我们只要先理解以下几个概念就很容易抓住重点了:&/p&&p& 1. instance&/p&&p&一个用来跟踪的缓冲区(内存)称为一个instance,缓冲区的大小由文件buffer_size_kb和buffer_total_size_kb文件指定。有了缓冲区,你就可以启动行为跟踪,跟踪的结果会分CPU写到缓冲区中。缓冲区的数据可以通过trace和trace_pipe两个接口读出。前者通常用于事后读,后者是个pipe,可以让你动态读。为了不影响执行过程,我更推荐前一个接口。&/p&&p&trace等文件的输出是综合所有CPU的,如果你关心单个CPU可以进入per_cpu目录,里面有这些文件的分CPU版本。&br&&/p&&p&我们不要看到trace文件中输出那么多文本,就觉得这个跟踪效率不高。那些文本都是事后(就是你读这个文件的时候)format出来的,跟踪的时候仅仅记录了必须的数据信息,所以不需要担心跟踪时的效率问题。&/p&&p&所以读者应该已经明白了/sys/kernel/debug/tracing这个目录本身就代表一个instance。如果你需要更多的instance,你可以进入到这个目录下面的instances目录中,创建一个任意名字的目录,那个目录中就也会有另一套buffer_size_kb啦,trace啦这些文件,那里就是另一个instance了。通过多instance,你可以隔离多个独立的跟踪任务。当然,这也很浪费内存。 &/p&&p&和所有面向对象设计一样,instance通过操作对应属性来控制其行为,比如,向trace文件写一个空字符串可以清空对应的缓冲区:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&nb&&echo&/span& & trace
&/code&&/pre&&/div&&p&又比如,向tracing_on文件写1启动跟踪,写0停止跟踪等。向set_ftrace_pid写pid可以限制只根据某个pid的事件等。&/p&&p&更复杂的控制在trace_options中,这个文件也是很好理解的,类似vim,你看看它的内容,要启动某个功能就echo某个字符串进去,要关闭它只要echo带“no”前缀的那个字符串进去就可以了。options目录可以提供更精细的控制。&/p&&p&2.
事件(event)&/p&&p&ftrace有两种主要跟踪机制可以往缓冲区中写数据,一种是函数,一种是事件。前者比较酷,很多教程都会先讲前者。但对我来说,后者才比较可靠实用,所以我先讲后者。&/p&&p&事件是固定插入到内核中的跟踪点,我们看Linux代码的时候,经常看到这种trace_开头的函数调用:&/p&&div class=&highlight&&&pre&&code class=&language-c&&&span&&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&likely&/span&&span class=&p&&(&/span&&span class=&n&&prev&/span& &span class=&o&&!=&/span& &span class=&n&&next&/span&&span class=&p&&))&/span& &span class=&p&&{&/span&
&span class=&n&&rq&/span&&span class=&o&&-&&/span&&span class=&n&&nr_switches&/span&&span class=&o&&++&/span&&span class=&p&&;&/span&
&span class=&n&&rq&/span&&span class=&o&&-&&/span&&span class=&n&&curr&/span& &span class=&o&&=&/span& &span class=&n&&next&/span&&span class=&p&&;&/span&
&span class=&o&&++*&/span&&span class=&n&&switch_count&/span&&span class=&p&&;&/span&
&span class=&n&&trace_sched_switch&/span&&span class=&p&&(&/span&&span class=&n&&preempt&/span&&span class=&p&&,&/span& &span class=&n&&prev&/span&&span class=&p&&,&/span& &span class=&n&&next&/span&&span class=&p&&);&/span&
&span class=&n&&rq&/span& &span class=&o&&=&/span& &span class=&n&&context_switch&/span&&span class=&p&&(&/span&&span class=&n&&rq&/span&&span class=&p&&,&/span& &span class=&n&&prev&/span&&span class=&p&&,&/span& &span class=&n&&next&/span&&span class=&p&&,&/span& &span class=&n&&cookie&/span&&span class=&p&&);&/span& &span class=&cm&&/* unlocks the rq */&/span&
&span class=&p&&}&/span& &span class=&k&&else&/span& &span class=&p&&{&/span&
&span class=&n&&lockdep_unpin_lock&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&rq&/span&&span class=&o&&-&&/span&&span class=&n&&lock&/span&&span class=&p&&,&/span& &span class=&n&&cookie&/span&&span class=&p&&);&/span&
&span class=&n&&raw_spin_unlock_irq&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&rq&/span&&span class=&o&&-&&/span&&span class=&n&&lock&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&这个地方就是一个事件,也就是打在程序中的一个桩,如果你使能这个桩,程序执行到这个地方就会把这个点(就是一个整数,而不是函数名),加上后面的三个参数(preempt, prev, next)都写到缓冲区中。到后面你要输出的时候,它会用一个匹配的解释函数来把内容解释出来,然后你在trace文件中看到的就是这样的:&/p&&p&&img data-rawheight=&506& data-rawwidth=&1781& src=&/be3c648d112e504d40643_b.png& class=&origin_image zh-lightbox-thumb& width=&1781& data-original=&/be3c648d112e504d40643_r.png&&启动事件跟踪的方法很简单:&/p&&p&1.
先查available_events中有哪些可以用的事件(查events目录也可以)。&/p&&p&2. 把那个事件的名称写进set_event,可以写多个,可以写sched:*这样的通配符&/p&&p&3. 通过trace_on文件启动跟踪。启动之前可以通过比如tracing_cpumask这样的文件限制跟踪的CPU,通过set_event_pid设置跟踪的pid,或者通过其他属性进行更深入的设定。&/p&&p&剩下的事情就是执行跟踪程序和分析跟踪结果了。&/p&&p&我通常把ftrace的设置和启动等命令和业务程序的启动写到一个脚本中,一次运行足够的时间然后直接取结果。然后就专心手工或者通过python脚本分析输出结果(ftrace的输出用awk很不好拆,还是python比较实际)&/p&&p&事件跟踪的另一个更强大的功能是可以设定跟踪条件,要做这种精细化的设置,你需要直接操作events目录下面的事件参数,比如仍是跟踪前面这个sched_switch,你可以先看看events/sched/sched_switch/format文件:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&name: sched_switch
field:unsigned short common_type&span class=&p&&;&/span&
offset:0&span class=&p&&;&/span&
size:2&span class=&p&&;&/span& signed:0&span class=&p&&;&/span&
field:unsigned char common_flags&span class=&p&&;&/span&
offset:2&span class=&p&&;&/span&
size:1&span class=&p&&;&/span& signed:0&span class=&p&&;&/span&
field:unsigned char common_preempt_count&span class=&p&&;&/span&
offset:3&span class=&p&&;&/span&
size:1&span class=&p&&;&/span& signed:0&span class=&p&&;&/span&
field:int common_pid&span class=&p&&;&/span&
offset:4&span class=&p&&;&/span&
size:4&span class=&p&&;&/span& signed:1&span class=&p&&;&/span&
field:char prev_comm&span class=&o&&[&/span&16&span class=&o&&]&/span&&span class=&p&&;&/span&
offset:8&span class=&p&&;&/span&
size:16&span class=&p&&;&/span&
signed:1&span class=&p&&;&/span&
field:pid_t prev_pid&span class=&p&&;&/span&
offset:24&span class=&p&&;&/span&
size:4&span class=&p&&;&/span& signed:1&span class=&p&&;&/span&
field:int prev_prio&span class=&p&&;&/span&
offset:28&span class=&p&&;&/span&
size:4&span class=&p&&;&/span& signed:1&span class=&p&&;&/span&
field:long prev_state&span class=&p&&;&/span&
offset:32&span class=&p&&;&/span&
size:8&span class=&p&&;&/span& signed:1&span class=&p&&;&/span&
field:char next_comm&span class=&o&&[&/span&16&span class=&o&&]&/span&&span class=&p&&;&/span&
offset:40&span class=&p&&;&/span&
size:16&span class=&p&&;&/span&
signed:1&span class=&p&&;&/span&
field:pid_t next_pid&span class=&p&&;&/span&
offset:56&span class=&p&&;&/span&
size:4&span class=&p&&;&/span& signed:1&span class=&p&&;&/span&
field:int next_prio&span class=&p&&;&/span&
offset:60&span class=&p&&;&/span&
size:4&span class=&p&&;&/span& signed:1&span class=&p&&;&/span&
&/code&&/pre&&/div&&p&你就可以看到这个事件可以支持的域,你只要向同级目录中的filter中写一条类C的表达式就可以对这个事件进行过滤。&/p&&p&比如,我注意到这个跟踪点支持next_comm这个域,我就可以这样写:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&echo 'next_comm ~ &cs&' & events/sched/sched_switch/filter
&/code&&/pre&&/div&&p&这样我就可以仅跟踪调度器切换到cs这个线程的场景了。&/p&&p&对于性能分析,我用得最多的是这个线程switch事件(还有softirq的一组事件)。因为从考量通量的角度,主业务CPU要不idle,它要不在处理业务,要不在调度。一个“不折腾”的系统,主业务进程应该每次都用完自己的时间片,如果它总用不完,要不是它实时性要求很高(主业务这种情况很少),要不是线程调度设计有问题。我们常常看到的一种模型是,由于业务在线程上安排不合理,导致一个线程刚执行一步,马上要等下一个线程完成,那个线程又执行一步,又要回来等前一个线程完成,这样CPU的时间都在切换上,整个通量就很低了。&/p&&p&这种模型后面专门论述,但通过ftrace看调度过程,我们很容易用python分析这个调度过程,捕获所有“提前切换”的情况,并对高几率的提前切换进行分析,就可以针对性地解决问题了。&/p&&p&事件上还可以安装trigger,用来触发特定的动作,我很少用这个功能,读者可以自己看手册看看有没有什么实际的用途。 其中手册中提到一个特别酷的功能叫“hist”(输出柱状图),它可以通过这样的命令:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&nb&&echo&/span& &span class=&s1&&'hist:key=call_site:val=bytes_req'&/span& & /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
&/code&&/pre&&/div&&p&实现下面这样的效果:&/p&&p&&img data-rawheight=&648& data-rawwidth=&911& src=&/8d987f7aa42f6d407abfc0a_b.png& class=&origin_image zh-lightbox-thumb& width=&911& data-original=&/8d987f7aa42f6d407abfc0a_r.png&&这相当于给你提供一个各个内存分配点的内存分配次数和数量的一个分布图。这很爽,不过老实说,有了trace文件,要产生这样的数据也是分分钟的事,所以我也不是很需要这个功能。&br&&/p&&br&&p&3. 预定义功能&/p&&p&事件跟踪需要根据我们对Kernel业务流有清晰的认识,我们才能合理设置事件。功能跟踪就会简单得多,功能跟踪可以直接使能某种跟踪功能,具体用什么事件,设置什么参数等,都默认设置好,这种预定义功能在available_tracers中列出,只要选择其中一个,把对应的名字写入current_tracer文件中就可以启动这个功能&/p&&p& 我的机器上支持如下功能:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
&/code&&/pre&&/div&&p& 比如我要跟踪系统唤醒的时延,我们可以:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&echo wakeup & current_tracer
echo 1 & tracing_on
&/code&&/pre&&/div&&p& wakeup跟踪的输出是这个样子的:&/p&&img data-rawheight=&709& data-rawwidth=&901& src=&/c9d56e796_b.png& class=&origin_image zh-lightbox-thumb& width=&901& data-original=&/c9d56e796_r.png&&&p&它可以跟踪在你跟踪的期间里,最高优先级的任务的调度最大时延。比如上面这个统计统计到的最大时延是52us(算不错了),下面给出的跟踪点是这个任务(irq/49-iwlwifi-1625)被唤醒后,执行了哪些动作,才轮到它执行了。通过分析这些动作,你就可以知道你可以优化哪些流程来提升整个系统的实时性了。 &/p&&p&我很少使用这种成套跟踪,读者可以自己一个个试用一下,看看是否有趁手的工具,可以帮助你解决你的环境中面的的问题。&/p&&br&&p&4. 函数跟踪&/p&&p&成套跟踪中有两个功能其实是相对独立的,就是function和function_graph。这个功能可以和事件一样单独使用(可惜的是不能同时使用,其实照理说这没有什么难度的)。&/p&&p&函数跟踪和事件跟踪一样,相当于在函数入口那里增加了一个trace_函数, 函数跟踪的效果类似这样:&/p&&p&&img data-rawheight=&901& data-rawwidth=&933& src=&/60aaef854afff88ab81e8b_b.png& class=&origin_image zh-lightbox-thumb& width=&933& data-original=&/60aaef854afff88ab81e8b_r.png&&加堆栈跟踪的话,可以变成这样:&/p&&p&&img data-rawheight=&872& data-rawwidth=&625& src=&/15dcee3a4abf_b.png& class=&origin_image zh-lightbox-thumb& width=&625& data-original=&/15dcee3a4abf_r.png&&函数跟踪也可以做类似事件工作一样的过滤功能,这个用户可以看手册,我用这个功能一般是用来跟踪和性能无关的执行过程,&/p&&p&== 用户态跟踪==&/p&&p&ftrace一个比较明显的缺点是没有用户态的跟踪点支持,作为补救,instance中提供了一个文件,trace_marker,写这个文件可以在跟踪中产生一条记录。类似这样:&/p&&p&&img data-rawheight=&563& data-rawwidth=&1764& src=&/ab18b1632adad0bfea22b5a91c4e8e15_b.png& class=&origin_image zh-lightbox-thumb& width=&1764& data-original=&/ab18b1632adad0bfea22b5a91c4e8e15_r.png&&你可以注意到,这其中 tracing_mark_write就是一个marker,我在我的程序做pthread_yield()的时候加了一个marker,这样我就可以跟踪当我yield出去的时候,系统是否发生了重新调度。&/p&&p&这个跟踪方法的缺点是需要额外的系统调用,没有内核跟踪那么高效,但聊胜于无,至少这个方法帮助我解决过不少问题。&/p&&br&&p&==会话跟踪==&/p&&p&使用ftrace的另一个缺点是它会话跟踪能力比较差,比如你在网卡上收到一个包,这个包调度到了Socket的队列,然后再送到用户队列。虽然你可以在这些位置人工增加跟踪点,但你不知道这个包属于哪个会话,你也不知道这个包在会话上的时延是什么。这个问题没有非常好的解决方案,关键在于你的跟踪点必须能从这个包上提取出会话有关的信息,比如你能取出这个包的类型和端口号,你就可以从跟踪结果上匹配出整个会话的流程来。&/p&&p&现在网络层的预置事件比较少,我们可以首先考虑是否可以通过函数来跟踪,如果不行,就自己加跟踪点吧。&/p&&br&&p&==其他功能==&/p&&p&ftrace还可以通过uprobe/kprobe设置跟踪点,我对这两个东西不是很信任,所以用得很少,原理也很容易猜出来,所以,读者有兴趣可以自己去看,这里就不深入介绍了。&/p&==总结==&p&本文介绍了ftrace的基本功能和用法。ftrace主要用于跟踪时延和行为,它让我们可以很深入地了解系统的运行行为。是进行Linux性能调优必须掌握的基本工具。&/p&
==介绍== 在我们进一步介绍更多模型分析技巧前,我们先要对基本工具有一些了解。这一篇先介绍ftrace的基本用法。ftrace在内核的Documentation目录下已经有文档了,我这里不是要对那个文档进行翻译,而是要说明这个工具的设计理念和使用策略。细节的东西读者…
&p&==介绍==&/p&&p&ftrace的跟踪方法是一种总体跟踪法,换句话说,你统计了一个事件到下一个事件所有的时间长度,然后把它们放到时间轴上,你可以知道整个系统运行在时间轴上的分布。&/p&&p&这种方法很准确,但跟踪成本很高。所以,我们也需要一种抽样形态的跟踪方法。perf提供的就是这样的跟踪方法。&/p&&p&perf的原理是这样的:每隔一个固定的时间,就在CPU上(每个核上都有)产生一个中断,在中断上看看,当前是哪个pid,哪个函数,然后给对应的pid和函数加一个统计值,这样,我们就知道CPU有百分几的时间在某个pid,或者某个函数上了。这个原理图示如下: &/p&&p&&img data-rawheight=&200& data-rawwidth=&987& src=&/9a1cce72e02b748c02d182d56dc5df40_b.png& class=&origin_image zh-lightbox-thumb& width=&987& data-original=&/9a1cce72e02b748c02d182d56dc5df40_r.png&& 很明显可以看出,这是一种采样的模式,我们预期,运行时间越多的函数,被时钟中断击中的机会越大,从而推测,那个函数(或者pid等)的CPU占用率就越高。&/p&&p&这种方式可以推广到各种事件,比如上一个博文我们介绍的ftrace的事件,你也可以在这个事件发生的时候上来冒个头,看看击中了谁,然后算出分布,我们就知道谁会引发特别多的那个事件了。&/p&&p&当然,如果某个进程运气特别好,它每次都刚好躲过你发起探测的位置,你的统计结果可能就完全是错的了。这是所有采样统计都有可能遇到的问题了。 &br&&/p&&p&还是用我们介绍ftrace时用到的那个sched_switch为例,我们可以用tracepoint作为探测点,每次内核调用这个函数的时候,就上来看看,到底谁引发了这个跟踪点(这个只能用来按pid分类,按函数分类没有用,因为tracepoint的位置是固定的),比如这样:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e sched:sched_switch -s pid
&/code&&/pre&&/div&&img data-rawheight=&600& data-rawwidth=&754& src=&/a3d60ec6cceb2ac81433c9_b.png& class=&origin_image zh-lightbox-thumb& width=&754& data-original=&/a3d60ec6cceb2ac81433c9_r.png&&&p&当然,perf使用更多是CPU的PMU计数器,PMU计数器是大部分CPU都有的功能,它们可以用来统计比如L1 Cache失效的次数,分支预测失败的次数等。PMU可以在这些计数器的计数超过一个特定的值的时候产生一个中断,这个中断,我们可以用和时钟一样的方法,来抽样判断系统中哪个函数发生了最多的Cache失效,分支预测失效等。&/p&&p&下面是一个分支预测失效的跟踪命令和动态结果:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e branch-misses
&/code&&/pre&&/div&&p&&img data-rawheight=&614& data-rawwidth=&809& src=&/29a16c30ba1de309b967ccc_b.png& class=&origin_image zh-lightbox-thumb& width=&809& data-original=&/29a16c30ba1de309b967ccc_r.png&&我们从这里就可以看到系统中哪些函数制造了最多的分支预测失败,我们可能就需要在那些函数中考虑一下有没有可能塞进去几个likely()/unlikely()这样的宏了。 &br&&/p&&p&而且读者应该也注意到了,perf比起ftrace来说,最大的好处是它可以直接跟踪到整个系统的所有程序(而不仅仅是内核),所以perf通常是我们分析的第一步,我们先看到整个系统的outline,然后才会进去看具体的调度,时延等问题。而且perf本身也告诉你调度是否正常了,比如内核调度子系统的函数占用率特别高,我们可能就知道我们需要分析一下调度过程了。&/p&&p&==使用perf==&/p&&p&perf的源代码就是Linux的源代码目录中,因为它在相当程度上和内核是关联的。它会使用Linux内核的头文件。但你编译内核的时候并不会编译它,你必须主动进入tools/perf目录下面,执行make才行。&/p&&p&perf支持很多功能,make的时候它会自动检查这些功能是否存在。比如前面我们用了tracepoint进行事件收集,你就要保证你的系统中有libtracepoint这个库。perf的自由度设计得相当高,很多功能你都可以没有,并不会影响你的基本功能。&/p&&p&由于perf和内核关联,所以理论上,你用哪个内核,就应该使用对应内核的perf,这能保证接口的一致。所以很多类似Ubuntu这样的发行版,你装哪个内核,就要装对应内核的perf命令,而通过的perf命令入其实只是个脚本,根据你当前的perf命令,调用不同perf版本。&/p&&p&但那只是理论上,实践中,其实perf的用户-内核接口相当稳定,很多时候跨版本使用是没有问题的,由于perf的版本还在高速发展中,而且很多发行版的perf版本没有使能很多功能,我在实践中经常直接找最新的内核自己重新编译版本,好像也没有出过什么问题。读者可以有限度参考这个经验。perf也没有很多的路径依赖,你编译完以后连安装都不用,直接用绝对路径调用你编译的版本即可。 &br&&/p&&br&&p&==一般跟踪==&/p&&p&前面我们已经看了几个perf工作的例子了。类似git,docker等多功能工具,perf也是使用perf &子命令&这种模式。所有人首先需要学习的是两个最简单的命令:perf list和perf top。&/p&&p&perf list列出perf可以支持的所有事件。例如这样:&/p&&p&&img data-rawheight=&582& data-rawwidth=&877& src=&/8f1b67292_b.png& class=&origin_image zh-lightbox-thumb& width=&877& data-original=&/8f1b67292_r.png&&旧版本还会列出所有的tracepoint,但那个列表太长了,新版本已经不列这个东西了,读者可以直接到ftrace那边去看就好了。&/p&&p&perf top可以动态收集和更新统计列表,和很多其他perf命令一样。它支持很多参数,但我们关键要记住两个参数:&/p&&p&1. -e 指定跟踪的事件&/p&&p&-e可以指定前面perf list提供的所有事件(包括没有列出的tracepoint),可以用多个-e指定多个事件同时跟踪(但显示的时候会分开显示)&/p&&p&一个-e也可以直接指定多个事件,中间用逗号隔开即可:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo perf top -e branch-misses,cycles
&/code&&/pre&&/div&&p& 事件可以指定后缀,比如我想只跟踪发生在用户态时产生的分支预测失败,我可以这样:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e branch-misses:u,cycles
&/code&&/pre&&/div&&p& 全部事件都有这个要求,我还可以:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e ‘{branch-misses,cycles}:u'
&/code&&/pre&&/div&&p&看看perf-list的手册,会找到更多的后缀,后缀我也用得比较少,读者对这个有兴趣,可以自己深入挖掘一下,如果有什么好的使用经验,希望也可以告诉我。&br&&/p&&br&&p&2. -s 指定按什么参数来进行分类 &/p&&p&-s参数可以不使用,默认会按函数进行分类,但如果你想按pid来分,就需要靠-s来进行分类了。前面我们已经看过这样的例子了。-s也可以指定多个域(用逗号隔开),例如这样:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf top -e 'cycles' -s comm,pid,dso
&/code&&/pre&&/div&&img data-rawheight=&369& data-rawwidth=&768& src=&/c47ea36e6a78cd96ec047c1605cac3e6_b.png& class=&origin_image zh-lightbox-thumb& width=&768& data-original=&/c47ea36e6a78cd96ec047c1605cac3e6_r.png&&&p&perf-top用来理解,体会perf的功能是比较好的,但实践中用得不多,用得比较多的是perf-record和perf-report命令。perf-record用来启动一次跟踪,而perf-report用来输出跟踪结果。&/p&&p&一般的过程是:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf record -e 'cycles' -- myapplication arg1 arg2
sudo perf report
&/code&&/pre&&/div&&p&下面是一个报告的例子:&/p&&p&&img data-rawheight=&416& data-rawwidth=&811& src=&/b9392cada1d_b.png& class=&origin_image zh-lightbox-thumb& width=&811& data-original=&/b9392cada1d_r.png&&perf record在当前目录产生一个perf.data文件(如果这个文件已经存在,旧的文件会被改名为perf.data.old),用来记录过程数据。之后运行的perf report命令会输出统计的结果。perf.data只包含原始数据,perf report需要访问本地的符号表,pid和进城的对应关系等信息来生成报告。所以perf.data不能直接拷贝到其他机器上用的。但你可以通过perf-archive命令把所有这些数据打包,这样移到另一个机器上就可以用了。&/p&&p&请注意,perf-archive是指perf-archive这个命令,不是指perf archive这个子命令。这个命令在编译perf源代码的时候会产生的,如果你的发行版不支持,可以自己编译一个。比较可惜的是,perf-archive备份的代码不能跨平台使用(比如你从arm平台上备份的数据,在x86上是分析不了的)。&br&&/p&&p&perf.data保留前一个版本,可以支持perf diff这个命令,这个命令比较两次两次运行的区别。这样你可以用不同参数运行你的程序,看看运行结果有什么不同,用前面这个cs程序为例,我用4线程对比2线程,就有如下结果:&img data-rawheight=&457& data-rawwidth=&851& src=&/1fa34c856fead98cd9f1e3bbc57c8e29_b.png& class=&origin_image zh-lightbox-thumb& width=&851& data-original=&/1fa34c856fead98cd9f1e3bbc57c8e29_r.png&&我们这里看到,增加线程后,heavy_cal的占比大幅下降了10.70%,其他的变化不大。&br&&/p&&p&perf record不一定用于跟踪自己启动的进城,通过指定pid,可以直接跟踪固定的一组进城。另外,大家应该也注意到了,上面给出的跟踪都仅仅跟踪发生在特定pid的事件。但很多模型,比如一个webserver,你其实关心的是整个系统的性能,网络上会占掉一部分CPU,WebServer本身占一部分CPU,存储子系统也会占据部分的CPU,网络和存储不一定就属于你的WebServer这个pid。所以,对于全系统调优,我们常常给record命令加上-a参数,这样可以跟踪整个系统的性能。比如,还是前面这个cs程序的跟踪,如果我用-a命令去跟踪,得到的结果就和原来很不一样了:&/p&&p&&img data-rawheight=&530& data-rawwidth=&977& src=&/8e98a335ece6fabb59f96ddb_b.png& class=&origin_image zh-lightbox-thumb& width=&977& data-original=&/8e98a335ece6fabb59f96ddb_r.png&&大家注意一下Command那一列。那里已经不仅仅有cs这个进程了。&/p&&p&perf report是一个菜单接口,可以一直展开到每个函数的代码的,例如我们要展开上面这个heavy_cal()函数的具体计数,我们在上面回车,选择代码分析,我们可以得到:&/p&&img data-rawheight=&468& data-rawwidth=&603& src=&/c09106dc4dcbad72e61a021ff6168a40_b.png& class=&origin_image zh-lightbox-thumb& width=&603& data-original=&/c09106dc4dcbad72e61a021ff6168a40_r.png&&&br&&p&perf record还有其他参数可以控制,例如可以通过-c指定事件的触发的事件次数等,那个读者们可以自己看手册。&/p&&p&和perf record/report类似的还有一个perf stat命令,这个命令不计算分布,仅仅进行统计,类似这样:&/p&&p&&img data-rawheight=&304& data-rawwidth=&964& src=&/8a6bb964dafc_b.png& class=&origin_image zh-lightbox-thumb& width=&964& data-original=&/8a6bb964dafc_r.png&& 一般情况下,我觉得这个功能用不上。&br&&/p&&p&==堆栈跟踪==&/p&&p&perf的跟踪有一个错觉需要我们注意,假设我们有一个函数abc(),调用另一个函数def(),在perf的统计中,这两者是分开统计的,就是说,执行def的时间,是不计算abc的时间的,图示如下:&/p&&p&&img data-rawheight=&210& data-rawwidth=&926& src=&/208e1c43d41adeb224b12b0_b.png& class=&origin_image zh-lightbox-thumb& width=&926& data-original=&/208e1c43d41adeb224b12b0_r.png&&这里,abc()被击中5次,def()被击中5次,ghi被击中1次。这会给我们不少错觉,似乎abc的计算压力不大,实际上不是,你要把def和ghi计算在内才行。&/p&&p&但这又带来另一个问题:可能def不仅仅是abc这个函数调用啊,别人也会调用它呢,这种情况,我们怎么知道是谁导致的?&/p&&p&这种情况我们可以启动堆栈跟踪,也就是每次击中的时候,向上回溯一下调用栈,让调用者也会被击中,这样就就更容易看出问题来,这个原理类似这样:&/p&&p&&img data-rawheight=&217& data-rawwidth=&899& src=&/64e0c0e19caaac6e795dc89_b.png& class=&origin_image zh-lightbox-thumb& width=&899& data-original=&/64e0c0e19caaac6e795dc89_r.png&&这种情况,abc击中了11次,def击中了6次,而ghi击中了1次。这样我们可以在一定程度上更容易判断瓶颈的位置。-g命令可以实现这样的跟踪,下面是一个例子:&/p&&p&&img data-rawheight=&425& data-rawwidth=&1077& src=&/54cddcb2d899c330cfc8fa_b.png& class=&origin_image zh-lightbox-thumb& width=&1077& data-original=&/54cddcb2d899c330cfc8fa_r.png&&使用堆栈跟踪后,start_thread上升到前面去了,因为正是它调的heavy_cal。&/p&&p&使用堆栈跟踪要注意的是,堆栈跟踪受扫描深度的限制,太深的堆栈可能回溯不过去,这是有可能影响结果的。&/p&&p&另一个问题是,有些我们从源代码看来是函数调用的,其实在汇编一级并不是函数调用。比如inline函数,宏,都不是函数调用。另外,gcc在很多平台中,会自动把很短的函数变成inline函数,这也不产生函数调用。还有一种是,fastcall函数,通过寄存器传递参数,不会产生调用栈,也有可能不产生调用栈,这个通过调用栈回溯是有可能看不到的。&/p&&p&还有一种更奇葩的情况是,部分平台使用简化的堆栈回溯机制,在堆栈中看见一个地址像是代码段的地址,就认为是调用栈,这些情况都会引起堆栈跟踪上的严重错误。使用者应该对系统的ABI非常熟悉,才能很好驾驭堆栈跟踪这个功能的。&/p&&br&&p&==其他功能==&/p&&p&perf是现在Linux中主推的性能分析工具,几乎每次升级都会有重大更新,连什么benchmarking的功能都做进来了,还有用于专项分析perf-mem这样的命令,用来产生脚本的perf script命令,帮助你用不同的脚本语言分析操作结果。这个用户可以自己看手册去,有前面的基础,这些功能都是很好理解的。&/p&&p&不过特别提一下script命令,虽然它的功能看起来只是用来产生分析脚本的,但我们还常常用来导出原始分析数据,读者可以在perf-record后直接用这个命令来导出结果:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo perf script
&/code&&/pre&&/div&&p&&img data-rawheight=&773& data-rawwidth=&1368& src=&/6af084a5b368b4dcbccb9a957bf81f47_b.png& class=&origin_image zh-lightbox-thumb& width=&1368& data-original=&/6af084a5b368b4dcbccb9a957bf81f47_r.png&&这里列出每个击中点,你爱怎么处理这些击中点的数据,就全凭你的想象力了。&br&&/p&&br&&p&==perf跟踪的缺陷== &/p&&p&前面已经强调过了,perf跟踪是一种采样跟踪,所以我们必须非常小心采样跟踪本身的问题,一旦模型设置不好,整个分析结果可能都是错的。我们要时刻做好这种准备。&/p&&p&我特别提醒的是,你每次看perf report的报告,首先要去注意一下总共收集了多少个点,如果你只有几十个点,你这个报告就可能很不可信了。 &br&&/p&&p&另外,我们要清楚,现代CPU基本上已经不用忙等的方式进入等待了,所以,如果CPU在idle(就是没有任务调度,这种情况只要你的CPU占用率不是100%,必然要发生的),击中任务也会停止,所以,在Idle上是没有点的(你看到Idle函数本身的点并非CPU Idle的点,而是准备进入Idle前后花的时间),所以,perf的统计不能用来让你分析CPU占用率的。ftrace和top等工具才能看CPU占用率,perf是不行的。 &/p&&p&perf还有一个问题是对中断的要求,perf很多事件都依赖中断,但Linux内核是可以关中断的,关中断以后,你就无法击中关中断的点了,你的中断会被延迟到开中断的时候,所以,在这样的平台上,你会看到很多开中断之后的函数被密集击中。但它们是无辜的。但更糟糕的事,如果在关中断的时候,发生了多个事件,由于中断控制器会合并相同的中断,你就会失去多次事件,让你的统计发生错误。&/p&&p&现代的Intel平台,基本上已经把PMU中断都切换为NMI中断了(不可屏蔽),所以前面这个问题不存在。但在大部分ARM/ARM64平台上,这个问题都没有解决,所以看这种平台的报告,都要特别小心,特别是你看到_raw_spin_unlock()一类的函数击中极高,你就要怀疑一下你的测试结果了(注意,这个结果也是能用的,只是看你怎么用)。&/p&&br&&p&==小结==&/p&&p&这一篇我们介绍了perf的基本用法,perf通常是我们进行性能分析的第一步,但这一步,要用好也不是那么容易的,我们首先应该掌握它的原理,然后基于一个分析模型逐步用perf来验证我们的猜测,我们才有可能真正发现问题。 &/p&
==介绍==ftrace的跟踪方法是一种总体跟踪法,换句话说,你统计了一个事件到下一个事件所有的时间长度,然后把它们放到时间轴上,你可以知道整个系统运行在时间轴上的分布。这种方法很准确,但跟踪成本很高。所以,我们也需要一种抽样形态的跟踪方法。perf提…
&p&==战地分析== &br&&/p&&p&性能分析常常是一种战地分析,所以,在我们可以端起咖啡慢慢想怎么进行分析之前,我们要先说说我们在战地上的套路。&/p&&p&战地分析是说在实用环境中发现问题,我们真正需要进行性能分析的场合,通常都没有机会让你反复运行程序,重试等等的。几千万用户,几百万在线,几百万个Socket连接,上T的数据库记录,这些场景通常你回家以后就再也没有机会建出来了。而且客户现场的运维工程师可能很Nice,但通常他们的领导都不Nice。领导说,再弄一个小时,他们再搞不定就让他们回家,我们上备份系统……你就得抱着你的便携,手忙脚乱地滚出人家的实验室。&/p&&p&所以现场的机会很宝贵, 针对不同的现场,你最好手上有一套脚本,上去不管三八二十四,先把什么dmesg啦,dpkg -l啦, /proc/cpu, /proc/ingterrupts, /proc/mem啦,ifconfig啦,ps -ef -L啦,/var/log啦,统统先给他扯一套出来,这样你后面怎么都好分析,现场数据对于后面的分析非常重要。你连那个系统有多少内存都不知道,你分析条毛的性能啊?&/p&&p&第二步就是性能了,我们通常先看top,不要用什么交互模式了,直接用top -b -n 3取一个结果出来再说,至少你可以备份。但这个方法有个缺点,它不会显示每个CPU的分布,我的方法是先用交互模式进去(直接运行top),然后按1,展开CPU,然后W,把当前配置写进去,然后再运行top -b -n 3即可。&/p&&p&对top有谱了,我们大概就能知道问题主要出现在哪里了,如果整个系统都闲得很,通量还是上不去,那就是在什么地方丢包或者入口通道带宽不足了了,开始找丢包点把。&/p&&p&如果只是时延太大,就要回去画整个包的调度流程图,看看包括那些步骤,然后用ftrace跟踪这些步骤吧。&/p&&p&(补充一句,在现场的话,如果要定位的是启动速度问题,读者可以考虑一下使用strace或者ltrace attach来跟踪启动效率的问题)&br&&/p&&p&如果有CPU占用率很高,这时就要靠perf来画像了,先查基于时间的perf分布。看看问题,顺便最好把perf-archive打包带回去。&/p&&p&这样,现场的工作就差不多了,出去和开始请客户

我要回帖

更多关于 此设备可提高性能 的文章

 

随机推荐