Let's Go!

发布新日志

  • Linux 性能监控分析(二) (转)

    2011-12-14 18:41:25



    3.1  vmstat

    # vmstat 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st 0  3 252696   2432    268   7148 3604 2368  3608  2372  288  288  0  0 21 78  1 0  2 253484   2216    228   7104 5368 2976  5372  3036  930  519  0  0  0 100  0 0  1 259252   2616    128   6148 19784 18712 19784 18712 3821 1853  0  1  3 95  1 1  2 260008   2188    144   6824 11824 2584 12664  2584 1347 1174 14  0  0 86  0 2  1 262140   2964    128   5852 24912 17304 24952 17304 4737 2341 86 10  0  0  4 部分参数说明:(1).      swpd,已使用的 SWAP 空间大小,KB 为单位;

    (2).      free,可用的物理内存大小,KB 为单位;

    (3).      buff,物理内存用来缓存读写操作的 buffer 大小,KB 为单位;

    (4).      cache,物理内存用来缓存进程地址空间的 cache 大小,KB 为单位;

    (5).      si,数据从 SWAP 读取到 RAM(swap in)的大小,KB 为单位;

    (6).      so,数据从 RAM 写到 SWAP(swap out)的大小,KB 为单位;

    (7).      bi,磁盘块从文件系统或 SWAP 读取到 RAM(blocks in)的大小,block 为单位;

    (8).      bo,磁盘块从 RAM 写到文件系统或 SWAP(blocks out)的大小,block 为单位;

    上面是一个频繁读写交换区的例子,可以观察到以下几点:

    (1).      物理可用内存 free 基本没什么显著变化,swapd 逐步增加,说明最小可用的内存始终保持在 256MB(物理内存大小) * 10% = 2.56MB 左右,当脏页达到10%的时候(vm.dirty_background_ratio = 10)就开始大量使用 swap;

    (2).      buff 稳步减少说明系统知道内存不够了,kwapd 正在从 buff 那里借用部分内存;

    (3).      kswapd 持续把脏页面写到 swap 交换区(so),并且从 swapd 逐渐增加看出确实如此。根据上面讲的 kswapd 扫描时检查的三件事,如果页面被修改了,但不是被文件系统修改的,把页面写到 swap,所以这里 swapd 持续增加。

    四. IO

           磁盘通常是计算机最慢的子系统,也是最容易出现性能瓶颈的地方,因为磁盘离 CPU 距离最远而且 CPU 访问磁盘要涉及到机械操作,比如转轴、寻轨等。访问硬盘和访问内存之间的速度差别是以数量级来计算的,就像1天和1分钟的差别一样。要监测 IO 性能,有必要了解一下基本原理和 Linux 是如何处理硬盘和内存之间的 IO 的。

    4.1 内存页

    在第三节Memory中提到了内存和硬盘之间的 IO 是以页为单位来进行的,在 Linux 系统上1页的大小为 4K。可以用以下命令查看系统默认的页面大小:

    $ /usr/bin/time -v date

           ...

           Page size (bytes): 4096

           ...

    4.2 缺页中断

           Linux 利用虚拟内存极大的扩展了程序地址空间,使得原来物理内存不能容下的程序也可以通过内存和硬盘之间的不断交换(把暂时不用的内存页交换到硬盘,把需要的内存页从硬盘读到内存)来赢得更多的内存,看起来就像物理内存被扩大了一样。事实上这个过程对程序是完全透明的,程序完全不用理会自己哪一部分、什么时候被交换进内存,一切都有内核的虚拟内存管理来完成。当程序启动的时候,Linux 内核首先检查 CPU 的缓存和物理内存,如果数据已经在内存里就忽略,如果数据不在内存里就引起一个缺页中断(Page Fault),然后从硬盘读取缺页,并把缺页缓存到物理内存里。缺页中断可分为主缺页中断(Major Page Fault)和次缺页中断(Minor Page Fault),要从磁盘读取数据而产生的中断是主缺页中断;数据已经被读入内存并被缓存起来,从内存缓存区中而不是直接从硬盘中读取数据而产生的中断是次缺页中断。

           上面的内存缓存区起到了预读硬盘的作用,内核先在物理内存里寻找缺页,没有的话产生次缺页中断从内存缓存里找,如果还没有发现的话就从硬盘读取。很显然,把多余的内存拿出来做成内存缓存区提高了访问速度,这里还有一个命中率的问题,运气好的话如果每次缺页都能从内存缓存区读取的话将会极大提高性能。要提高命中率的一个简单方法就是增大内存缓存区面积,缓存区越大预存的页面就越多,命中率也会越高。

           下面的 time 命令可以用来查看某程序第一次启动的时候产生了多少主缺页中断和次缺页中断:

    $ /usr/bin/time -v date        ...        Major (requiring I/O) page faults: 1        Minor (reclaiming a frame) page faults: 260        ... 4.3  File Buffer Cache

           从上面的内存缓存区(也叫文件缓存区 File Buffer Cache)读取页比从硬盘读取页要快得多,所以 Linux 内核希望能尽可能产生次缺页中断(从文件缓存区读),并且能尽可能避免主缺页中断(从硬盘读),这样随着次缺页中断的增多,文件缓存区也逐步增大,直到系统只有少量可用物理内存的时候 Linux 才开始释放一些不用的页。我们运行 Linux 一段时间后会发现虽然系统上运行的程序不多,但是可用内存总是很少,这样给大家造成了 Linux 对内存管理很低效的假象,事实上 Linux 把那些暂时不用的物理内存高效的利用起来做预存(内存缓存区)呢。下面是一台 Sun 服务器上的物理内存和文件缓存区的情况:

    $ cat /proc/meminfoMemTotal:      8182776 kBMemFree:       3053808 kBBuffers:        342704 kBCached:        3972748 kB       这台服务器总共有 8GB 物理内存(MemTotal),3GB 左右可用内存(MemFree),343MB 左右用来做磁盘缓存(Buffers),4GB 左右用来做文件缓存区(Cached),可见 Linux 真的用了很多物理内存做 Cache,而且这个缓存区还可以不断增长。

    4.4 页面类型

    Linux 中内存页面有三种类型:

    (1).      Read pages,只读页(或代码页),那些通过主缺页中断从硬盘读取的页面,包括不能修改的静态文件、可执行文件、库文件等。当内核需要它们的时候把它们读到内存中,当内存不足的时候,内核就释放它们到空闲列表,当程序再次需要它们的时候需要通过缺页中断再次读到内存。

    (2).      Dirty pages,脏页,指那些在内存中被修改过的数据页,比如文本文件等。这些文件由 pdflush 负责同步到硬盘,内存不足的时候由 kswapd 和 pdflush 把数据写回硬盘并释放内存。

    (3).      Anonymous pages,匿名页,那些属于某个进程但是又和任何文件无关联,不能被同步到硬盘上,内存不足的时候由 kswapd 负责将它们写到交换分区并释放内存。

    4.5  IO’s Per Second(IOPS)

           每次磁盘 IO 请求都需要一定的时间,和访问内存比起来这个等待时间简直难以忍受。在一台 2001 年的典型 1GHz PC 上,磁盘随机访问一个 word 需要 8,000,000 nanosec = 8 millisec,顺序访问一个 word 需要 200 nanosec;而从内存访问一个 word 只需要 10 nanosec.(数据来自:Teach Yourself Programming in Ten Years)这个硬盘可以提供 125 次 IOPS(1000 ms / 8 ms)。

    4.6  顺序 IO 和 随机 IO

           IO 可分为顺序 IO 和 随机 IO 两种,性能监测前需要弄清楚系统偏向顺序 IO 的应用还是随机 IO 应用。

           (1)顺序 IO 是指同时顺序请求大量数据,比如数据库执行大量的查询、流媒体服务等,顺序 IO 可以同时很快的移动大量数据。可以这样来评估 IOPS 的性能,用每秒读写 IO 字节数除以每秒读写 IOPS 数,rkB/s 除以 r/s,wkB/s 除以 w/s. 下面显示的是连续2秒的 IO 情况,可见每次 IO 写的数据是增加的(45060.00 / 99.00 = 455.15 KB per IO,54272.00 / 112.00 = 484.57 KB per IO)。

           相对随机 IO 而言,顺序 IO 更应该重视每次 IO 的吞吐能力(KB per IO):

    $ iostat -kx 1avg-cpu:  %user   %nice %system %iowait  %steal   %idle           0.00    0.00    2.50   25.25    0.00   72.25 Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %utilsdb       24.00 19995.00 29.00 99.00  4228.00 45060.00   770.12    45.01  539.65   7.80  99.80 avg-cpu:  %user   %nice %system %iowait  %steal   %idle           0.00    0.00    1.00   30.67    0.00   68.33 Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %utilsdb        3.00 12235.00  3.00 112.00   768.00 54272.00   957.22   144.85  576.44   8.70 100.10       (2)随机 IO 是指随机请求数据,其 IO 速度不依赖于数据的大小和排列,依赖于磁盘的每秒能 IO 的次数,比如 Web 服务、Mail 服务等每次请求的数据都很小,随机 IO 每秒同时会有更多的请求数产生,所以磁盘的每秒能 IO 多少次是关键。

    $ iostat -kx 1avg-cpu:  %user   %nice %system %iowait  %steal   %idle           1.75    0.00    0.75    0.25    0.00   97.26 Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %utilsdb        0.00    52.00  0.00 57.00     0.00   436.00    15.30     0.03    0.54   0.23   1.30 avg-cpu:  %user   %nice %system %iowait  %steal   %idle           1.75    0.00    0.75    0.25    0.00   97.24 Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %utilsdb        0.00    56.44  0.00 66.34     0.00   491.09    14.81     0.04    0.54   0.19   1.29       按照上面的公式得出:436.00 / 57.00 = 7.65 KB per IO,491.09 / 66.34 = 7.40 KB per IO. 与顺序 IO 比较发现,随机 IO 的 KB per IO 小到可以忽略不计,可见对于随机 IO 而言重要的是每秒能 IOPS 的次数,而不是每次 IO 的吞吐能力(KB per IO)。

    4.7 SWAP

           当系统没有足够物理内存来应付所有请求的时候就会用到 swap 设备,swap 设备可以是一个文件,也可以是一个磁盘分区。不过要小心的是,使用 swap 的代价非常大。如果系统没有物理内存可用,就会频繁 swapping,如果 swap 设备和程序正要访问的数据在同一个文件系统上,那会碰到严重的 IO 问题,最终导致整个系统迟缓,甚至崩溃。swap 设备和内存之间的 swapping 状况是判断 Linux 系统性能的重要参考,我们已经有很多工具可以用来监测 swap 和 swapping 情况,比如:top、cat /proc/meminfo、vmstat 等:

    $ cat /proc/meminfoMemTotal:      8182776 kBMemFree:       2125476 kBBuffers:        347952 kBCached:        4892024 kBSwapCached:        112 kB...SwapTotal:     4096564 kBSwapFree:      4096424 kB... $ vmstat 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st 1  2 260008   2188    144   6824 11824 2584 12664  2584 1347 1174 14  0  0 86  0 2  1 262140   2964    128   5852 24912 17304 24952 17304 4737 2341 86 10  0  0五. network

           网络的监测是所有 Linux 子系统里面最复杂的,有太多的因素在里面,比如:延迟、阻塞、冲突、丢包等,更糟的是与 Linux 主机相连的路由器、交换机、无线信号都会影响到整体网络并且很难判断是因为 Linux 网络子系统的问题还是别的设备的问题,增加了监测和判断的复杂度。现在我们使用的所有网卡都称为自适应网卡,意思是说能根据网络上的不同网络设备导致的不同网络速度和工作模式进行自动调整。我们可以通过 ethtool 工具来查看网卡的配置和工作模式:

    # /sbin/ethtool eth0Settings for eth0:        Supported ports: [ TP ]        Supported link modes:   10baseT/Half 10baseT/Full                                100baseT/Half 100baseT/Full                                1000baseT/Half 1000baseT/Full        Supports auto-negotiation: Yes        Advertised link modes:  10baseT/Half 10baseT/Full                                100baseT/Half 100baseT/Full                                1000baseT/Half 1000baseT/Full        Advertised auto-negotiation: Yes        Speed: 100Mb/s        Duplex: Full        Port: Twisted Pair        PHYAD: 1        Transceiver: internal        Auto-negotiation: on        Supports Wake-on: g        Wake-on: g        Current message level: 0x000000ff (255)        Link detected: yes       上面给出的例子说明网卡有 10baseT,100baseT 和 1000baseT 三种选择,目前正自适应为 100baseT(Speed: 100Mb/s)。可以通过 ethtool 工具强制网卡工作在 1000baseT 下:

    # /sbin/ethtool -s eth0 speed 1000 duplex full autoneg off 5.1  iptraf

           两台主机之间有网线(或无线)、路由器、交换机等设备,测试两台主机之间的网络性能的一个办法就是在这两个系统之间互发数据并统计结果,看看吞吐量、延迟、速率如何。iptraf 就是一个很好的查看本机网络吞吐量的好工具,支持文字图形界面,很直观。下面图片显示在 100 mbps 速率的网络下这个 Linux 系统的发送传输率有点慢,Outgoing rates 只有 66 mbps.

    # iptraf -d eth05.2  netperf

           netperf 运行在 client/server 模式下,比 iptraf 能更多样化的测试终端的吞吐量。先在服务器端启动 netserver:

    # netserverStarting netserver at port 12865Starting netserver at hostname 0.0.0.0 port 12865 and family AF_UNSPEC然后在客户端测试服务器,执行一次持续10秒的 TCP 测试:

    # netperf -H 172.16.38.36 -l 10TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.38.36 (172.16.38.36) port 0 AF_INETRecv   Send    SendSocket Socket  Message  ElapsedSize   Size    Size     Time     Throughputbytes  bytes   bytes    secs.    10^6bits/sec    87380  16384  16384    10.32      93.68       从以上输出可以看出,网络吞吐量在 94mbps 左右,对于 100mbps 的网络来说这个性能算的上很不错。上面的测试是在服务器和客户端位于同一个局域网,并且局域网是有线网的情况,你也可以试试不同结构、不同速率的网络,比如:网络之间中间多几个路由器、客户端在 wi-fi、VPN 等情况。

           netperf 还可以通过建立一个 TCP 连接并顺序地发送数据包来测试每秒有多少 TCP 请求和响应。下面的输出显示在 TCP requests 使用 2K 大小,responses 使用 32K 的情况下处理速率为每秒243:

     # netperf -t TCP_RR -H 172.16.38.36 -l 10 -- -r 2048,32768TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.38.36 (172.16.38.36) port 0 AF_INETLocal /RemoteSocket Size   Request  Resp.   Elapsed  Trans.Send   Recv   Size     Size    Time     Ratebytes  Bytes  bytes    bytes   secs.    per sec    16384  87380  2048     32768   10.00     243.0316384  87380 5.3  iperf

           iperf 和 netperf 运行方式类似,也是 server/client 模式,先在服务器端启动 iperf:

    # iperf -s -D------------------------------------------------------------Server listening on TCP port 5001TCP window size: 85.3 KByte (default)------------------------------------------------------------Running Iperf Server as a daemonThe Iperf daemon process ID : 5695       然后在客户端对服务器进行测试,客户端先连接到服务器端(172.16.38.36),并在30秒内每隔5秒对服务器和客户端之间的网络进行一次带宽测试和采样:

    # iperf -c 172.16.38.36 -t 30 -i 5------------------------------------------------------------Client connecting to 172.16.38.36, TCP port 5001TCP window size: 16.0 KByte (default)------------------------------------------------------------[  3] local 172.16.39.100 port 49515 connected with 172.16.38.36 port 5001[ ID] Interval       Transfer     Bandwidth[  3]  0.0- 5.0 sec  58.8 MBytes  98.6 Mbits/sec[ ID] Interval       Transfer     Bandwidth[  3]  5.0-10.0 sec  55.0 MBytes  92.3 Mbits/sec[ ID] Interval       Transfer     Bandwidth[  3] 10.0-15.0 sec  55.1 MBytes  92.4 Mbits/sec[ ID] Interval       Transfer     Bandwidth[  3] 15.0-20.0 sec  55.9 MBytes  93.8 Mbits/sec[ ID] Interval       Transfer     Bandwidth[  3] 20.0-25.0 sec  55.4 MBytes  92.9 Mbits/sec[ ID] Interval       Transfer     Bandwidth[  3] 25.0-30.0 sec  55.3 MBytes  92.8 Mbits/sec[ ID] Interval       Transfer     Bandwidth[  3]  0.0-30.0 sec    335 MBytes  93.7 Mbits/sec 5.4  tcpdump 和 tcptrace

           tcmdump 和 tcptrace 提供了一种更细致的分析方法,先用 tcpdump 按要求捕获数据包把结果输出到某一文件,然后再用 tcptrace 分析其文件格式。这个工具组合可以提供一些难以用其他工具发现的信息:

    # /usr/sbin/tcpdump -w network.dmptcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes511942 packets captured511942 packets received by filter0 packets dropped by kernel # tcptrace network.dmp1 arg remaining, starting with 'network.dmp'Ostermann's tcptrace -- version 6.6.7 -- Thu Nov  4, 2004 511677 packets seen, 511487 TCP packets tracedelapsed wallclock time: 0:00:00.510291, 1002714 pkts/sec analyzedtrace file elapsed time: 0:02:35.836372TCP connection info:  1: zaber:54581 - boulder:111 (a2b)                   6>    5<  (complete)  2: zaber:833 - boulder:32774 (c2d)                   6>    5<  (complete)  3: zaber:pcanywherestat - 172.16.39.5:53086 (e2f)    2>    3<  4: zaber:716 - boulder:2049 (g2h)                  347>  257<  5: 172.16.39.100:58029 - zaber:12865 (i2j)           7>    5<  (complete)  6: 172.16.39.100:47592 - zaber:36814 (k2l)        255380> 255378<  (reset)  7: breakpoint:45510 - zaber:7012 (m2n)               9>    5<  (complete)  8: zaber:35813 - boulder:111 (o2p)                   6>    5<  (complete)  9: zaber:837 - boulder:32774 (q2r)                   6>    5<  (complete) 10: breakpoint:45511 - zaber:7012 (s2t)               9>    5<  (complete) 11: zaber:59362 - boulder:111 (u2v)                   6>    5<  (complete) 12: zaber:841 - boulder:32774 (w2x)                   6>    5<  (complete) 13: breakpoint:45512 - zaber:7012 (y2z)               9>    5<  (complete)       tcptrace 功能很强大,还可以通过过滤和布尔表达式来找出有问题的连接,比如,找出转播大于100 segments 的连接:

    # tcptrace -f'rexmit_segs>100' network.dmp如果发现连接 #10 有问题,可以查看关于这个连接的其他信息:

    # tcptrace -o10 network.dmp下面的命令使用 tcptrace 的 slice 模式,程序自动在当前目录创建了一个 slice.dat 文件,这个文件包含了每隔15秒的转播信息:

    # tcptrace -xslice network.dmp # cat slice.datdate                segs    bytes  rexsegs rexbytes      new   active--------------- -------- -------- -------- -------- -------- --------16:58:50.244708    85055  4513418        0        0        6        616:59:05.244708   110921  5882896        0        0        0        216:59:20.244708   126107  6697827        0        0        1        316:59:35.244708   151719  8043597        0        0        0        216:59:50.244708    37296  1980557        0        0        0        317:00:05.244708       67     8828        0        0        2        317:00:20.244708      149    22053        0        0        1        217:00:35.244708       30     4080        0        0        0        117:00:50.244708       39     5688        0        0        0        117:01:05.244708       67     8828        0        0        2        317:01:11.081080       37     4121        0        0        1        3

    详细出处参考:http://www.jb51.net/LINUXjishu/34607.html


  • Linux 性能监控分析(一) (转)

    2011-12-14 18:39:35

    Linux 性能监控分析



    详细出处参考:http://www.jb51.net/LINUXjishu/34607.html


           系统由若干子系统构成,通常修改一个子系统有可能影响到另外一个子系统,甚至会导致整个系统不稳定、崩溃。所以说优化、监测、测试通常是连在一起的,而且是一个循环而且长期的过程,通常监测的子系统有以下这些:

    (1).      CPU

    (2).      Memory

    (3).      IO

    (4).      Network

           这些子系统互相依赖,了解这些子系统的特性,监测这些子系统的性能参数以及及时发现可能会出现的瓶颈对系统优化很有帮助。

    1.1  应用类型

           不同的系统用途也不同,要找到性能瓶颈需要知道系统跑的是什么应用、有些什么特点,比如 web server 对系统的要求肯定和 file server 不一样,所以分清不同系统的应用类型很重要,通常应用可以分为两种类型:

           (1)IO 相关,IO 相关的应用通常用来处理大量数据,需要大量内存和存储,频繁 IO 操作读写数据,而对 CPU 的要求则较少,大部分时候 CPU 都在等待硬盘,比如,数据库服务器、文件服务器等。

           (2)CPU 相关,CPU 相关的应用需要使用大量 CPU,比如高并发的 web/mail 服务器、图像/视频处理、科学计算等都可被视作 CPU 相关的应用。

    看看实际中的例子,第1个是文件服务器拷贝一个大文件时表现出来的特征:

    $ vmstat 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st 0  4    140 1962724 335516 4852308  0    0   388 65024 1442  563  0  2 47 52  0 0  4    140 1961816 335516 4853868  0    0   768 65536 1434  522  0  1 50 48  0 0  4    140 1960788 335516 4855300  0    0   768 48640 1412  573  0  1 50 49  0 0  4    140 1958528 335516 4857280  0    0  1024 65536 1415  521  0  1 41 57  0 0  5    140 1957488 335516 4858884  0    0   768 81412 1504  609  0  2 50 49  0 第2个是 CPU 做大量计算时表现出来的特征:

    $ vmstat 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st 4  0    140 3625096 334256 3266584  0    0     0    16 1054  470 100 0  0  0  0 4  0    140 3625220 334264 3266576  0    0     0    12 1037  448 100 0  0  0  0 4  0    140 3624468 334264 3266580  0    0     0   148 1160  632 100 0  0  0  0 4  0    140 3624468 334264 3266580  0    0     0     0 1078  527 100 0  0  0  0 4  0    140 3624712 334264 3266580  0    0     0    80 1053  501 100 0  0  0  0       上面两个例子最明显的差别就是 id 一栏,代表 CPU 的空闲率,拷贝文件时候 id 维持在 50% 左右,CPU 大量计算的时候 id 基本为 0。

    1.2  底线

           事先建立一个底线,如果性能监测得到的统计数据跨过这条线,我们就可以说这个系统性能差,如果数据能保持在线内我们就说性能好。建立这样底线需要知道一些理论、额外的负载测试和系统管理员多年的经验。如果自己没有多年的经验,有一个简单划底线的办法就是:把这个底线建立在自己对系统的期望上。自己期望这个系统有个什么样的性能,这是一个底线,如果没有达到这个要求就是性能差。

    1.3  监测工具

    工具
     简单介绍
     
    top
     查看进程活动状态以及一些系统状况
     
    vmstat
     查看系统状态、硬件和系统信息等
     
    iostat
     查看CPU 负载,硬盘状况
     
    sar
     综合工具,查看系统状况
     
    mpstat
     查看多处理器状况
     
    netstat
     查看网络状况
     
    iptraf
     实时网络状况监测
     
    tcpdump
     抓取网络数据包,详细分析
     
    mpstat
     查看多处理器状况
     
    tcptrace
     数据包分析工具
     
    netperf
     网络带宽工具
     
    dstat
     综合工具,综合了 vmstat, iostat, ifstat, netstat 等多个信息
     


     

    vmstat 是报告关于进程,内存,IO,CPU活动的一个统计报告。

    在不同的系统中,特别是linux和unix中显示的相关选项会有很大差别。

    我们先以ubuntu为例:

    一般VMSTAT工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ipcpu@ubuntu:~$ vmstat 5 10 
    procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
    r b swpd free buff cache si so bi bo in cs us sy id wa
    1 0 0 6797712 147668 884660 0 0 3 21 162 146 1 1 98 0
    0 0 0 6797696 147668 884660 0 0 0 3 35 37 1 0 99 0
    1 0 0 6797332 147668 884660 0 0 0 24 62 95 1 0 99 0
    0 0 0 6811632 147668 884692 0 0 0 5 25 26 1 0 99 0
    0 0 0 6818360 147668 884704 0 0 0 5 70 265 1 3 96 0
    0 0 0 6817468 147668 884728 0 0 0 316 253 474 3 2 95 0

    procs相关选项: 
    r    在运行队列中等待的进程数
    b    在等待io的进程数

    memoy 
    swapd    现时可用的交换内存(k表示)
    free    空闲的内存(k表示)
    buff    作为buffer cache的内存数量,一般对块设备的读写才需要缓冲。
    cache    作为page cache的内存数量,一般作为文件系统的cache,

    如果cache较大,说明用到cache的文件较多,如果此时IO中bi比较小,说明文件系统效率比较好。

    swap
    si     由内存进入内存交换区数量。
    so    由内存交换区进入内存数量。
    如今的大内存也让swap渐渐淡出了人们的视线,这个不好分析。

    IO
    bi     从块设备读入数据的总量(读磁盘)(每秒kb)。
    bo     向块设备写入数据的总量(写磁盘)(每秒kb)

    system 显示采集间隔内发生的中断数
    in     列表示在某一时间间隔中观测到的每秒设备中断数。
    cs    列表示每秒产生的上下文切换次数。

    如当 cs 比磁盘 I/O 和网络信息包速率高得多,都应进行进一步调查。

    cpu相关状态
    cs[user]    用户进程消耗的CPU时间百分比
    sy[system]    内核进程消耗的CPU时间百分比
    id[idle]    cpu空闲的时间
    wa[wait]    IO等待消耗的CPU时间百分比

    us的值比较高时,说明用户进程消耗的cpu时间多,但是如果长期大于50%,需要考虑优化用户的程序。
    us+sy 大于 80%说明可能存在CPU不足。
    wa超过30%,说明IO等待严重,这可能是磁盘大量随机访问造成的,也可能磁盘或者磁盘访问控制器的带
    宽瓶颈造成的(主要是块操作)。wa长期超过10% 就该考虑了。

    *注意:
    NFS由于是在内核里面运行的,所以NFS活动所占用的cpu时间反映在sy里面。这个数字经常很大的话,就需要注意是否某个内核进程,比如NFS任务比较繁重。如果us和sy同时都比较大的话,就需要考虑将某些用户程序分离到另外的服务器上面,以免互相影响。

    CPU问题现象:
    1) 如果在processes中运行的序列(process r)是连续的大于在系统中的CPU的个数表示系统现在运行比较慢,有多数的进程等待CPU。
    2) 如果r的输出数大于系统中可用CPU个数的4倍的话,则系统面临着CPU短缺的问题,或者是CPU的速率过低,系统中有多数的进程在等待CPU,造成系统中进程运行过慢。
    3) 如果空闲时间(cpu id)持续为0并且系统时间(cpu sy)是用户时间的两倍(cpu us) 系统则面临着CPU资源的短缺。

    解决办法:
    当发生以上问题的时候请先调整应用程序对CPU的占用情况。使得应用程序能够更有效的使用CPU。同时可以考虑增加更多的CPU。
    关于CPU的使用情况还可以结合mpstat,   ps aux top   prstat等等一些相应的命令来综合考虑关于具体的CPU的使用情况,和那些进程在占用大量的CPU时间。一般情况下,应用程序的问题会比较大一些。比 如一些SQL语句不合理等等都会造成这样的现象。

    Unix中的vmstat

    1 
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    freebsd7.2中的vmstat 
    [
    ipcpu@freebsd ~]$ vmstat
    procs memory page disk faults cpu
    r b w avm fre flt re pi po fr sr ad4 in sy cs us sy id
    0 0 0 152M 7448M 131 0 0 0 132 0 0 167 644 860 0 1 99
    [ipcpu@freebsd ~]$  

    AIX 5.3中的vmstat -bash-3.00
    $ vmstat  
    System
    configuration: lcpu=4 mem=1904MB  
    kthr memory page faults cpu
    ----- ----------- ------------------------ ------------ -----------
    r b avm fre re pi po fr sr cy in sy cs us sy id wa
    1 1 308679 55310 0 0 0 0 1 0 94 4501 333 1 1 98 0

    -
    bash-3.00$  
    SunOS 5.10的vmstat   -
    bash-3.00$ vmstat
    kthr memory page disk faults cpu
    r b w swap free re mf pi po fr de sr s0 s1 s2 s5 in sy cs us sy id
    0 0 0 2584720 2665344 3 10 1 0 0 0 0 0 0 0 0 495 249 235 0 0 99 -bash-3.00$

    这里稍微介绍下page相关选项:
    re    回收的页面
    mf    非严重错误的页面
    pi    进入页面数(k表示)
    po    出页面数(k表示)
    fr    空余的页面数(k表示)
    de    提前读入的页面中的未命中数
    sr    通过时钟算法扫描的页面

    Tips小提示Linux的块设备和字符设备
    他们根本区别在于是否可以被随机访问——换句话说就是,能否在访问设备时随意地从一个位置跳转到另一个位置。

    举个例子,键盘这种设备提供的就是一个数据流,只能按照你敲击的字母顺序进行录入,所以键盘就是一种典型的字符设备。

    硬盘设备的驱动可能要求读取磁盘上任意块的内容,然后又转去读取别的块的内容,而被读取的块在磁盘上位置不一定要连续,所以说硬盘可以被随机访问,而不是以流的方式被访问,显然它是一个块设备。


      

     

    二. CPU

           CPU 的占用主要取决于什么样的资源正在 CPU 上面运行,比如拷贝一个文件通常占用较少 CPU,因为大部分工作是由 DMA(Direct Memory Access)完成,只是在完成拷贝以后给一个中断让 CPU 知道拷贝已经完成;科学计算通常占用较多的 CPU,大部分计算工作都需要在 CPU 上完成,内存、硬盘等子系统只做暂时的数据存储工作。要想监测和理解 CPU 的性能需要知道一些的操作系统的基本知识,比如:中断、进程调度、进程上下文切换、可运行队列等。    这里用个例子来简单介绍一下这些概念和他们的关系,CPU每时每刻都有工作在做(进程、线程)并且自己有一张工作清单(可运行队列),由老板(进程调度)来决定他该干什么,他需要和老板沟通以便得到老板的想法并及时调整自己的工作(上下文切换),部分工作做完以后还需要及时向老板汇报(中断),所以打工仔(CPU)除了做自己该做的工作以外,还有大量时间和精力花在沟通和汇报上。

           CPU 也是一种硬件资源,和任何其他硬件设备一样也需要驱动和管理程序才能使用,我们可以把内核的进程调度看作是 CPU 的管理程序,用来管理和分配 CPU 资源,合理安排进程抢占 CPU,并决定哪个进程该使用 CPU、哪个进程该等待。操作系统内核里的进程调度主要用来调度两类资源:进程(或线程)和中断,进程调度给不同的资源分配了不同的优先级,优先级最高的是硬件中断,其次是内核(系统)进程,最后是用户进程。每个 CPU 都维护着一个可运行队列,用来存放那些可运行的线程。线程要么在睡眠状态(blocked 正在等待 IO)要么在可运行状态,如果 CPU 当前负载太高而新的请求不断,就会出现进程调度暂时应付不过来的情况,这个时候就不得不把线程暂时放到可运行队列里。

    可以从以下几个方面监控CPU的信息:

    (1)中断;

    (2)上下文切换;

    (3)可运行队列;

    (4)CPU 利用率。

    2.1 底线

    通常我们期望我们的系统能到达以下目标:

           (1)CPU 利用率,如果 CPU 有 100% 利用率,那么应该到达这样一个平衡:65%-70% User Time,30%-35% System Time,0%-5% Idle Time;

           (2)上下文切换,上下文切换应该和 CPU 利用率联系起来看,如果能保持上面的 CPU 利用率平衡,大量的上下文切换是可以接受的;

           (3)可运行队列,每个可运行队列不应该有超过1-3个线程(每处理器),比如:双处理器系统的可运行队列里不应该超过6个线程。

    2.2  vmstat

           vmstat 是个查看系统整体性能的小工具,小巧、即使在很 heavy 的情况下也运行良好,并且可以用时间间隔采集得到连续的性能数据。

    $ vmstat 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st 2  1    140 2787980 336304 3531996  0    0     0   128 1166 5033  3  3 70 25  0 0  1    140 2788296 336304 3531996  0    0     0     0 1194 5605  3  3 69 25  0 0  1    140 2788436 336304 3531996  0    0     0     0 1249 8036  5  4 67 25  0 0  1    140 2782688 336304 3531996  0    0     0     0 1333 7792  6  6 64 25  0 3  1    140 2779292 336304 3531992  0    0     0    28 1323 7087  4  5 67 25  0参数介绍:

    (1).      r,可运行队列的线程数,这些线程都是可运行状态,只不过 CPU 暂时不可用;

    (2).      b,被 blocked 的进程数,正在等待 IO 请求;

    (3).      in,被处理过的中断数

    (4).      cs,系统上正在做上下文切换的数目

    (5).      us,用户占用 CPU 的百分比

    (6).      sys,内核和中断占用 CPU 的百分比

    (7).      wa,所有可运行的线程被 blocked 以后都在等待 IO,这时候 CPU 空闲的百分比

    (8).      id,CPU 完全空闲的百分比

    举两个现实中的例子来实际分析一下:

    $ vmstat 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st 4  0    140 2915476 341288 3951700  0    0     0     0 1057  523 19 81  0  0  0 4  0    140 2915724 341296 3951700  0    0     0     0 1048  546 19 81  0  0  0 4  0    140 2915848 341296 3951700  0    0     0     0 1044  514 18 82  0  0  0 4  0    140 2915848 341296 3951700  0    0     0    24 1044  564 20 80  0  0  0 4  0    140 2915848 341296 3951700  0    0     0     0 1060  546 18 82  0  0  0从上面的数据可以看出几点:

    (1).      interrupts(in)非常高,context switch(cs)比较低,说明这个 CPU 一直在不停的请求资源;

    (2).      user time(us)一直保持在 80% 以上,而且上下文切换较低(cs),说明某个进程可能一直霸占着 CPU;

    (3).      run queue(r)刚好在4个。

    $ vmstat 1procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------ r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st14  0    140 2904316 341912 3952308  0    0     0   460 1106 9593 36 64  1  0  017  0    140 2903492 341912 3951780  0    0     0     0 1037 9614 35 65  1  0  020  0    140 2902016 341912 3952000  0    0     0     0 1046 9739 35 64  1  0  017  0    140 2903904 341912 3951888  0    0     0    76 1044 9879 37 63  0  0  016  0    140 2904580 341912 3952108  0    0     0     0 1055 9808 34 65  1  0  0从上面的数据可以看出几点:

    (1).      context switch(cs)比 interrupts(in)要高得多,说明内核不得不来回切换进程;

    (2).      进一步观察发现 system time(sy)很高而 user time(us)很低,而且加上高频度的上下文切换(cs),说明正在运行的应用程序调用了大量的系统调用(system call);

    (3).      run queue(r)在14个线程以上,按照这个测试机器的硬件配置(四核),应该保持在12个以内。

    我上午CPU 100%时的信息:

    top - 11:49:08 up 50 days, 22:25,  6 users,  load average: 59.79, 59.98, 60.50

    Tasks: 200 total,  61 running, 139 sleeping,   0 stopped,   0 zombie

    Cpu0  : 26.5%us, 73.5%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

    Cpu1  : 25.0%us, 75.0%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

    Mem:   1939780k total,  1744412k used,   195368k free,    95704k buffers

    Swap:  4401800k total,   662836k used,  3738964k free,   811124k cached

    [root@localhost ~]# vmstat 2 10

    procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------

     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st

    58  1 662836 195988  95428 810740    0    0     4   106    4    1 23  4 72  1  0

    59  1 662836 195988  95448 810732    0    0     0   128  235  221 28 72  0  0  0

    59  1 662836 195988  95448 810768    0    0     0     0  216  209 28 72  0  0  0

    2.3  mpstat

           mpstat 和 vmstat 类似,不同的是 mpstat 可以输出多个处理器的数据。

    注意:需要安装sysstat 包后才有这个命令,可以使用yum安装:

           #yum install sysstat

           sysstat 包含iostat、mpstat、sar、命令。

    [root@localhost gmail]# export LANG=en_US[root@localhost gmail]# mpstat -P ALL    Linux 2.6.18-8.el5xen (localhost.localdomain)   02/21/2011 10:20:16 PM  CPU   %user   %nice    %sys %iowait    %irq   %soft  %steal   %idle    intr/s10:20:16 PM  all   11.49    0.00    2.58    1.04    0.01    0.13    0.01   84.74    314.6110:20:16 PM    0   15.73    0.00    2.56    0.55    0.02    0.23    0.01   80.89    241.0910:20:16 PM    1    7.25    0.00    2.60    1.53    0.00    0.02    0.01   88.59     73.52[root@localhost gmail]# mpstat -P ALL 1Linux 2.6.18-8.el5xen (localhost.localdomain)   02/21/2011 10:20:18 PM  CPU   %user   %nice    %sys %iowait    %irq   %soft  %steal   %idle    intr/s10:20:19 PM  all    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00    136.6310:20:19 PM    0    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00     86.1410:20:19 PM    1    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00     50.50 10:20:19 PM  CPU   %user   %nice    %sys %iowait    %irq   %soft  %steal   %idle    intr/s10:20:20 PM  all    0.00    0.00    0.00    0.47    0.00    0.00    0.00   99.53    105.0010:20:20 PM    0    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00     79.0010:20:20 PM    1    0.00    0.00    0.00    0.90    0.00    0.00    0.00   99.10     26.00 2.4  ps

    查看某个程序、进程占用了多少 CPU 资源:

    [root@localhost gmail]#  while :; do ps -eo pid,ni,pri,pcpu,psr,comm | grep 'oracle'; sleep 1; done  PID  NI PRI %CPU PSR COMMAND 3668   0  24  0.0   0 oracle 3670   0  21  0.0   0 oracle 3672   0  24  0.0   0 oracle 3674   0  23  0.0   0 oracle 3676   0  24  0.0   1 oracle 3678   0  23  0.0   0 oracle 3680   0  21  0.0   1 oracle 3682   0  24  0.0   1 oracle 3684   0  24  0.0   0 oracle 3686   0  21  0.0   0 oracle三. Memory

           这里的讲到的 “内存” 包括物理内存和虚拟内存,虚拟内存(Virtual Memory)把计算机的内存空间扩展到硬盘,物理内存(RAM)和硬盘的一部分空间(SWAP)组合在一起作为虚拟内存为计算机提供了一个连贯的虚拟内存空间,好处是我们拥有的内存 ”变多了“,可以运行更多、更大的程序,坏处是把部分硬盘当内存用整体性能受到影响,硬盘读写速度要比内存慢几个数量级,并且 RAM 和 SWAP之间的交换增加了系统的负担。

           在操作系统里,虚拟内存被分成页,在 x86 系统上每个页大小是 4KB。 Linux 内核读写虚拟内存是以 “页” 为单位操作的,把内存转移到硬盘交换空间(SWAP)和从交换空间读取到内存的时候都是按页来读写的。内存和 SWAP 的这种交换过程称为页面交换(Paging),值得注意的是 paging 和 swapping 是两个完全不同的概念,国内很多参考书把这两个概念混为一谈,swapping 也翻译成交换,在操作系统里是指把某程序完全交换到硬盘以腾出内存给新程序使用,和 paging 只交换程序的部分(页面)是两个不同的概念。纯粹的 swapping 在现代操作系统中已经很难看到了,因为把整个程序交换到硬盘的办法既耗时又费力而且没必要,现代操作系统基本都是 paging 或者 paging/swapping 混合,swapping 最初是在 Unix system V 上实现的。

    在这里只介绍和性能监测有关的两个内核进程:kswapd 和 pdflush。

           (1)kswapd daemon 用来检查 pages_high 和 pages_low,如果可用内存少于 pages_low,kswapd 就开始扫描并试图释放 32个页面,并且重复扫描释放的过程直到可用内存大于 pages_high 为止。

           扫描的时候检查3件事:

           1)如果页面没有修改,把页放到可用内存列表里;

           2)如果页面被文件系统修改,把页面内容写到磁盘上;

           3)如果页面被修改了,但不是被文件系统修改的,把页面写到交换空间。

           (2)pdflush daemon 用来同步文件相关的内存页面,把内存页面及时同步到硬盘上。比如打开一个文件,文件被导入到内存里,对文件做了修改后并保存后,内核并不马上保存文件到硬盘,由 pdflush 决定什么时候把相应页面写入硬盘,这由一个内核参数 vm.dirty_background_ratio 来控制,比如下面的参数显示脏页面(dirty pages)达到所有内存页面10%的时候开始写入硬盘。

    # /sbin/sysctl -n vm.dirty_background_ratio

    10

    3.1  vmstat


  • 结合netstat和awk命令来统计网络连接数 (转)

    2011-12-14 18:38:40

    结合netstat和awk命令来统计网络连接数



    From: http://hi.baidu.com/thinkinginlamp/blog/item/afbcab64b1ad81f3f6365453.html

    netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'

    会得到类似下面的结果,具体数字会有所不同:

    LAST_ACK 1
    SYN_RECV 14
    ESTABLISHED 79
    FIN_WAIT1 28
    FIN_WAIT2 3
    CLOSING 5
    TIME_WAIT 1669

    状态:描述
    CLOSED:无连接是活动的或正在进行
    LISTEN:服务器在等待进入呼叫
    SYN_RECV:一个连接请求已经到达,等待确认
    SYN_SENT:应用已经开始,打开一个连接
    ESTABLISHED:正常数据传输状态
    FIN_WAIT1:应用说它已经完成
    FIN_WAIT2:另一边已同意释放
    ITMED_WAIT:等待所有分组死掉
    CLOSING:两边同时尝试关闭
    TIME_WAIT:另一边已初始化一个释放
    LAST_ACK:等待所有分组死掉

    也就是说,这条命令可以把当前系统的网络连接状态分类汇总。

    下面解释一下为啥要这样写:

    一个简单的管道符连接了netstat和awk命令。

    ------------------------------------------------------------------

    先来看看netstat:

    netstat -n

    Active Internet connections (w/o servers)
    Proto Recv-Q Send-Q Local Address Foreign Address State
    tcp 0 0 123.123.123.123:80 234.234.234.234:12345 TIME_WAIT

    你实际执行这条命令的时候,可能会得到成千上万条类似上面的记录,不过我们就拿其中的一条就足够了。

    ------------------------------------------------------------------

    再来看看awk:

    /^tcp/
    滤出tcp开头的记录,屏蔽udp, socket等无关记录。

    state[]
    相当于定义了一个名叫state的数组

    NF
    表示记录的字段数,如上所示的记录,NF等于6

    $NF
    表示某个字段的值,如上所示的记录,$NF也就是$6,表示第6个字段的值,也就是TIME_WAIT

    state[$NF]
    表示数组元素的值,如上所示的记录,就是state[TIME_WAIT]状态的连接数

    ++state[$NF]
    表示把某个数加一,如上所示的记录,就是把state[TIME_WAIT]状态的连接数加一

    END
    表示在最后阶段要执行的命令

    for(key in state)
    遍历数组

    print key,"\t",state[key]
    打印数组的键和值,中间用\t制表符分割,美化一下。

    如发现系统存在大量TIME_WAIT状态的连接,通过调整内核参数解决,
    vim /etc/sysctl.conf
    编辑文件,加入以下内容:

    1.net.ipv4.tcp_syncookies = 1
    2.net.ipv4.tcp_tw_reuse = 1
    3.net.ipv4.tcp_tw_recycle = 1
    4.net.ipv4.tcp_fin_timeout = 30

    然后执行 /sbin/sysctl -p 让参数生效。

    net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
    net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
    net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
    net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间

    下面附上TIME_WAIT状态的意义:

    客户端与服务器端建立TCP/IP连接后关闭SOCKET后,服务器端连接的端口
    状态为TIME_WAIT

    是不是所有执行主动关闭的socket都会进入TIME_WAIT状态呢?
    有没有什么情况使主动关闭的socket直接进入CLOSED状态呢?

    主动关闭的一方在发送最后一个 ack 后
    就会进入 TIME_WAIT 状态 停留2MSL(max segment lifetime)时间
    这个是TCP/IP必不可少的,也就是“解决”不了的。

    也就是TCP/IP设计者本来是这么设计的
    主要有两个原因
    1。防止上一次连接中的包,迷路后重新出现,影响新连接
    (经过2MSL,上一次连接中所有的重复包都会消失)
    2。可靠的关闭TCP连接
    在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发
    fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以
    主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。

    TIME_WAIT 并不会占用很大资源的,除非受到攻击。

    还有,如果一方 send 或 recv 超时,就会直接进入 CLOSED 状态

    netstat -an | grep SYN | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | more

    1. netstat -tna | cut -b 49- |grep TIME_WAIT | sort
      取出目前所有 TIME_WAIT 的连接 IP ( 排序过 )

    2.   net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
        net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
        net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
        net.ipv4.tcp_fin_timeout = 30 表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。
        net.ipv4.tcp_keepalive_time = 1200 表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
        net.ipv4.ip_local_port_range = 1024 65000 表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。
        net.ipv4.tcp_max_syn_backlog = 8192 表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
        net.ipv4.tcp_max_tw_buckets = 5000 表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000,改 为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于Squid,效果却不大。此项参 数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。

       

       

      在怀疑有Dos攻击的时候,可以输入

      1 netstat -na | grep :80 |awk '{print $5}'|awk -F '::ffff:' '{print $2}' grep ':' awk -F: '{print $1}' sort uniq -c |sort -r | awk -F' ' '{if ($1 > 50) print $2}' sed 's/^.*$/iptables -I firewall 1 -p tcp -s & --dport 80 --syn -j REJECT/' | sh

      先把冲击量最大的前50个IP给封了.

      还可以加几个例外的白名单IP

      1 netstat -na | grep :80 |awk '{print $5}'|awk -F '::ffff:' '{print $2}' grep ':' awk -F: '{print $1}' sort uniq -c |sort -r | awk -F' ' '{if ($1 > 50) print $2}' grep -v xxx.xxx.xxx.xxx | sed 's/^.*$/iptables -I RH-Firewall-1-INPUT 1 -p tcp -m tcp -s & --dport 80 --syn -j REJECT/' | sh
      以上的命令还没有实际考证过, 放在这里做参考.


      转自:
      http://www.cnblogs.com/derekchen/archive/2011/02/26/1965839.html
  • web管理常用命令二 (转)

    2011-12-14 18:37:33

    web管理常用命令二


    原文链接:http://bbs.linuxtone.org/thread-16-1-1.html IT运维专家网--"自由平等,互助分享!" 
    作者:NetSeek

    1.删除0字节文件
    引用
    find -type f -size 0 -exec rm -rf {} \;

    2.查看进程
    按内存从大到小排列
    引用
    ps -e  -o "%C  : %p : %z : %a"|sort -k5 -nr

    3.按cpu利用率从大到小排列
    引用
    ps -e  -o "%C  : %p : %z : %a"|sort  -nr

    4.打印说cache里的URL
    引用
    grep -r -a  jpg /data/cache/* | strings | grep "http:" | awk -F'http:' '{print "http:"$2;}'

    5.查看http的并发请求数及其TCP连接状态:
    引用
    netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

    6.sed 替换的使用
    引用
    sed -i '/Root/s/no/yes/' /etc/ssh/sshd_config  sed在这个文里Root的一行,匹配Root一行,将no替换成yes.

    7.如何杀掉mysql进程:
    引用
    (1):ps aux|grep mysql|grep -v grep|awk '{print $2}'|xargs kill -9   (从中了解到awk的用途)
    (2):pgrep mysql |xargs kill -9
    (3):killall -TERM mysqld
    (4):kill -9 `cat /usr/local/apache2/logs/httpd.pid`  试试查杀进程PID

    8.显示运行3级别开启的服务:
    引用
    ls /etc/rc3.d/S* |cut -c 15-  (从中了解到cut的用途,截取数据)

    9.如何在编写SHELL显示多个信息,用EOF
    引用
    cat << EOF
    +--------------------------------------------------------------+
    |         === Welcome to www.6curl.com===                   |
    +--------------------------------------------------------------+
    EOF

    10. for 的巧用(如给mysql建软链接)
    引用
    cd /usr/local/mysql/bin
    for i in *
    do ln /usr/local/mysql/bin/$i /usr/bin/$i
    done

    11. 取IP地址:
    引用
    (1):ifconfig eth0|sed -n '2p'|awk '{print $2}'|cut -c 6-30
    (2):ifconfig eth0 |grep "inet addr:" |awk '{print $2}'|cut -c 6-
    (3):ifconfig  | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'
    (4):ifconfig eth0 | sed -n '/inet /{s/.*addr://;s/ .*//;p}'
    Perl实现获取IP的方法:
    ifconfig -a | perl -ne 'if ( m/^\s*inet (?:addr:)?([\d.]+).*?cast/ ) { print qq($1\n); exit 0; }'

    12.内存的大小:
    引用
    free -m |grep "Mem" | awk '{print $2}'

    13.
    引用
    netstat -an -t | grep ":80" | grep ESTABLISHED | awk '{printf "%s %s\n",$5,$6}' | sort

    14.查看Apache的并发请求数及其TCP连接状态:
    引用
    netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

    15.因为同事要统计一下服务器下面所有的jpg的文件的大小,写了个shell给他来统计.原来用xargs实现,但他一次处理一部分,搞的有多个总和....,下面的命令就能解决啦.
    引用
    find / -name *.jpg -exec wc -c {} \;|awk '{print $1}'|awk '{a+=$1}END{print a}'

    16  CPU负载
    引用
    cat /proc/loadavg
    检查前三个输出值是否超过了系统逻辑CPU的4倍.
    cat /proc/cpuinfo |grep -c processor (多核CPU)

    18  CPU负载,检查%idle是否过低(比如小于5%)
    引用
    #mpstat 1 1

    19  内存空间  
    引用
    # free
    检查free值是否过低  也可以用 # cat /proc/meminfo

    20  swap空间
    引用
    # free
    检查swap used值是否过高  如果swap used值过高,进一步检查swap动作是否频繁:
    # vmstat 1 5
    观察si和so值是否较大

    21  磁盘空间
    # df -h
    引用
    检查是否有分区使用率(Use%)过高(比如超过90%)  如发现某个分区空间接近用尽,可以进入该分区的挂载点,用以下命令找出占用空间最多的文件或目录:
    # du -cks * | sort -rn | head -n 10

    22  磁盘I/O负载  
    引用
    # iostat -x 1 2
    检查I/O使用率(%util)是否超过100%

    23  网络负载
    引用
    # sar -n DEV
    检查网络流量(rxbyt/s, txbyt/s)是否过高

    24  网络错误  
    引用
    # netstat -i
    检查是否有网络错误(drop fifo colls carrier)  
    cat /proc/net/dev

    25 网络连接数目
    引用
    # netstat -an | grep -E “^(tcp)” | cut -c 68- | sort | uniq -c | sort -n

    26  进程总数  
    引用
    # ps aux | wc -l
    检查进程个数是否正常 (比如超过250)

    27  可运行进程数目
    引用
    # vmwtat 1 5
    列给出的是可运行进程的数目,检查其是否超过系统逻辑CPU的4倍

    28  进程  
    引用
    # top -id 1
    观察是否有异常进程出现

    29  网络状态
    引用
    检查DNS, 网关等是否可以正常连通

    30  用户
    引用
    # who | wc -l
    检查登录用户是否过多 (比如超过50个)  
    也可以用命令:# uptime

    31  系统日志
    引用
    # cat /var/log/rflogview/*errors
    # grep -i error /var/log/messages
    # grep -i fail /var/log/messages
    # egrep -i 'error|warn' /var/log/messages 查看系统异常

    32  核心日志  
    # dmesg
    检查是否有异常错误记录
    33  系统时间
    # date
    检查系统时间是否正确
    34  打开文件数目
    引用
    # lsof | wc -l
    检查打开文件总数是否过多

    35  日志
    引用
    # logwatch –print  配置/etc/log.d/logwatch.conf,将 Mailto 设置为自己的email 地址,启动mail服务 (sendmail或者postfix),这样就可以每天收到日志报告了。
    缺省logwatch只报告昨天的日志,可以用# logwatch –print –range all 获得所有的日志分析结果。
    可以用# logwatch –print –detail high 获得更具体的日志分析结果(而不仅仅是出错日志)。

    36.杀掉80端口相关的进程
    引用
    lsof -i :80|grep -v "PID"|awk '{print "kill -9",$2}'|sh

    37.清除僵死进程。
    引用
    ps -eal | awk '{ if ($2 == "Z") {print $4}}' | kill -9

    38.tcpdump 抓包 ,用来防止80端口被人攻击时可以分析数据
    引用
    # tcpdump -c 10000 -i eth0 -n dst port 80 > /root/pkts

    39.然后检查IP的重复数 并从小到大排序 注意 "-t\ +0"  中间是两个空格
    引用
    # less pkts | awk {'printf $3"\n"'} | cut -d. -f 1-4 | sort | uniq -c | awk {'printf $1" "$2"\n"'} | sort -n -t\ +0

    40.查看有多少个活动的php-cgi进程
    引用
    netstat -anp | grep php-cgi | grep ^tcp | wc -l

    41.利用iptables对应简单攻击
    引用
    netstat -an | grep -v LISTEN | awk ‘{print $5}’ |grep -v 127.0.0.1|grep -v 本机ip|sed  “s/::ffff://g”|awk ‘BEGIN { FS=”:” } { Num[$1]++ } END { for(i in Num) if(Num>8) { print i} }’ |grep ‘[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}’|  xargs -i[] iptables -I INPUT -s [] -j DROP


    ps: Num>8部分设定值为阀值,这条句子会自动将netstat -an 中查到的来自同一IP的超过一定量的连接的列入禁止范围。   基中本机ip改成你的服务器的ip地址
    42. 怎样知道某个进程在哪个CPU上运行?
    引用
    # ps -eo pid,args,psr

    43. 查看硬件制造商
    引用
    dmidecode -s system-product-name


    转自:http://www.cnblogs.com/derekchen/archive/2011/02/26/1965834.html



  • web管理常用命令一 (转)

    2011-12-14 18:36:36

    web管理常用命令一


    实时查看正在执行的sql语句
    #/usr/sbin/tcpdump -i eth0 -s 0 -l -w - dst port 3306 | strings | egrep -i 'SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|CALL'
     
    查看http连接
    netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"t",state[key]}'
     
    查看SYN状态的http连接
    netstat -an | grep SYN | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | more
     
    查看TIME_WAIT状态的http连接
    netstat -tna | cut -b 49- |grep TIME_WAIT | sort |more
    netstat -an | grep TIME_WAIT | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | more
     
    查看ESTABLISHED状态的http连接
    netstat -an | grep ESTABLISHED | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | morenetstat -an | grep ":80" | grep ESTABLISHED | sort | more
    批量kill进程
    ps -efww|grep sqlr-listener|grep -v grep|cut -c 9-15|xargs kill -9
     
    查看活动的php-cgi连接数
    netstat -anpo|grep php-cgi|wc -l

     

     

    判断CC攻击 netstat命令详解,快速找出有问题的ip

     

     

    网站排障分析常用的命令】
    系统连接状态篇:
    1.查看TCP连接状态
    netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn 
    netstat -n | awk '/^tcp/ {++S[$NF]};END {for(a in S) print a, S[a]}' 或
    netstat -n | awk '/^tcp/ {++state[$NF]}; END {for(key in state) print key,"\t",state[key]}'
    netstat -n | awk '/^tcp/ {++arr[$NF]};END {for(k in arr) print k,"\t",arr[k]}'
    netstat -n |awk '/^tcp/ {print $NF}'|sort|uniq -c|sort -rn 
    netstat -ant | awk '{print $NF}' | grep -v '[a-z]' | sort | uniq -c
    2.查找请求数请20个IP(常用于查找攻来源):
    netstat -anlp|grep 80|grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20
    netstat -ant |awk '/:80/{split($5,ip,":");++A[ip[1]]}END{for(i in A) print A[i],i}' |sort -rn|head -n20
    3.用tcpdump嗅探80端口的访问看看谁最高
    tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -nr |head -20
    4.查找较多time_wait连接
    netstat -n|grep TIME_WAIT|awk '{print $5}'|sort|uniq -c|sort -rn|head -n20
    5.找查较多的SYN连接
    netstat -an | grep SYN | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | more
    6.根据端口列进程
    netstat -ntlp | grep 80 | awk '{print $7}' | cut -d/ -f1
    7.计算httpd占用内存的平均数
    ps aux|grep -v grep|awk '/httpd/{sum+=$6;n++};END{print sum/n}'
    网站日志分析篇1(Apache):
    1.获得访问前10位的ip地址
    cat access.log|awk '{print $1}'|sort|uniq -c|sort -nr|head -10
    cat access.log|awk '{counts[$(11)]+=1}; END {for(url in counts) print counts[url], url}'
    2.访问次数最多的文件或页面,取前20
    cat access.log|awk '{print $11}'|sort|uniq -c|sort -nr|head -20
    3.列出传输最大的几个exe文件(分析下载站的时候常用)
    cat access.log |awk '($7~/\.exe/){print $10 " " $1 " " $4 " " $7}'|sort -nr|head -20
    4.列出输出大于200000byte(约200kb)的exe文件以及对应文件发生次数
    cat access.log |awk '($10 > 200000 && $7~/\.exe/){print $7}'|sort -n|uniq -c|sort -nr|head -100
    5.如果日志最后一列记录的是页面文件传输时间,则有列出到客户端最耗时的页面
    cat access.log |awk  '($7~/\.php/){print $NF " " $1 " " $4 " " $7}'|sort -nr|head -100
    6.列出最最耗时的页面(超过60秒的)的以及对应页面发生次数
    cat access.log |awk '($NF > 60 && $7~/\.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100
    7.列出传输时间超过 30 秒的文件
    cat access.log |awk '($NF > 30){print $7}'|sort -n|uniq -c|sort -nr|head -20
    8.统计网站流量(G)
    cat access.log |awk '{sum+=$10} END {print sum/1024/1024/1024}'
    9.统计404的连接
    awk '($9 ~/404/)' access.log | awk '{print $9,$7}' | sort
    10. 统计http status.
    cat access.log |awk '{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}'
    cat access.log |awk '{print $9}'|sort|uniq -c|sort -rn
    10.蜘蛛分析
    查看是哪些蜘蛛在抓取内容。
    /usr/sbin/tcpdump -i eth0 -l -s 0 -w - dst port 80 | strings | grep -i user-agent | grep -i -E 'bot|crawler|slurp|spider'

    网站日分析2(Squid篇)

    2.按域统计流量
    zcat squid_access.log.tar.gz| awk '{print $10,$7}' |awk 'BEGIN{FS="[ /]"}{trfc[$4]+=$1}END{for(domain in trfc){printf "%s\t%d\n",domain,trfc[domain]}}'
    效率更高的perl版本请到此下载:http://docs.linuxtone.org/soft/tools/tr.pl
    数据库篇
    1.查看数据库执行的sql
    /usr/sbin/tcpdump -i eth0 -s 0 -l -w - dst port 3306 | strings | egrep -i 'SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|CALL'

    系统Debug分析篇
    1.调试命令
    strace -p pid
    2.跟踪指定进程的PID
    gdb -p pid



    转自:http://www.cnblogs.com/derekchen/archive/2011/02/26/1965806.html
  • Linux的sysctl 命令 参数

    2011-12-14 17:59:28



    Linux内核通过/proc虚拟文件系统向用户导出内核信息,用户也可以通过/proc文件系统或通过sysctl命令动态配置内核。比如,如果我们想启动NAT,除了加载模块、配置防火墙外,还需要启动内核转发功能。我们有三种方法:

    1. 直接写/proc文件系统
    # echo 1 > /proc/sys/net/ipv4/ip_forward

    2. 利用sysctl命令
    # sysctl -w net.ipv4.ip_forward=1
    sysctl -a可以查看内核所有导出的变量

    3. 编辑/etc/sysctl.conf
    添加如下一行,这样系统每次启动后,该变量的值就是1
    net.ipv4.ip_forward = 1

    sysctl是procfs软件中的命令,该软件包还提供了w, ps, vmstat, pgrep, pkill, top, slabtop等命令。

    sysctl配置与显示在/proc/sys目录中的内核参数.可以用sysctl来设置或重新设置联网功能,如IP转发、IP碎片去除以及源路由检查等。用户只需要编辑/etc/sysctl.conf文件,即可手工或自动执行由sysctl控制的功能。

        命令格式:
        sysctl [-n] [-e] -w variable=value
        sysctl [-n] [-e] -p <filename> (default /etc/sysctl.conf)
        sysctl [-n] [-e] -a
        常用参数的意义:
        -w   临时改变某个指定参数的值,如
             sysctl -w net.ipv4.ip_forward=1
        -a   显示所有的系统参数
        -p   从指定的文件加载系统参数,如不指定即从/etc/sysctl.conf中加载
        如果仅仅是想临时改变某个系统参数的值,可以用两种方法来实现,例如想启用IP路由转发功能:
        1) #echo 1 > /proc/sys/net/ipv4/ip_forward
        2) #sysctl -w net.ipv4.ip_forward=1
        以上两种方法都可能立即开启路由功能,但如果系统重启,或执行了
         # service network restart
    命令,所设置的值即会丢失,如果想永久保留配置,可以修改/etc/sysctl.conf文件
    将 net.ipv4.ip_forward=0改为net.ipv4.ip_forward=1



    sysctl是一个允许您改变正在运行中的Linux系统的接口。它包含一些 TCP/IP 堆栈和虚拟内存系统的高级选项, 这可以让有经验的管理员提高引人注目的系统性能。用sysctl可以读取设置超过五百个系统变量。基于这点,sysctl(8) 提供两个功能:读取和修改系统设置。
    查看所有可读变量:
    % sysctl -a
    读一个指定的变量,例如 kern.maxproc:
    % sysctl kern.maxproc kern.maxproc: 1044
    要设置一个指定的变量,直接用 variable=value 这样的语法:
    # sysctl kern.maxfiles=5000
    kern.maxfiles: 2088 -> 5000
    您可以使用sysctl修改系统变量,也可以通过编辑sysctl.conf文件来修改系统变量。sysctl.conf 看起来很像 rc.conf。它用 variable=value 的形式来设定值。指定的值在系统进入多用户模式之后被设定。并不是所有的变量都可以在这个模式下设定。
    sysctl 变量的设置通常是字符串、数字或者布尔型。 (布尔型用 1 来表示'yes',用 0 来表示'no')。

    sysctl -w kernel.sysrq=0
    sysctl -w kernel.core_uses_pid=1
    sysctl -w net.ipv4.conf.default.accept_redirects=0
    sysctl -w net.ipv4.conf.default.accept_source_route=0
    sysctl -w net.ipv4.conf.default.rp_filter=1
    sysctl -w net.ipv4.tcp_syncookies=1
    sysctl -w net.ipv4.tcp_max_syn_backlog=2048
    sysctl -w net.ipv4.tcp_fin_timeout=30
    sysctl -w net.ipv4.tcp_synack_retries=2
    sysctl -w net.ipv4.tcp_keepalive_time=3600
    sysctl -w net.ipv4.tcp_window_scaling=1
    sysctl -w net.ipv4.tcp_sack=1

    配置sysctl

    编辑此文件:

    vi /etc/sysctl.conf


    如果该文件为空,则输入以下内容,否则请根据情况自己做调整:

    # Controls source route verification
    # Default should work for all interfaces
    net.ipv4.conf.default.rp_filter = 1
    # net.ipv4.conf.all.rp_filter = 1
    # net.ipv4.conf.lo.rp_filter = 1
    # net.ipv4.conf.eth0.rp_filter = 1

    # Disables IP source routing
    # Default should work for all interfaces
    net.ipv4.conf.default.accept_source_route = 0
    # net.ipv4.conf.all.accept_source_route = 0
    # net.ipv4.conf.lo.accept_source_route = 0
    # net.ipv4.conf.eth0.accept_source_route = 0

    # Controls the System Request debugging functionality of the kernel
    kernel.sysrq = 0

    # Controls whether core dumps will append the PID to the core filename.
    # Useful for debugging multi-threaded applications.
    kernel.core_uses_pid = 1

    # Increase maximum amount of memory allocated to shm
    # Only uncomment if needed!
    # kernel.shmmax = 67108864

    # Disable ICMP Redirect Acceptance
    # Default should work for all interfaces
    net.ipv4.conf.default.accept_redirects = 0
    # net.ipv4.conf.all.accept_redirects = 0
    # net.ipv4.conf.lo.accept_redirects = 0
    # net.ipv4.conf.eth0.accept_redirects = 0

    # Enable Log Spoofed Packets, Source Routed Packets, Redirect Packets
    # Default should work for all interfaces
    net.ipv4.conf.default.log_martians = 1
    # net.ipv4.conf.all.log_martians = 1
    # net.ipv4.conf.lo.log_martians = 1
    # net.ipv4.conf.eth0.log_martians = 1

    # Decrease the time default value for tcp_fin_timeout connection
    net.ipv4.tcp_fin_timeout = 25

    # Decrease the time default value for tcp_keepalive_time connection
    net.ipv4.tcp_keepalive_time = 1200

    # Turn on the tcp_window_scaling
    net.ipv4.tcp_window_scaling = 1

    # Turn on the tcp_sack
    net.ipv4.tcp_sack = 1

    # tcp_fack should be on because of sack
    net.ipv4.tcp_fack = 1

    # Turn on the tcp_timestamps
    net.ipv4.tcp_timestamps = 1

    # Enable TCP SYN Cookie Protection
    net.ipv4.tcp_syncookies = 1

    # Enable ignoring broadcasts request
    net.ipv4.icmp_echo_ignore_broadcasts = 1

    # Enable bad error message Protection
    net.ipv4.icmp_ignore_bogus_error_responses = 1

    # Make more local ports available
    # net.ipv4.ip_local_port_range = 1024 65000

    # Set TCP Re-Ordering value in kernel to ‘5′
    net.ipv4.tcp_reordering = 5

    # Lower syn retry rates
    net.ipv4.tcp_synack_retries = 2
    net.ipv4.tcp_syn_retries = 3

    # Set Max SYN Backlog to ‘2048′
    net.ipv4.tcp_max_syn_backlog = 2048

    # Various Settings
    net.core.netdev_max_backlog = 1024

    # Increase the maximum number of skb-heads to be cached
    net.core.hot_list_length = 256

    # Increase the tcp-time-wait buckets pool size
    net.ipv4.tcp_max_tw_buckets = 360000

    # This will increase the amount of memory available for socket input/output queues
    net.core.rmem_default = 65535
    net.core.rmem_max = 8388608
    net.ipv4.tcp_rmem = 4096 87380 8388608
    net.core.wmem_default = 65535
    net.core.wmem_max = 8388608
    net.ipv4.tcp_wmem = 4096 65535 8388608
    net.ipv4.tcp_mem = 8388608 8388608 8388608
    net.core.optmem_max = 40960

    如果希望屏蔽别人 ping 你的主机,则加入以下代码:

    # Disable ping requests
    net.ipv4.icmp_echo_ignore_all = 1

    编辑完成后,请执行以下命令使变动立即生效:

    /sbin/sysctl -p
    /sbin/sysctl -w net.ipv4.route.flush=1

    我们常常在 Linux 的 /proc/sys 目录下,手动设定一些 kernel 的参数或是直接 echo 特定的值给一个 proc下的虚拟档案,俾利某些档案之开启,常见的例如设定开机时自动启动 IP Forwarding: 
    echo “1” > /proc/sys/net/ipv4/ip_forward 

    其实,在 Linux 我们还可以用 sysctl command 便可以简易的去检视、设定或自动配置 特定的 kernel 设定。我们可以在系统提示符号下输入「sysctl -a」,摘要如后:abi.defhandler_coff = 117440515 

    dev.raid.speed_limit_max = 100000 

    net.ipv4.conf.default.send_redirects = 1 

    net.ipv4.conf.default.secure_redirects = 1 

    net.ipv4.conf.default.accept_redirects = 1 

    net.ipv4.conf.default.mc_forwarding = 0 

    net.ipv4.neigh.lo.delay_first_probe_time = 5 

    net.ipv4.neigh.lo.base_reachable_time = 30 

    net.ipv4.icmp_ratelimit = 100 

    net.ipv4.inet_peer_gc_mintime = 10 

    net.ipv4.igmp_max_memberships = 20 

    net.ipv4.ip_no_pmtu_disc = 0 

    net.core.no_cong_thresh = 20 

    net.core.netdev_max_backlog = 300 

    net.core.rmem_default = 65535 

    net.core.wmem_max = 65535 

    vm.kswapd = 512 32 8 

    vm.overcommit_memory = 0 

    vm.bdflush = 30 64 64 256 500 3000 60 0 0 

    vm.freepages = 351 702 1053 

    kernel.sem = 250 32000 32 128 

    kernel.panic = 0 

    kernel.domainname = (none) 

    kernel.hostname = pc02.shinewave.com.tw 

    kernel.version = #1 Tue Oct 30 20:11:04 EST 2001 

    kernel.osrelease = 2.4.9-13 

    kernel.ostype = Linux 

    fs.dentry-state = 1611 969 45 0 0 0 

    fs.file-nr = 1121 73 8192 

    fs.inode-state = 1333 523 0 0 0 0 0 

    从上述的语法我们大概可看出 sysctl 的表示法乃把目录结构的「/」以「.」表示,一层一层的连结下去。当然以echo 特定的值给一个 proc下的虚拟档案也是可以用 sysctl加以表示,例如: 

    #sysctl –w net.ipv4.ip_forward =”1” 


    或是直接在 /etc/sysctl.conf 增删修改特定档案的 0,1值亦可: 

    # Enables packet forwarding 

    net.ipv4.ip_forward = 1 

    # Enables source route verification 

    net.ipv4.conf.default.rp_filter = 1 

    # Disables the magic-sysrq key 

    kernel.sysrq = 0 

    当然如果考虑 reboot 后仍有效, 直接在 /etc/sysctl.conf 增删修改特定档案的 0,1值才可使之保留设定(以RedHat 为例,每次开机系统启动后, init 会执行 /etc/rc.d/rc.sysinit,便会使用 /etc/sysctl.conf 的预设值去执行 sysctl)。 

    相关参考档案: 

    /sbin/sysctl 

    /etc/sysctl.conf 

    sysctl 及sysctl.conf manpage 

    /usr/src/linux-x.y.z/Documentation/sysctl/* 

    /usr/share/doc/kernel-doc-x.y.z/sysctl/* (RedHat)

    http://hi.baidu.com/caosicong/blog/item/0a592360d438cfda8db10d9b.html
    http://hi.baidu.com/phpfamer/blog/item/932e276eb39c30de80cb4a3c.htmlsysctl配置与显示在/proc/sys目录中的内核参数.可以用sysctl来设置或重新设置联网功能,如IP转发、IP碎片去除以及源路由检查等。用户只需要编辑/etc/sysctl.conf文件,即可手工或自动执行由sysctl控制的功能。
        命令格式:
        sysctl [-n] [-e] -w variable=value
        sysctl [-n] [-e] -p <filename> (default /etc/sysctl.conf)
        sysctl [-n] [-e] -a
        常用参数的意义:
        -w   临时改变某个指定参数的值,如
             sysctl -w net.ipv4.ip_forward=1
        -a   显示所有的系统参数
        -p   从指定的文件加载系统参数,如不指定即从/etc/sysctl.conf中加载
        如果仅仅是想临时改变某个系统参数的值,可以用两种方法来实现,例如想启用IP路由转发功能:
        1) #echo 1 > /proc/sys/net/ipv4/ip_forward
        2) #sysctl -w net.ipv4.ip_forward=1
        以上两种方法都可能立即开启路由功能,但如果系统重启,或执行了
         # service network restart
    命令,所设置的值即会丢失,如果想永久保留配置,可以修改/etc/sysctl.conf文件
    将 net.ipv4.ip_forward=0改为net.ipv4.ip_forward=1



    sysctl是一个允许您改变正在运行中的Linux系统的接口。它包含一些 TCP/IP 堆栈和虚拟内存系统的高级选项, 这可以让有经验的管理员提高引人注目的系统性能。用sysctl可以读取设置超过五百个系统变量。基于这点,sysctl(8) 提供两个功能:读取和修改系统设置。
    查看所有可读变量:
    % sysctl -a
    读一个指定的变量,例如 kern.maxproc:
    % sysctl kern.maxproc kern.maxproc: 1044
    要设置一个指定的变量,直接用 variable=value 这样的语法:
    # sysctl kern.maxfiles=5000
    kern.maxfiles: 2088 -> 5000
    您可以使用sysctl修改系统变量,也可以通过编辑sysctl.conf文件来修改系统变量。sysctl.conf 看起来很像 rc.conf。它用 variable=value 的形式来设定值。指定的值在系统进入多用户模式之后被设定。并不是所有的变量都可以在这个模式下设定。
    sysctl 变量的设置通常是字符串、数字或者布尔型。 (布尔型用 1 来表示'yes',用 0 来表示'no')。

    sysctl -w kernel.sysrq=0
    sysctl -w kernel.core_uses_pid=1
    sysctl -w net.ipv4.conf.default.accept_redirects=0
    sysctl -w net.ipv4.conf.default.accept_source_route=0
    sysctl -w net.ipv4.conf.default.rp_filter=1
    sysctl -w net.ipv4.tcp_syncookies=1
    sysctl -w net.ipv4.tcp_max_syn_backlog=2048
    sysctl -w net.ipv4.tcp_fin_timeout=30
    sysctl -w net.ipv4.tcp_synack_retries=2
    sysctl -w net.ipv4.tcp_keepalive_time=3600
    sysctl -w net.ipv4.tcp_window_scaling=1
    sysctl -w net.ipv4.tcp_sack=1

    配置sysctl

    编辑此文件:

    vi /etc/sysctl.conf


    如果该文件为空,则输入以下内容,否则请根据情况自己做调整:

    # Controls source route verification
    # Default should work for all interfaces
    net.ipv4.conf.default.rp_filter = 1
    # net.ipv4.conf.all.rp_filter = 1
    # net.ipv4.conf.lo.rp_filter = 1
    # net.ipv4.conf.eth0.rp_filter = 1

    # Disables IP source routing
    # Default should work for all interfaces
    net.ipv4.conf.default.accept_source_route = 0
    # net.ipv4.conf.all.accept_source_route = 0
    # net.ipv4.conf.lo.accept_source_route = 0
    # net.ipv4.conf.eth0.accept_source_route = 0

    # Controls the System Request debugging functionality of the kernel
    kernel.sysrq = 0

    # Controls whether core dumps will append the PID to the core filename.
    # Useful for debugging multi-threaded applications.
    kernel.core_uses_pid = 1

    # Increase maximum amount of memory allocated to shm
    # Only uncomment if needed!
    # kernel.shmmax = 67108864

    # Disable ICMP Redirect Acceptance
    # Default should work for all interfaces
    net.ipv4.conf.default.accept_redirects = 0
    # net.ipv4.conf.all.accept_redirects = 0
    # net.ipv4.conf.lo.accept_redirects = 0
    # net.ipv4.conf.eth0.accept_redirects = 0

    # Enable Log Spoofed Packets, Source Routed Packets, Redirect Packets
    # Default should work for all interfaces
    net.ipv4.conf.default.log_martians = 1
    # net.ipv4.conf.all.log_martians = 1
    # net.ipv4.conf.lo.log_martians = 1
    # net.ipv4.conf.eth0.log_martians = 1

    # Decrease the time default value for tcp_fin_timeout connection
    net.ipv4.tcp_fin_timeout = 25

    # Decrease the time default value for tcp_keepalive_time connection
    net.ipv4.tcp_keepalive_time = 1200

    # Turn on the tcp_window_scaling
    net.ipv4.tcp_window_scaling = 1

    # Turn on the tcp_sack
    net.ipv4.tcp_sack = 1

    # tcp_fack should be on because of sack
    net.ipv4.tcp_fack = 1

    # Turn on the tcp_timestamps
    net.ipv4.tcp_timestamps = 1

    # Enable TCP SYN Cookie Protection
    net.ipv4.tcp_syncookies = 1

    # Enable ignoring broadcasts request
    net.ipv4.icmp_echo_ignore_broadcasts = 1

    # Enable bad error message Protection
    net.ipv4.icmp_ignore_bogus_error_responses = 1

    # Make more local ports available
    # net.ipv4.ip_local_port_range = 1024 65000

    # Set TCP Re-Ordering value in kernel to ‘5′
    net.ipv4.tcp_reordering = 5

    # Lower syn retry rates
    net.ipv4.tcp_synack_retries = 2
    net.ipv4.tcp_syn_retries = 3

    # Set Max SYN Backlog to ‘2048′
    net.ipv4.tcp_max_syn_backlog = 2048

    # Various Settings
    net.core.netdev_max_backlog = 1024

    # Increase the maximum number of skb-heads to be cached
    net.core.hot_list_length = 256

    # Increase the tcp-time-wait buckets pool size
    net.ipv4.tcp_max_tw_buckets = 360000

    # This will increase the amount of memory available for socket input/output queues
    net.core.rmem_default = 65535
    net.core.rmem_max = 8388608
    net.ipv4.tcp_rmem = 4096 87380 8388608
    net.core.wmem_default = 65535
    net.core.wmem_max = 8388608
    net.ipv4.tcp_wmem = 4096 65535 8388608
    net.ipv4.tcp_mem = 8388608 8388608 8388608
    net.core.optmem_max = 40960

    如果希望屏蔽别人 ping 你的主机,则加入以下代码:

    # Disable ping requests
    net.ipv4.icmp_echo_ignore_all = 1

    编辑完成后,请执行以下命令使变动立即生效:

    /sbin/sysctl -p
    /sbin/sysctl -w net.ipv4.route.flush=1

    我们常常在 Linux 的 /proc/sys 目录下,手动设定一些 kernel 的参数或是直接 echo 特定的值给一个 proc下的虚拟档案,俾利某些档案之开启,常见的例如设定开机时自动启动 IP Forwarding: 
    echo “1” > /proc/sys/net/ipv4/ip_forward 

    其实,在 Linux 我们还可以用 sysctl command 便可以简易的去检视、设定或自动配置 特定的 kernel 设定。我们可以在系统提示符号下输入「sysctl -a」,摘要如后:abi.defhandler_coff = 117440515 

    dev.raid.speed_limit_max = 100000 

    net.ipv4.conf.default.send_redirects = 1 

    net.ipv4.conf.default.secure_redirects = 1 

    net.ipv4.conf.default.accept_redirects = 1 

    net.ipv4.conf.default.mc_forwarding = 0 

    net.ipv4.neigh.lo.delay_first_probe_time = 5 

    net.ipv4.neigh.lo.base_reachable_time = 30 

    net.ipv4.icmp_ratelimit = 100 

    net.ipv4.inet_peer_gc_mintime = 10 

    net.ipv4.igmp_max_memberships = 20 

    net.ipv4.ip_no_pmtu_disc = 0 

    net.core.no_cong_thresh = 20 

    net.core.netdev_max_backlog = 300 

    net.core.rmem_default = 65535 

    net.core.wmem_max = 65535 

    vm.kswapd = 512 32 8 

    vm.overcommit_memory = 0 

    vm.bdflush = 30 64 64 256 500 3000 60 0 0 

    vm.freepages = 351 702 1053 

    kernel.sem = 250 32000 32 128 

    kernel.panic = 0 

    kernel.domainname = (none) 

    kernel.hostname = pc02.shinewave.com.tw 

    kernel.version = #1 Tue Oct 30 20:11:04 EST 2001 

    kernel.osrelease = 2.4.9-13 

    kernel.ostype = Linux 

    fs.dentry-state = 1611 969 45 0 0 0 

    fs.file-nr = 1121 73 8192 

    fs.inode-state = 1333 523 0 0 0 0 0 

    从上述的语法我们大概可看出 sysctl 的表示法乃把目录结构的「/」以「.」表示,一层一层的连结下去。当然以echo 特定的值给一个 proc下的虚拟档案也是可以用 sysctl加以表示,例如: 

    #sysctl –w net.ipv4.ip_forward =”1” 


    或是直接在 /etc/sysctl.conf 增删修改特定档案的 0,1值亦可: 

    # Enables packet forwarding 

    net.ipv4.ip_forward = 1 

    # Enables source route verification 

    net.ipv4.conf.default.rp_filter = 1 

    # Disables the magic-sysrq key 

    kernel.sysrq = 0 

    当然如果考虑 reboot 后仍有效, 直接在 /etc/sysctl.conf 增删修改特定档案的 0,1值才可使之保留设定(以RedHat 为例,每次开机系统启动后, init 会执行 /etc/rc.d/rc.sysinit,便会使用 /etc/sysctl.conf 的预设值去执行 sysctl)。 



    转自:http://hi.baidu.com/michaelhan/blog/item/b2784b7b45538ef10bd1872b.html
  • Linux下chkconfig命令详解和service命令

    2011-12-14 17:49:13

    Linux下chkconfig命令详解



    chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息。谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接。

    使用语法:
    chkconfig [--add][--del][--list][系统服务] 或 chkconfig [--level <等级代号>][系统服务][on/off/reset]

    chkconfig在没有参数运行时,显示用法。如果加上服务名,那么就检查这个服务是否在当前运行级启动。如果是,返回true,否则返回false。如果在服务名后面指定了on,off或者reset,那么chkconfi 会改变指定服务的启动信息。on和off分别指服务被启动和停止,reset指重置服务的启动信息,无论有问题的初始化脚本指定了什么。on和off开关,系统默认只对运行级3,4,5有效,但是reset可以对所有运行级有效。

    参数用法:
       --add  增加所指定的系统服务,让chkconfig指令得以管理它,并同时在系统启动的叙述文件内增加相关数据。
       --del  删除所指定的系统服务,不再由chkconfig指令管理,并同时在系统启动的叙述文件内删除相关数据。
       --level<等级代号>  指定读系统服务要在哪一个执行等级中开启或关毕。
          等级0表示:表示关机
          等级1表示:单用户模式
          等级2表示:无网络连接的多用户命令行模式
          等级3表示:有网络连接的多用户命令行模式
          等级4表示:不可用
          等级5表示:带图形界面的多用户模式
          等级6表示:重新启动
          需要说明的是,level选项可以指定要查看的运行级而不一定是当前运行级。对于每个运行级,只能有一个启动脚本或者停止脚本。当切换运行级时,init不会重新启动已经启动的服务,也不会再次去停止已经停止的服务。

        chkconfig --list [name]:显示所有运行级系统服务的运行状态信息(on或off)。如果指定了name,那么只显示指定的服务在不同运行级的状态。
        chkconfig --add name:增加一项新的服务。chkconfig确保每个运行级有一项启动(S)或者杀死(K)入口。如有缺少,则会从缺省的init脚本自动建立。
        chkconfig --del name:删除服务,并把相关符号连接从/etc/rc[0-6].d删除。
        chkconfig [--level levels] name:设置某一服务在指定的运行级是被启动,停止还是重置。

    运行级文件:
    每个被chkconfig管理的服务需要在对应的init.d下的脚本加上两行或者更多行的注释。第一行告诉chkconfig缺省启动的运行级以及启动和停止的优先级。如果某服务缺省不在任何运行级启动,那么使用 - 代替运行级。第二行对服务进行描述,可以用\ 跨行注释。
    例如,random.init包含三行:
    # chkconfig: 2345 20 80
    # description: Saves and restores system entropy pool for \
    # higher quality random number generation.

    使用范例:
    chkconfig --list        #列出所有的系统服务
    chkconfig --add httpd        #增加httpd服务
    chkconfig --del httpd        #删除httpd服务
    chkconfig --level httpd 2345 on        #设置httpd在运行级别为2、3、4、5的情况下都是on(开启)的状态
    chkconfig --list        #列出系统所有的服务启动情况
    chkconfig --list mysqld        #列出mysqld服务设置情况
    chkconfig --level 35 mysqld on        #设定mysqld在等级3和5为开机运行服务,--level 35表示操作只在等级3和5执行,on表示启动,off表示关闭
    chkconfig mysqld on        #设定mysqld在各等级为on,“各等级”包括2、3、4、5等级

    如何增加一个服务:
    1.服务脚本必须存放在/etc/ini.d/目录下;
    2.chkconfig --add servicename
        在chkconfig工具服务列表中增加此服务,此时服务会被在/etc/rc.d/rcN.d中赋予K/S入口了;
    3.chkconfig --level 35 mysqld on
        修改服务的默认启动等级。



    --------------------------------------------------------------------------------------------


    linux  service命令

    service命令,顾名思义,就是用于管理Linux操作系统中服务的命令。

    1. 声明:这个命令不是在所有的linux发行版本中都有。主要是在redhat、fedora、mandriva和centos中。

    2. 此命令位于/sbin目录下,用file命令查看此命令会发现它是一个脚本命令。

    3. 分析脚本可知此命令的作用是去/etc/init.d目录下寻找相应的服务,进行开启和关闭等操作。

    4. 开启httpd服务器:service httpd start

    start可以换成restart表示重新启动,stop表示关闭,reload表示重新载入配置。

    5. 关闭mysql服务器:service mysqld stop

    6. 强烈建议大家将service命令替换为/etc/init.d/mysqld stop (因为有一些linux的版本不支持service)

     

     

     

    Usage: service < option > | --status-all | [ service_name [ command | --full-restart ] ]

    service oracle start

    service oracle stop

    service oracle restart

    service oracle status





    转自:http://www.cnblogs.com/panjun-Donet/archive/2010/08/10/1796873.html


    http://blog.sina.com.cn/s/blog_51dc0fba0100rjrb.html
  • linux awk用法

    2011-12-14 17:34:55

    用法:awk '{pattern + action}' {filenames} 
    pattern指在每一行中进行匹配的条件,action指针对符合条件的行进行的操作,filenames是输入的文件名。

    假设data文件中有以下数据:

        1 donald 305 20050129
        2 chin 102 20040129
        3 mark 304 20040229
    --------------------------------------------------------------
    awk '{action}' {filenames} 
     范例:awk '{print $1, $2, $3, $4}' data
           输出data文件的1,2,3,4列

    awk '{pattern + action}' {filenames} 
    范例:awk '/donald/ {print $4}' data
             匹配当data文件中包含字符串"donald"的行,输出第4列的值:
    ----------------------------------------------------

    pattern指在每一行中进行匹配的条件,action指针对符合条件的行进行的操作,filenames是输入的文件名。

    假设data文件中有以下数据:

        1 donald 305 20050129
        2 chin 102 20040129
        3 mark 304 20040229


    下面对这个文件进行操作:

        awk '{print $1, $2, $3, $4}' data


    输出:

        1 donald 305 20050129
        2 chin 102 20040129
        3 mark 304 20040229



        awk '{print $1"\t", $2"\t", $3"\t", $4}' data


    输出:

        1 donald 305 20050129
        2 chin 102 20040129
        3 mark 304 20040229


    这里显示的格式并不是输出的真实格式,真实格式是中间会有一个tab符号,格式对的很整齐,只不过在html里看不出来。

        awk '/donald/ {print $4}' data

    匹配当data文件中包含字符串"donald"的行,输出第4列的值:

        20050129

        awk '/donald|chin/ {print $1, $2}' data

    这里的"|"应该是或的作用,而不是管道,输出:

        1 donald
        2 chin

        awk '/a[rl]/ {print $1, $2}' data

    兼容perl的正则表达式,匹配包含"ar"或"al"的列,输出:

        1 donald
        3 mark

        awk '/a[rl]/ {print $1, $2, $3+1}' data

    给第三列加上1再输出:

        1 donald 306
        3 mark 305

        awk '/a[rl]/ {print $1, $2} {print $3+1}' data

    匹配只对第一对花括号产生作用,输出:

        1 donald
        306
        103
        3 mark
        305

        awk 'FS="n" {print $1}' data

    使用"n"而不是空格做为分隔符,输出:

        1
        2 chi
        3 mark 304 20040229

        awk 'FS="n" {OFS="-"} {print $1, $2}' data

    把分隔符输出:

        1-donald
        2 chi- 102 20040129
        3 mark 304 20040229-

        awk 'FS="n" {OFS="-"} {print NR, $1, $2}' data

    使用NR变量,num of row,即行号,输出:

        1-1-donald
        2-2 chi- 102 20040129
        3-3 mark 304 20040229-

        awk '{x=x+$3} {print NR, $3, x}' data

    使用变量进行累加计算,输出:

        1 305 305
        2 102 407
        3 304 711

        awk '{x=x+$3} END {print NR, $3, x}' data

    使用BEGIN和END在处理之前或之后显示结果,输出:

        3 304 711

        awk '{x=x+$3} {print NR, $3, x | "sort -nr"}' data

    在awk内使用管道进行排序,输出:

        3 304 711
        2 102 407
        1 305 305

        cat command
        {x=x+$3}
        {print NR, $3, x | "sort -nr"}

        awk -f command data

    将指定写在文件中,输出:

        3 304 711
        2 102 407
        1 305 305

    如果简单的输出不能处理您的程序中所需要的复杂信息,则可以尝试由 printf 命令获得的更加复杂的输出,其语法是

    printf( format, value, value ...)

    该语法类似于 C 语言中的 printf 命令,而格式的规格是相同的。通过插入一项定义如何打印数值的规格,可以定义该格式。格式规格包含一个跟有字母的 %。类似于打印命令,printf 不必包含在圆括号中,但是可以认为使用圆括号是一种良好的习惯。

    下表列出 printf 命令提供的各种规格。

    规格 说明
    %c 打印单个 ASCII 字符
    %d 打印十进制数
    %e 打印数字的科学计数表示
    %f 打印浮点表示
    %g 打印 %e 或 %f;两种方式都更简短
    %o 打印无符号的八进制数
    s 打印 ASCII 字符串
    %x 打印无符号的十六进制数
    %% 打印百分号;不执行转换

    可以在 % 与字符之间提供某些附加的格式化参数。这些参数进一步改进数值的打印方式:

    参数 说明
    - 将字段中的表达式向左对齐
    ,width 根据需要将字段补齐到指定宽度(前导零使用零将字段补齐)
    .prec 小数点右面数字的最大字符串宽度或最大数量



    转自:http://bbs.linuxtone.org/thread-222-1-1.html


    ----------------------------------------------------
    awk 用法:awk ' pattern {action} '  data

    变量名                含义
    ARGC                命令行变元个数
    ARGV                命令行变元数组
    FILENAME        当前输入文件
    FNR                当前文件中的记录号
    FS                输入域分隔符,默认为一个空格
    RS                输入记录分隔符
    NF                当前记录里域个数
    NR                到目前为止记录数
    OFS                输出域分隔符
    ORS                输出记录分隔符

    1、awk '/101/'               file 显示文件file中包含101的匹配行。
       awk '/101/,/105/'         file
       awk '$1 == 5'             file
       awk '$1 == "CT"'          file 注意必须带双引号
       awk '$1 * $2 >100 '       file 
       awk '$2 >5 && $2<=15'     file
    2、awk '{print NR,NF,$1,$NF,}' file 显示文件file的当前记录号、域数和每一行的第一个和最后一个域。
       awk '/101/ {print $1,$2 + 10}' file 显示文件file的匹配行的第一、二个域加10。
       awk '/101/ {print $1$2}'  file
       awk '/101/ {print $1 $2}' file 显示文件file的匹配行的第一、二个域,但显示时域中间没有分隔符。
    3、df | awk '$4>1000000 '         通过管道符获得输入,如:显示第4个域满足条件的行。
    4、awk -F "|" '{print $1}'   file 按照新的分隔符“|”进行操作。
       awk  'BEGIN { FS="[: \t|]" }
       {print $1,$2,$3}'              file 通过设置输入分隔符(FS="[: \t|]")修改输入分隔符。

       Sep="|"
       awk -F $Sep '{print $1}'  file 按照环境变量Sep的值做为分隔符。   
       awk -F '[ :\t|]' '{print $1}' file 按照正则表达式的值做为分隔符,这里代表空格、:、TAB、|同时做为分隔符。
       awk -F '[][]'    '{print $1}' file 按照正则表达式的值做为分隔符,这里代表[、]
    5、awk -f awkfile              file 通过文件awkfile的内容依次进行控制。
       cat awkfile
    /101/{print "\047 Hello! \047"} --遇到匹配行以后打印 ' Hello! '.\047代表单引号。
    {print $1,$2}                   --因为没有模式控制,打印每一行的前两个域。
    6、awk '$1 ~ /101/ {print $1}' file 显示文件中第一个域匹配101的行(记录)。
    7、awk   'BEGIN { FS="%"}
       {print $1,$2}'           file 通过设置输出分隔符(OFS="%")修改输出格式。
    8、awk   'BEGIN { max=100 ;print "max=" max}             BEGIN 表示在处理任意行之前进行的操作。
       {max=($1 >max ?$1:max); print $1,"Now max is "max}' file 取得文件第一个域的最大值。
       (表达式1?表达式2:表达式3 相当于:
       if (表达式1)
           表达式2
       else
           表达式3
       awk '{print ($1>4 ? "high "$1: "low "$1)}' file 
    9、awk '$1 * $2 >100 {print $1}' file 显示文件中第一个域匹配101的行(记录)。
    10、awk '{$1 == 'Chi' {$3 = 'China'; print}' file 找到匹配行后先将第3个域替换后再显示该行(记录)。
        awk '{$7 %= 3; print $7}'  file 将第7域被3除,并将余数赋给第7域再打印。
    11、awk '/tom/ {wage=$2+$3; printf wage}' file 找到匹配行后为变量wage赋值并打印该变量。
    12、awk '/tom/ {count++;} 
             END {print "tom was found "count" times"}' file END表示在所有输入行处理完后进行处理。
    13、awk 'gsub(/\$/,"");gsub(/,/,""); cost+=$4;
             END {print "The total is $" cost>"filename"}'    file gsub函数用空串替换$和,再将结果输出到filename中。
        1 2 3 $1,200.00
        1 2 3 $2,300.00
        1 2 3 $4,000.00

        awk '{gsub(/\$/,"");gsub(/,/,"");
        if ($4>1000&&$4<2000) c1+=$4;
        else if ($4>2000&&$4<3000) c2+=$4;
        else if ($4>3000&&$4<4000) c3+=$4;
        else c4+=$4; }
        END {printf  "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"' file
        通过if和else if完成条件语句

        awk '{gsub(/\$/,"");gsub(/,/,"");
        if ($4>3000&&$4<4000) exit;
        else c4+=$4; }
        END {printf  "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"' file
        通过exit在某条件时退出,但是仍执行END操作。
        awk '{gsub(/\$/,"");gsub(/,/,"");
        if ($4>3000) next;
        else c4+=$4; }
        END {printf  "c4=[%d]\n",c4}"' file
        通过next在某条件时跳过该行,对下一行执行操作。


    14、awk '{ print FILENAME,$0 }' file1 file2 file3>fileall 把file1、file2、file3的文件内容全部写到fileall中,格式为
        打印文件并前置文件名。
    15、awk ' $1!=previous { close(previous); previous=$1 }   
        {print substr($0,index($0," ") +1)>$1}' fileall 把合并后的文件重新分拆为3个文件。并与原文件一致。
    16、awk 'BEGIN {"date"|getline d; print d}'         通过管道把date的执行结果送给getline,并赋给变量d,然后打印。 
    17、awk 'BEGIN {system("echo \"Input your name:\\c\""); getline d;print "\nYour name is",d,"\b!\n"}'
        通过getline命令交互输入name,并显示出来。
        awk 'BEGIN {FS=":"; while(getline< "/etc/passwd" >0) { if($1~"050[0-9]_") print $1}}'
        打印/etc/passwd文件中用户名包含050x_的用户名。

    18、awk '{ i=1;while(i<NF) {print NF,$i;i++}}' file 通过while语句实现循环。
        awk '{ for(i=1;i<NF;i++) {print NF,$i}}'   file 通过for语句实现循环。    
        type file|awk -F "/" '
        { for(i=1;i<NF;i++)
        { if(i==NF-1) { printf "%s",$i }
        else { printf "%s/",$i } }}'               显示一个文件的全路径。
        用for和if显示日期
        awk  'BEGIN {
    for(j=1;j<=12;j++)
    { flag=0;
      printf "\n%d月份\n",j;
            for(i=1;i<=31;i++)
            {
            if (j==2&&i>28) flag=1;
            if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
            if (flag==0) {printf "%02d%02d ",j,i}
            }
    }
    }'
    19、在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串
    Flag=abcd
    awk '{print '$Flag'}'   结果为abcd
    awk '{print  "$Flag"}'   结果为$Flag


    转自:http://bbs.chinaunix.net/viewthread.php?tid=691456&extra=page%3D2
  • linux sed用法

    2011-12-06 18:09:11

    linux sed用法  



    今天学习了sed的基本用法,如有不对的地方希望大家指出。.      

             使用sed命令行格式为:
              # sed [-nefri] 'command[aidcsp]' 输入文本        

    常用选项:
           
     -n∶使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN的资料一般都会被列出到萤幕上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
            -e∶直接在指令列模式上进行 sed 的动作编辑;
            -f∶直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的sed 动作;即通过读取文件脚本执行sed命令
            -r∶sed 的动作支援的是延伸型正规表示法的语法。(预设是基础正规表示法语法)
             -i∶直接修改读取的档案内容,而不是由屏幕输出。      

    常用命令:
            a   ∶新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~

      ∶插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);

            d   ∶删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
            c   ∶取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
             
     ∶取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法!例如 1,20s/old/new/g 就是啦!
             p  ∶打印,亦即将某个选择的行打印到屏幕。通常 p 会与参数 sed -n 一起运作~
             

    举例:(假设我们有一文件名为ab)
         删除某行
         [root@localhost ruby# sed '1d' ab              #删除第一行 
         [root@localhost ruby] # sed '$d' ab              #删除最后一行
         [root@localhost ruby] # sed '1,2d' ab           #删除第一行到第二行
         [root@localhost ruby] # sed '2,$d' ab           #删除第二行到最后一行
         显示某行
    .    [root@localhost ruby# sed -n '1p' ab           #显示第一行 
         [root@localhost ruby] # sed -n '$p' ab           #显示最后一行
         [root@localhost ruby] # sed -n '1,2p' ab        #显示第一行到第二行
         [root@localhost ruby] # sed -n '2,$p' ab        #显示第二行到最后一行
         使用模式进行查询
         [root@localhost ruby] # sed -n '/ruby/p' ab    #查询包括关键字ruby所在所有行
         [root@localhost ruby] # sed -n '/\$/p' ab        #查询包括关键字¥所在所有行,使用反斜线\屏蔽特殊含义
         增加一行或多行字符串
         [root@localhost ruby]# cat ab
         Hello!
         ruby is me,welcome to my blog.
         end
         [root@localhost ruby] # sed '1a drink tea' ab  #第一行后增加字符串"drink tea"
         Hello!
         drink tea
         ruby is me,welcome to my blog. 
         end
         [root@localhost ruby] # sed '1,3a drink tea' ab #第一行到第三行后增加字符串"drink tea"
         Hello!
         drink tea
         ruby is me,welcome to my blog.
         drink tea
         end
         drink tea
         [root@localhost ruby] # sed '1a drink tea\nor coffee' ab   #第一行后增加多行,使用换行符\n
         Hello!
         drink tea
         or coffee
         ruby is me,welcome to my blog.
         end
         代替一行或多行
         [root@localhost ruby] # sed '1c Hi' ab                #第一行代替为Hi
         Hi
         ruby is me,welcome to my blog.
         end
         [root@localhost ruby] # sed '1,2c Hi' ab             #第一行到第二行代替为Hi
         Hi
         end
        

     插入:前面的都是改变文件内容输出到屏幕,文件本身内容未被改变,-i则是直接修改文件内容本身
         [root@localhost ruby] # sed -i '$a bye' ab         #在文件ab中最后一行直接输入"bye"
         [root@localhost ruby]# cat ab
         Hello!
         ruby is me,welcome to my blog.
         end
         bye





    ====================================================
    sed的其他用法范例:

    sed用法: 
    sed 'Command' filename(s) 只显示结果而不修改文件

    1、sed    '2,5d'    file 显示文件file,除去2-5行,但行数超过文件实际行数时不会报错。
       sed    '/10[1-4]/d'      file 显示文件file,除去包含101-104的行。
       sed    '2,$d'            file 显示文件,只显示第一行。sed '2,$!d' file则只显示除第一行外的其它行。
       sed    '/^ *$/d          file 删除文件中的空行。
    2、sed    -n '/10[1-4]/p'   file 只显示文件file中包含101-104的行。(-n和p必须同时使用,否则只有p时显示全部文件并多显示一次找到的行)
       sed    -n '5p'           file 只显示文件的第5行
    3、sed 's/moding/moden/g'   file 将moding替换为moden
    4、sed -n 's/^west/north/p' file 将west开头的行替换为north并显示出来。
    5、sed 's/[0-9][0-9][0-9]$/&.5/' file将file文件中以3个数字结尾的行替换为原数字加".5",&代表搜索到的字符串。
    6、sed 's/\(mod\)ing/\1en/g file 将mod做为模式1封装在括号里,然后替换。
       sed 's/...$//'           file 删除每一行的最后三个字符。
       sed 's/^...//'           file 删除每一行的头三个字符。
    7、sed 's#moding#moden#g'   file 将moding替换为moden,s后面的#代表搜索串和替换串之间的分界符。
    8、sed -n '/101/,/105/p'    file 显示从101的匹配行到105的匹配行。如果只找到101的匹配行,则从101的匹配行到文件末。
       sed -n '2,/999/p'        file 显示从第2行到匹配行。
    9、sed '/101/,/105/s/$/  20050119/' file将从101的匹配行到105的匹配行的行末增加"        20050119"内容。
    10、sed -e '1,3d' -e 's/moding/moden/g' file 先删除文件的1-3行,再进行替换。
        sed -e '/^#/!d'         file 显示文件以#开头的行。
    11、sed '/101/r newfile'    file 在每个匹配行增加文件newfile的内容
        sed '/101/w newfile'    file 把匹配行写入newfile。
    12、sed '/101/a\ 
        > ###'                     file 在匹配行后增加一新行。
        sed '/101/i\
        > ###'                    file 在匹配行前增加一新行。
        sed '/101/c\
        > ###'                    file 用新行替换匹配行。

    13、sed 'y/abcd/ABCD/'      file 将a、b、c、d分别替换为ABCD。 
    14、sed '5q'                file 显示到第5行时退出。
    15、sed '/101/{ n; s/moding/moden/g; }' file 在文件中找到匹配行的后一行(n)再进行替换。
        sed '/101/{ s/moding/moden/g; q; }' file 在文件中找到第一个匹配行后进行替换后再退出。
    16、sed -e '/101/{ h; d; }' -e '/104/{ G; }' file 在文件中找到与101匹配行后先存在一个缓存中,再放在与104匹配行后。
        sed -e '/101/{ h; d; }' -e '/104/{ g; }' file 在文件中找到与101匹配行后先存在一个缓存中,再替代104的匹配行。
        sed -e '/101/h' -e '$G'                  file 将最后一个匹配行放在文件末。
        sed -e '/101/h' -e '$g'                  file 将最后一个匹配行替换文件末行。
        sed -e '/101/h' -e '/104/x'              file 在文件中找到与101匹配行后先存在一个缓存中,再与104的匹配行进行互换。
    17、sed -f sfile                             file 根据文件sfile的命令列表进行操作。
        cat sfile
    /101/a\
    ####101####\
    ****101****
    /104/c\
    ####104 deleted####\
    ****104 deleted****
    1i\
    ####test####\
    ****test****



    http://bbs.chinaunix.net/thread-691881-1-1.html






     sed在行首(行尾)添加字符串;在某行后添加多行字符串
    分类: linux shell 2013-03-13 19:17 1013人阅读 评论(0) 收藏 举报
    SHELLLinux

    sed在行首添加字符串;

    sed ‘s/^/xxx/'  filename >output:^符号代表行首

    sed在行尾添加字符串;

    sed ‘s/$/string/' filename>output:$符号代表行尾



    sed在匹配某行后添加一行字符串:

    sed '/string1/c\string1\nstring2' filename>output:用string1替代string1,同时在string1后面加个回车换行后再添加string2


    sed在每行后添加多行:

    先在每一行字符串后面添加一行字符串,然后再用多行替换一行;

    sed 'a\string1'  filename >filename1

    sed '/string1/c\string2\nstring3' filename1>output


    ------------------------------------------------------
    sed 在指定行号的前面增加#,同时直接修改原文件

    [root@testrelease ~]# cat test.txt
    1
    2
    3
    4
    5
    [root@testrelease ~]# sed '2s/^/#/'  test.txt
    1
    #2
    3
    4
    5
    [root@testrelease ~]# cat test.txt
    1
    2
    3
    4
    5
    =====>说明:未修改原文件
    [root@testrelease ~]# sed -i '2s/^/#/'  test.txt
    [root@testrelease ~]# cat test.txt
    1
    #2
    3
    4
    5
    ====>增加 -i 参数后,直接修改原文件

  • awk与shell之间的变量传递方法 (转)

    2011-11-30 18:52:38


    这个博客还是可以滴:http://renyongjie668.blog.163.com/blog/#m=0

    我认为在linuxawk是个好东东啊,处理一些文本文件会非常方便。而在Linux下嘛,经常会和shell打交道,所以awkshell之间的变量相互传递,有时还是很有必要的,所以简单总结一下吧。

     

    awk中使用shell中的变量

    : "'$var'"

    这种写法大家无需改变用'括起awk程序的习惯,是老外常用的写法.:

    var="test"
    awk 'BEGIN{print "'$var'"}'

    这种写法其实际是双括号变为单括号的常量,传递给了awk.

    如果var中含空格,为了shell不把空格作为分格符,便应该如下使用:

    var="this is a test"
    awk 'BEGIN{print "'"$var"'"}'
    : '"$var"'

    这种写法与上一种类似.如果变量含空格,则变为'""$var""'较为可靠.
    : export 变量,使用ENVIRON["var"]形式,获取环境变量的值

    例如:
    var="this is a test"; export var;

    awk 'BEGIN{print ENVIRON["var"]}'
    : 可以使用awk-v选项  (如果变量个数不多,个人偏向于这种写法)

    例如:
    var="this is a test"
    awk -v awk_var="$var" 'BEGIN {print awk_var}'

    这样便把系统变量var传递给了awk变量awk_var.

     

     awkshell变量传递值

    awkshell传递变量,其思想无非是用awk(sed/perl等也是一样)输出若干条shell命令,然后再用shell去执行这些命令。

    eval $(awk 'BEGIN{print "var1='str1';var2='str2'"}')

    或者eval $(awk '{printf("var1=%s; var2=%s; var3=%s;",$1,$2,$3)}' abc.txt)

    之后可以在当前shell中使用var1,var2等变量了。

    echo "var1=$var1 ----- var2=$var2"

     

     参考资料:

    http://developer.51cto.com/art/200509/3781.htm

    http://www.ixpub.net/thread-1457438-1-1.html


    转自:http://renyongjie668.blog.163.com/blog/static/16005312011829102025222/



  • Linux下vmstat调优工具的深入分析 (*****)

    2011-11-30 13:03:31

    一)概述:

    vmstat
    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 310596  24796 143780    0    0   933    89 1044  119  3 21 72  4  0
     
    1)procs:
    r:代表正在运行的进程数.
    b:代表处在不可屏蔽中断的进程数.

    2)memory:
    swpd:已使用swap的空间大小.
    free:空闲的内存.
    buff:内存中buffer的大小.
    cache:内存中cache的大小.

    3)swap
    si:从swap读出的内存,也就是主缺页,这个值是一个比率,即每秒读了多少KB.
    so:置换到swap的内存,这个值是一个比率,即每秒写了多少KB.

    4)io
    bi:从磁盘读数据,这个值是一个比率,即每秒读了多少BLOCK.
    bo:写数据到磁盘,这个值是一个比率,即每秒写了多少BLOCK.

    5)system
    in:每秒中断的次数.
    cs:每秒转换上下文的次数.

    6)
    us:用户态进程使用CPU的百分比.
    sy:内核态进程使用CPU的百分比.
    id:处于空闲的CPU百分比.
    wa:系统等待IO的CPU时间百分比.
    st:来自于一个虚拟机偷取的CPU时间的百分比.

     

    二)系统监控的实验:

    实例一,大量的算术运算
    本程序会进入一个死循环,不断的进行求平方根的操作,模拟大量的算术运算的环境.
    测试源程序如下:
    #include <stdio.h>
    #include <math.h>
    #include <unistd.h>
    #include <stdlib.h>

    void
    run_status(void)
    {
    double pi = M_PI;
    double pisqrt;
    long i;
    while(1){
    pisqrt = sqrt(pi);
    }
    }

    int
    main (void)
    {
    run_status();

    exit(EXIT_SUCCESS);
    }

    gcc run.c -o run -lm
    ./run&

    运行:
    vmstat 1
    注:我们的程序不断的进行算术运算,r的值由0变成了1,而cpu的用户态利用率也达到了100%.如下:
    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 304592  25244 147800    0    0     0     0 1010   31  0  1 99  0  0
     0  0      0 304592  25244 147800    0    0     0     0 1020   37  0  0 100  0  0
     1  0      0 304592  25244 147800    0    0     0    36 1016   46 69  1 30  0  0
     1  0      0 304592  25244 147800    0    0     0     0 1067   56 100  0  0  0  0
     1  0      0 304592  25244 147800    0    0     0     0 1010   31 100  0  0  0  0


    实例二,大量的系统调用
    本脚本会进入一个死循环,不断的执行cd命令,从而模拟大量系统调用的环境
    测试脚本如下:
    #!/bin/bash

    while (true)
    do
    cd ;
    done

    chmod +x loop.sh
    ./loop.sh

    运行:
    vmstat 1
    注:程序不断的调用cd命令,此时进程不断的进行上下文切换,所以cs的值会骤然提高,而cpu的内核态利用率也会达到98%左右.如下:
    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 304592  25248 147804    0    0   111    15 1025  179 20 20 59  0  0
     0  0      0 304592  25248 147804    0    0     0     0 1013   36  0  0 100  0  0
     1  0      0 304592  25248 147816    0    0     0     0 1015  422  1 72 27  0  0
     2  0      0 304592  25248 147816    0    0     0     0 1012  544  3 97  0  0  0
     1  0      0 304592  25248 147816    0    0     0     0 1007  522  3 97  0  0  0
     1  0      0 304592  25248 147816    0    0     0    64 1015  523  3 97  0  0  0
     2  0      0 304592  25248 147816    0    0     0     0 1003  572  2 98  0  0  0
     1  0      0 304592  25248 147816    0    0     0     0 1012 1263  2 98  0  0  0
     1  0      0 304592  25248 147816    0    0     0     0 1006 1264  3 97  0  0  0
     1  0      0 304592  25248 147816    0    0     0     0 1015 1249  3 97  0  0  0


    实例三,大量的io操作

    我们用dd命令,从/dev/zero读数据,写入到/tmp/data文件中,如下:
    dd if=/dev/zero f=/tmp/data bs=1M count=1000

    运行:
    vmstat 1
    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 302160  25868 149004    0    0    77   116 1027  151 14 17 69  0  0
     1  0      0 302160  25868 149004    0    0     0     0 1018   35  0  1 99  0  0
     3  0      0 134884  26032 311628    0    0     0 109872 1423  102  0 100  0  0  0
     1  0      0  14596  26148 428808    0    0     0 117208 1372  120  0 100  0  0  0
     1  0      0   6224  22908 440592    0    0     4 64944 1305  322  0 98  0  2  0
     1  0      0   5976  21836 441016    0    0     4 79072 1447  162  0 51  0 49  0
     0  2      0   5716  21956 439672    0    0     4 79016 1431  374  0 81  0 19  0
     2  2      0   6180  22044 438064    0    0     0 61432 1392  285  0 61  0 39  0
     2  2      0   6912  22104 436828    0    0     4 73980 1486  253  1 59  0 40  0
     0  4      0   5876  14132 448856    0    0     8 63784 1378  313  0 69  0 31  0
     0  2      4   5980   4140 457860    0    0     0 46756 1399  274  0 65  0 35  0
     1  3      4   6060   3892 457580    0    0     8 69876 1398  214  0 46  0 54  0
     1  4      4   6120   2872 457348    0    0     0 59920 1364  327  0 71  0 29  0
     
    注:dd不断的向磁盘写入数据,所以bo的值会骤然提高,而cpu的wait数值也变高,说明由于大量的IO操作,系统的瓶径出现在低速的设备上.
    由于对文件系统的写入操作,cache也从149004KB提高到了457348KB,又由于大量的写中断调用,in的值也从1018提高到1364.


    接下来我们还用dd命令,这回从/tmp/data文件读,写到/dev/null文件中,如下:
    dd if=/tmp/test1 f=/dev/null bs=1M

    运行:
    vmstat 1
    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     60   7056   2492 464560    0    0   177   517 1028  116 10 12 78  1  0
     0  0     60   7056   2492 464560    0    0     0     0 1006   32  0  0 100  0  0
     0  1     60   5768   2296 465032    0    4 94340     4 1514  252  0 65 17 18  0
     1  1     60   5876   2220 466032    0    0 150148    56 1770  306  0 93  0  7  0
     0  1     60   5792   2180 467152    0    0 98872     0 1598  281  0 81  0 19  0
     0  1     60   6308    988 469816    0   52 89556    52 1722  303  0 88  0 12  0
     2  1     60   5620   1004 470488    0    0 79052     0 1671  690  0 72  0 28  0
     0  1     60   6548   1028 469540    0    0 67392     4 1535  657  1 66  0 33  0
     1  1     60   5648   1060 470588    0    0 47408    16 1400  482  0 44  0 56  0
     0  1     60   6368   1088 469836    0    0 70212     0 1561  666  0 66  0 34  0

    注:dd不断的从/tmp/data磁盘文件中读取数据,所以bi的值会骤然变高,最后我们看到b(不可中断进程数)也由0变成了1.

    接下来我们继续用dd命令,把数据写到/dev/ram1里,如下:
    dd if=/dev/zero f=/dev/ram1 bs=1M count=16
    16+0 records in
    16+0 records out
    16777216 bytes (17 MB) copied, 0.0635522 seconds, 264 MB/s

    运行:
    vmstat 1
    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     60   6156   6256 466280    0    0   366   480 1029  111  9 11 79  1  0
     0  0     60   6156   6256 466280    0    0     0     0 1011   32  0  0 100  0  0
     0  0     60   6156   6256 466292    0    0    12     0 1031   65  0  3 96  1  0
     0  0     60   6156   6264 466284    0    0     0    48 1022   48  0  1 99  0  0
     0  0     60   6148  17920 454652    0    0     0     4 1021   81  0  8 92  0  0
     0  0     60   6148  17920 454652    0    0     0     0 1013   32  1  0 99  0  0
     0  0     60   6148  17920 454652    0    0     0     0 1016   36  0  1 99  0  0
     0  0     60   6148  17920 454652    0    0     0     0 1006   31  0  0 100  0  0
     0  0     60   6148  17920 454652    0    0     0     0 1026   42  0  0 100  0  0
     
    注:dd从/dev/zero读取数据,写入到/dev/ram1里面,由于/dev/ram1是设备节点,所以buff会增加.


    实例四:大量的占用内存

    本程序会不断分配内存,直到系统崩溃.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>

    int main (int argc, char *argv[])
    {
    void *ptr;
    int n = 0;
    while (1){
    ptr = malloc(0x100000);

    if (ptr == NULL)
    break;

    memset(ptr, 1, 0x100000);
    printf("malloced %d MB\n", ++n);
    }

    pause();
    }

    gcc callmem.c -o callmem
    ./callmem


    运行:
    vmstat 1
    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   7512  18796 451064    0    0   346   442 1028  105  8 10 81  1  0
     0  0      0   7512  18796 451064    0    0     0     0 1012   36  0  1 99  0  0
     2  0      0   6096  18704 417676    0    0     0     0 1042  169  0 88 12  0  0
     1  0      0   5896  18616 379356    0    0     0     0 1048  183  1 99  0  0  0
     1  0      0   6324  18532 340796    0    0     0    36 1043  215  1 99  0  0  0
     1  0      0   6376  18444 302372    0    0     0     0 1048  195  0 100  0  0  0
     1  0      0   6036  18384 264904    0    0     0     0 1040  187  1 99  0  0  0
     1  0      0   5784  18384 228560    0    0     0     0 1046  175  1 99  0  0  0
     1  0      0   6532  18372 190316    0    0     0     0 1041  188  1 99  0  0  0
     1  0      0   6084  18364 153804    0    0     0     0 1047  187  0 100  0  0  0
     1  0      0   6256  18368 115992    0    0     0    12 1041  195  1 99  0  0  0
     1  0      0   6580  17852  77868    0    0     0     0 1050  196  1 99  0  0  0
     1  1      0   4892  17304  39556    0    0     0     0 1044  157  0 100  0  0  0
     1  1      0   5252  17304  18676    0    0     0     0 1037   81  1 99  0  0  0
     1  0   9236   6156  16456   7580    0 9172     0  9196 1092  131  1 74  0 25  0
     1  0  56008   6860  16456   7620    0 46772     0 46772 1394  399  1 96  0  3  0
     2  1 103600   6488  16464   7600    0 47652     0 47668 1416  395  2 96  0  2  0
     1  1 162644   6580  16464   7536    0 59044     0 59044 1300  333  2 92  0  6  0
     1  0 197980   6408  16464   5876    0 35340     0 35340 1330  259  3 89  0  8  0
     2  4 230372   4920  16468   2876    0 32392     4 32392 1299  293  2 96  0  2  0
     2  2 269352   5824  16472   1304    0 38980   252 38980 1306  285  2 90  0  8  0
     2  2 305656   4936  16468   1392   88 36304   216 36304 1310  317  1 87  0 12  0
     3  5 361100   5136  16472   1352   96 55444    96 55456 1301  297  2 91  0  7  0
     5  3 404796   6820  16488   1760   96 43696   524 43696 1282  186  2 82  0 16  0

    注:我们看到cache迅速减少,而swpd迅速增加,这是因为系统为了分配给新的程序,而从cache(文件系统缓存)回收空间,当空间依然不足时,会用到swap空间.
    而于此同时,si/so也会增加,尤其是so,而swap属于磁盘空间,所以bo也会增加.

    最后:st这个值来自一个虚拟机偷到的时间,在Linux 2.6.11内核之前,没有这个值.

     

    实例五:又一个大量分配内存例子

    我们这个例子为了说明active/inactivte的作用,
    源程序如下:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>

    int
    main (int argc, char *argv[])
    {
            if (argc != 2)
                    exit (0);

            size_t mb = strtoul(argv[1],NULL,0);

            size_t nbytes = mb * 0x100000;
            char *ptr = (char *) malloc(nbytes);
            if (ptr == NULL){
                    perror("malloc");
                    exit (EXIT_FAILURE);
            }

            size_t i;
            const size_t stride = sysconf(_SC_PAGE_SIZE);
            for (i = 0;i < nbytes; i+= stride) {
                    ptr[i] = 0;
            }

            printf("allocated %d mb\n", mb);
            pause();
            return 0;
    }
    gcc act.c -o act -lrt
    ./act 100

    运行:
    vmstat -a 1
    procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
     r  b   swpd   free  inact active   si   so    bi    bo   in   cs us sy id wa st
     0  0      0 363868  79488  47724    5  160   291   504 1032   95  6  9 83  1  0
     0  0      0 363868  79488  47728    0    0     0     0 1010   32  0  0 100  0  0
     0  0      0 363868  79488  47728    0    0     0     0 1014   34  0  0 100  0  0
     1  0      0 333924  79492  77736    0    0     8    36 1014   44  0 75 24  1  0
     1  0      0 293252  79500 118388    0    0     0     0 1011   34  0 100  0  0  0
     0  0      0 261384  79500 150140    0    0     0     0 1009   36  0 78 22  0  0
     0  0      0 261384  79500 150192    0    0     0     0 1015   33  0  1 99  0  0
     0  0      0 261384  79500 150192    0    0     0     0 1008   30  0  0 100  0  0
     0  0      0 261384  79500 150192    0    0     0     0 1015   32  0  0 100  0  0
     0  0      0 363436  79500  47732    0    0     0    12 1018   45  0  2 98  0  0
     0  0      0 363436  79508  47732    0    0     0     0 1011   55  0  1 99  0  0
     0  0      0 363436  79508  47732    0    0     0     0 1008   29  0  0 100  0  0

    注:程序运行时系统给它分配了100MB的内存,所以此时的active从47728kb变到了150192kb.

     

    三)vmstat用法:

    查看系统已经fork了多少次
    vmstat -f
    processes 114688
    注:这个数据是从/proc/stat中的processes字段里取得的.

    查看内存的active和inactive
    vmstat -a
    procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
     r  b   swpd   free  inact active   si   so    bi    bo   in   cs us sy id wa st
     0  0      0 361952  80536  48396    5  140   255   441 1031   87  6  8 85  1  0
    注:inact和active的数据来自于/proc/meminfo.

    查看内存使用的详细信息
    vmstat -s
           515600  total memory
           154020  used memory
            48396  active memory
            80600  inactive memory
           361580  free memory
            46376  buffer memory
            57352  swap cache
          1052248  total swap
                0  used swap
          1052248  free swap
            31352 non-nice user cpu ticks
              167 nice user cpu ticks
            43234 system cpu ticks
           489636 idle cpu ticks
             5509 IO-wait cpu ticks
             1243 IRQ cpu ticks
             1751 softirq cpu ticks
                0 stolen cpu ticks
          1451094 pages paged in
          2514952 pages paged out
             6822 pages swapped in
           198826 pages swapped out
          5905614 interrupts
           498241 CPU context switches
       1300715746 boot time
           114723 forks
    注:这些信息的分别来自于/proc/meminfo,/proc/stat和/proc/vmstat.


    查看磁盘的读/写
    vmstat -d
    disk- ------------reads------------ ------------writes----------- -----IO------
           total merged sectors      ms  total merged sectors      ms    cur    sec
    ram0       0      0       0       0      0      0       0       0      0      0
    ram1       0      0       0       0      0      0       0       0      0      0
    ram2       0      0       0       0      0      0       0       0      0      0
    ram3       0      0       0       0      0      0       0       0      0      0
    ram4       0      0       0       0      0      0       0       0      0      0
    ram5       0      0       0       0      0      0       0       0      0      0
    ram6       0      0       0       0      0      0       0       0      0      0
    ram7       0      0       0       0      0      0       0       0      0      0
    ram8       0      0       0       0      0      0       0       0      0      0
    ram9       0      0       0       0      0      0       0       0      0      0
    ram10      0      0       0       0      0      0       0       0      0      0
    ram11      0      0       0       0      0      0       0       0      0      0
    ram12      0      0       0       0      0      0       0       0      0      0
    ram13      0      0       0       0      0      0       0       0      0      0
    ram14      0      0       0       0      0      0       0       0      0      0
    ram15      0      0       0       0      0      0       0       0      0      0
    sda    26411  18657 2900913  144728  22982 605889 5030968 3128488      0    117
    hdc      143     94    1276     357      0      0       0       0      0      0
    fd0        0      0       0       0      0      0       0       0      0      0
    md0        0      0       0       0      0      0       0       0      0      0

    注:这些信息主要来自于/proc/diskstats.
    merged:表示一次来自于合并的写/读请求,一般系统会把多个连接/邻近的读/写请求合并到一起来操作.

    查看/dev/sda1磁盘的读/写
    vmstat -p /dev/sda1
    sda1          reads   read sectors  writes    requested writes
                   35215    2842778     430114    3440912
                  
    注:这些信息主要来自于/proc/diskstats
    reads:来自于这个分区的读的次数.
    read sectors:来自于这个分区的读扇区的次数.
    writes:来自于这个分区的写的次数.
    requested writes:来自于这个分区的写请求次数.


    查看系统的slab信息
    vmstat -m
    Cache                       Num  Total   Size  Pages
    rpc_buffers                   8      8   2048      2
    rpc_tasks                     8     20    192     20
    rpc_inode_cache               6      9    448      9
    ip_fib_alias                 14    113     32    113
    ip_fib_hash                  14    113     32    113
    fib6_nodes                   24    113     32    113
    ip6_dst_cache                16     30    256     15
    ndisc_cache                   1     20    192     20
    RAWv6                         4     11    704     11
    UDPv6                         2      6    640      6
    tw_sock_TCPv6                 0      0    128     30
    request_sock_TCPv6            0      0    128     30
    TCPv6                         3      3   1280      3
    dm_tio                        0      0     16    203
    dm_io                         0      0     20    169
    jbd_4k                        0      0   4096      1
    scsi_cmd_cache                1     12    320     12
    sgpool-128                   32     32   2048      2
    sgpool-64                    32     32   1024      4
    sgpool-32                    32     32    512      8
    sgpool-16                    32     45    256     15
    sgpool-8                     34     60    128     30
    scsi_io_context               0      0    104     37
    ext3_inode_cache          21829  21832    492      8
    ext3_xattr                   36     78     48     78
    journal_handle                2    169     20    169
    journal_head                 63     72     52     72
    revoke_table                  2    254     12    254
    revoke_record                 0      0     16    203
    uhci_urb_priv                 0      0     28    127
    UNIX                         56     63    448      9
    flow_cache                    0      0    128     30
    cfq_ioc_pool                  0      0     92     42
    cfq_pool                      0      0     96     40
    crq_pool                      0      0     44     84
    deadline_drq                 63    252     44     84
    as_arq                        0      0     56     67
    mqueue_inode_cache            1      7    576      7
    isofs_inode_cache             2     20    368     10
    hugetlbfs_inode_cache         1     11    340     11
    ext2_inode_cache              0      0    476      8
    ext2_xattr                    0      0     48     78
    dnotify_cache                 2    169     20    169
    Cache                       Num  Total   Size  Pages
    dquot                         0      0    128     30
    eventpoll_pwq                 1    101     36    101
    eventpoll_epi                 1     30    128     30
    inotify_event_cache           0      0     28    127
    inotify_watch_cache           1     92     40     92
    kioctx                        0      0    192     20
    kiocb                         0      0    128     30
    fasync_cache                  0      0     16    203
    shmem_inode_cache           239    243    436      9
    posix_timers_cache            0      0     88     44
    uid_cache                     5     59     64     59
    ip_mrt_cache                  0      0    128     30
    tcp_bind_bucket               7    203     16    203
    inet_peer_cache               0      0     64     59
    secpath_cache                 0      0     32    113
    xfrm_dst_cache                0      0    320     12
    ip_dst_cache                  5     15    256     15
    arp_cache                     2     20    192     20
    RAW                           2      7    512      7
    UDP                           8     14    512      7
    tw_sock_TCP                   0      0    128     30
    request_sock_TCP              0      0    128     30
    TCP                           6      7   1152      7
    blkdev_ioc                    6    127     28    127
    blkdev_queue                 20     20    956      4
    blkdev_requests             100    184    172     23
    biovec-256                    7      8   3072      2
    biovec-128                    7     10   1536      5
    biovec-64                     7     10    768      5
    biovec-16                     7     20    192     20
    biovec-4                      7     59     64     59
    biovec-1                     71    406     16    203
    bio                         342    390    128     30
    utrace_engine_cache           0      0     32    113
    utrace_cache                  0      0     32    113
    sock_inode_cache            104    110    384     10
    skbuff_fclone_cache          10     10    384     10
    skbuff_head_cache           120    120    192     20
    file_lock_cache               3     40     96     40
    Acpi-Operand                448    552     40     92
    Acpi-ParseExt                 0      0     44     84
    Acpi-Parse                    0      0     28    127
    Acpi-State                    0      0     44     84
    Cache                       Num  Total   Size  Pages
    Acpi-Namespace              337    338     20    169
    delayacct_cache              78     78     48     78
    taskstats_cache              19     53     72     53
    proc_inode_cache             19     99    356     11
    sigqueue                     17     27    144     27
    radix_tree_node            2319   2422    276     14
    bdev_cache                   23     28    512      7
    sysfs_dir_cache            2928   2940     44     84
    mnt_cache                    28     30    128     30
    inode_cache                 692    792    340     11
    dentry_cache              24563  24563    136     29
    filp                        830    980    192     20
    names_cache                   3      3   4096      1
    avc_node                     14     72     52     72
    selinux_inode_security      636    780     48     78
    key_jar                      11     30    128     30
    idr_layer_cache             100    116    136     29
    buffer_head                8996   9000     52     72
    mm_struct                    61     63    448      9
    vm_area_struct             1788   1932     84     46
    fs_cache                     59     59     64     59
    files_cache                  60     60    384     10
    signal_cache                 81     81    448      9
    sighand_cache                72     72   1344      3
    task_struct                  78     78   1360      3
    anon_vma                    794   1016     12    254
    pgd                          47     47   4096      1
    pid                          92    101     36    101
    size-131072(DMA)              0      0 131072      1
    size-131072                   0      0 131072      1
    size-65536(DMA)               0      0  65536      1
    size-65536                    1      1  65536      1
    size-32768(DMA)               0      0  32768      1
    size-32768                    1      1  32768      1
    size-16384(DMA)               0      0  16384      1
    size-16384                    1      1  16384      1
    size-8192(DMA)                0      0   8192      1
    size-8192                     0      0   8192      1
    size-4096(DMA)                0      0   4096      1
    size-4096                    92     92   4096      1
    size-2048(DMA)                0      0   2048      2
    size-2048                   234    234   2048      2
    size-1024(DMA)                0      0   1024      4
    Cache                       Num  Total   Size  Pages
    size-1024                   176    176   1024      4
    size-512(DMA)                 0      0    512      8
    size-512                    264    264    512      8
    size-256(DMA)                 0      0    256     15
    size-256                    300    300    256     15
    size-128(DMA)                 0      0    128     30
    size-128                   1200   1200    128     30
    size-64(DMA)                  0      0     64     59
    size-32(DMA)                  0      0     32    113
    size-64                    1013   1180     64     59
    size-32                    1856   1921  &nbs

  • 诊断 CPU、内存或磁盘瓶颈的流程图(zt)

    2011-11-30 12:54:47


    诊断 CPU、内存或磁盘瓶颈的流程图(zt)


     

    从步骤1开始,首先查看CPU使用情况,按照诊断CPU、内存或磁盘瓶颈的指导进行操作。对于下面的每个步骤,查找一端时间内的趋势,从中收集系统运行性能较差时的数据。另外,只有将这些数据与系统正常运行时收集的数据进行比较时才能进行准确的诊断。

    步骤1

    # sar -u [interval] [iterations]
    (示例
    : sar -u 5 30)
    %idle是否很低?这是CPU未在运行任何进程的时间百分比。在一端时间内%idle为零可能是CPU瓶颈的第一个指示。

    不是->系统未发生CPU瓶颈。转至步骤3。
    是->系统可能发生了CPU、内存或I/O瓶颈。转至步骤2。

    步骤2

    %usr是否较高?很多系统正常情况下花费80%的CPU时间用于用户,20%用于系统。其他系统通常会使用80%左右的用户时间。

    不是->系统可能遇到CPU、内存或I/O瓶颈。转至步骤3。
    是->系统可能由于用户进程遇到CPU瓶颈。转至部分3,部分A, 调整系统的CPU瓶颈。

    步骤3

    %wio的值是否大于15?

    是->以后记住这个值。它可能表示磁盘或磁带瓶颈。转至步骤4。
    不是->转至步骤4。

    步骤4

    # sar -d [interval] [iterations]
    用于任何磁盘的%busy是否都大于50? (请记住,50%指示一个大概的 指南,它可能远远高于您系统的正常值。在某些系统上,甚至%busy值为20可能就表示发生了磁盘瓶颈,而其他系统正常情况下可能就为50% busy。)对于同一个磁盘上,avwait是否大于avserv?

    不是->很可能不是磁盘瓶颈,转至步骤6。
    是->此设备上好像发生了IO瓶颈。
    转至步骤5。

    步骤5

    系统上存在磁盘瓶颈,发生瓶颈的磁盘上有哪些内容?

    原始分区,
    文件系统->转至部分3,部分B,调整发生磁盘IO瓶颈的系统。
    Swap ->可能是由于内存瓶颈导致的。
    转至步骤6。

    步骤6

    # vmstat [interval] [iterations]
    在很长的一端时间内,po是否总是大于0
    ?
    对于一个s800系统(free * 4k)是否小于2 MB,

    (对于s700系统free * 4k是否小于1 MB)?
    (值2 MB和1 MB指示大概的指南,真正的LOTSFREE值,即系统开始发生paging的值是在系统引导时计算的,它是基于系统内存的大小的。)

    不是->如果步骤1中的%idle较低,系统则很可能发生了CPU瓶颈。
    转至部分3,部分A,调整发生了CPU瓶颈的系统。
    如果%idle不是很低,则可能不是CPU、磁盘IO或者内存瓶颈。
    请转至部分4,其他瓶颈。
    是->系统上存在内存瓶颈,转至部分3部分C,调整发生内存瓶颈的系统。



    转自:http://blog.csdn.net/macky0668/article/details/6720105

  • Linux TCP 连接数修改 使用支持高并发网络I/O的编程技术

    2011-11-30 12:47:37



    3、使用支持高并发网络I/O的编程技术
     
       在Linux上编写高并发TCP连接应用程序时,必须使用合适的网络I/O技术和I/O事件分派机制。
     
       可用的I/O技术有同步I/O,非阻塞式同步I/O(也称反应式I/O),以及异步I/O。在高TCP并发的情形下,如果使用同步I/O,这会严重阻塞程序的运转,除非为每个TCP连接的I/O创建一个线程。但是,过多的线程又会因系统对线程的调度造成巨大开销。因此,在高TCP并发的情形下使用同步I/O是不可取的,这时可以考虑使用非阻塞式同步I/O或异步I/O。非阻塞式同步I/O的技术包括使用select(),poll(),epoll等机制。异步I/O的技术就是使用AIO
     
       从I/O事件分派机制来看,使用select()是不合适的,因为它所支持的并发连接数有限(通常在1024个以内)。如果考虑性能,poll()也是不合适的,尽管它可以支持的较高的TCP并发数,但是由于其采用“轮询”机制,当并发数较高时,其运行效率相当低,并可能存在I/O事件分派不均,导致部分TCP连接上的I/O出现“饥饿”现象。而如果使用epoll或AIO,则没有上述问题(早期Linux内核的AIO技术实现是通过在内核中为每个I/O请求创建一个线程来实现的,这种实现机制在高并发TCP连接的情形下使用其实也有严重的性能问题。但在最新的Linux内核中,AIO的实现已经得到改进)
     
       综上所述,在开发支持高并发TCP连接的Linux应用程序时,应尽量使用epoll或AIO技术来实现并发的TCP连接上的I/O控制,这将为提升程序对高并发TCP连接的支持提供有效的I/O保证。


    Linux  TCP 连接数修改
     
    一、           文件数限制修改
    (1)   vi /etc/security/limits.conf
    *  soft nofile 10240
       *  hard nofile 10240
     
    (2) vi /etc/pam.d/login
    session required /lib/security/pam_limits.so
     
    二、           网络端口限制修改
    (1) vi /etc/rc.d/rc.local
    /sbin/modprobe ip_conntrack  # 加载 ip_contrack 模块
    # /sbin/sysctl –p              # 使 /etc/sysctl.conf 的配置生效,根据实际情况来决定是否添加此命令
     
    [root@AS4U8 ~]# sysctl -a | grep "net.ipv4.ip"
    net.ipv4.ip_conntrack_max = 16384
    这表明将系统对最大跟踪的TCP连接数限制默认为16384。请注意,此限制值要尽量小,以节省对内核内存的占用
     
    (2) vi /etc/sysctl.conf
    net.ipv4.ip_local_port_range = 1024 65000
    net.ipv4.ip_conntrack_max = 10240
    此限制值要尽量小,以节省对内核内存的占用。
     
     
    详细解说:
    1、修改用户进程可打开文件数限制
       在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄)。可使用ulimit命令查看系统允许当前用户进程打开的文件数限制:
       [speng@as4 ~]$ ulimit -n
       1024
       这表示当前用户的每个进程最多允许同时打开1024个文件,这1024个文件中还得除去每个进程必然打开的标准输入,标准输出,标准错误,服务器监听socket,进程间通讯的unix域socket等文件,那么剩下的可用于客户端socket连接的文件数就只有大概1024-10=1014个左右。也就是说缺省情况下,基于Linux的通讯程序最多允许同时1014个TCP并发连接。
     
       对于想支持更高数量的TCP并发连接的通讯处理程序,就必须修改Linux对当前用户的进程同时打开的文件数量的软限制(soft limit)和硬限制(hardlimit)。其中软限制是指Linux在当前系统能够承受的范围内进一步限制用户同时打开的文件数;硬限制则是根据系统硬件资源状况(主要是系统内存)计算出来的系统最多可同时打开的文件数量。通常软限制小于或等于硬限制。
     
       修改上述限制的最简单的办法就是使用ulimit命令:
       [speng@as4 ~]$ ulimit -n <file_num>
       上述命令中,在<file_num>中指定要设置的单一进程允许打开的最大文件数。如果系统回显类似于“Operation notpermitted”之类的话,说明上述限制修改失败,实际上是因为在<file_num>中指定的数值超过了Linux系统对该用户打开文件数的软限制或硬限制。因此,就需要修改Linux系统对用户的关于打开文件数的软限制和硬限制。
     
       第一步,修改/etc/security/limits.conf文件,在文件中添加如下行:
       speng soft nofile 10240
       speng hard nofile 10240
       其中speng指定了要修改哪个用户的打开文件数限制,可用'*'号表示修改所有用户的限制;soft或hard指定要修改软限制还是硬限制;10240则指定了想要修改的新的限制值,即最大打开文件数(请注意软限制值要小于或等于硬限制)。修改完后保存文件。
     
       第二步,修改/etc/pam.d/login文件,在文件中添加如下行:
       session required /lib/security/pam_limits.so
       这是告诉Linux在用户完成系统登录后,应该调用pam_limits.so模块来设置系统对该用户可使用的各种资源数量的最大限制(包括用户可打开的最大文件数限制),而pam_limits.so模块就会从/etc/security/limits.conf文件中读取配置来设置这些限制值。修改完后保存此文件。
     
       第三步,查看Linux系统级的最大打开文件数限制,使用如下命令:
       [speng@as4 ~]$ cat /proc/sys/fs/file-max
       12158
       这表明这台Linux系统最多允许同时打开(即包含所有用户打开文件数总和)12158个文件,是Linux系统级硬限制,所有用户级的打开文件数限制都不应超过这个数值。通常这个系统级硬限制是Linux系统在启动时根据系统硬件资源状况计算出来的最佳的最大同时打开文件数限制,如果没有特殊需要,不应该修改此限制,除非想为用户级打开文件数限制设置超过此限制的值。修改此硬限制的方法是修改/etc/rc.local脚本,在脚本中添加如下行:
       echo 22158 > /proc/sys/fs/file-max
       这是让Linux在启动完成后强行将系统级打开文件数硬限制设置为22158。修改完后保存此文件。
     
       完成上述步骤后重启系统,一般情况下就可以将Linux系统对指定用户的单一进程允许同时打开的最大文件数限制设为指定的数值。如果重启后用ulimit-n命令查看用户可打开文件数限制仍然低于上述步骤中设置的最大值,这可能是因为在用户登录脚本/etc/profile中使用ulimit-n命令已经将用户可同时打开的文件数做了限制。由于通过ulimit-n修改系统对用户可同时打开文件的最大数限制时,新修改的值只能小于或等于上次ulimit-n设置的值,因此想用此命令增大这个限制值是不可能的。所以,如果有上述问题存在,就只能去打开/etc/profile脚本文件,在文件中查找是否使用了ulimit-n限制了用户可同时打开的最大文件数量,如果找到,则删除这行命令,或者将其设置的值改为合适的值,然后保存文件,用户退出并重新登录系统即可。
       通过上述步骤,就为支持高并发TCP连接处理的通讯处理程序解除关于打开文件数量方面的系统限制。
     
    2、修改网络内核对TCP连接的有关限制
     
       在Linux上编写支持高并发TCP连接的客户端通讯处理程序时,有时会发现尽管已经解除了系统对用户同时打开文件数的限制,但仍会出现并发TCP连接数增加到一定数量时,再也无法成功建立新的TCP连接的现象。出现这种现在的原因有多种。
     
       第一种原因可能是因为Linux网络内核对本地端口号范围有限制。此时,进一步分析为什么无法建立TCP连接,会发现问题出在connect()调用返回失败,查看系统错误提示消息是“Can't assign requested address”。同时,如果在此时用tcpdump工具监视网络,会发现根本没有TCP连接时客户端发SYN包的网络流量。这些情况说明问题在于本地Linux系统内核中有限制。其实,问题的根本原因在于Linux内核的TCP/IP协议实现模块对系统中所有的客户端TCP连接对应的本地端口号的范围进行了限制(例如,内核限制本地端口号的范围为1024~32768之间)。当系统中某一时刻同时存在太多的TCP客户端连接时,由于每个TCP客户端连接都要占用一个唯一的本地端口号(此端口号在系统的本地端口号范围限制中),如果现有的TCP客户端连接已将所有的本地端口号占满,则此时就无法为新的TCP客户端连接分配一个本地端口号了,因此系统会在这种情况下在connect()调用中返回失败,并将错误提示消息设为“Can't assign requested address”。有关这些控制逻辑可以查看Linux内核源代码,以linux2.6内核为例,可以查看tcp_ipv4.c文件中如下函数:
       static int tcp_v4_hash_connect(struct sock *sk)
       请注意上述函数中对变量sysctl_local_port_range的访问控制。变量sysctl_local_port_range的初始化则是在tcp.c文件中的如下函数中设置:
       void __init tcp_init(void)
       内核编译时默认设置的本地端口号范围可能太小,因此需要修改此本地端口范围限制。
       第一步,修改/etc/sysctl.conf文件,在文件中添加如下行:
       net.ipv4.ip_local_port_range = 1024 65000
       这表明将系统对本地端口范围限制设置为1024~65000之间。请注意,本地端口范围的最小值必须大于或等于1024;而端口范围的最大值则应小于或等于65535。修改完后保存此文件。
       第二步,执行sysctl命令:
       [speng@as4 ~]$ sysctl -p
       如果系统没有错误提示,就表明新的本地端口范围设置成功。如果按上述端口范围进行设置,则理论上单独一个进程最多可以同时建立60000多个TCP客户端连接。
     
       第二种无法建立TCP连接的原因可能是因为Linux网络内核的IP_TABLE防火墙对最大跟踪的TCP连接数有限制。此时程序会表现为在connect()调用中阻塞,如同死机,如果用tcpdump工具监视网络,也会发现根本没有TCP连接时客户端发SYN包的网络流量。由于IP_TABLE防火墙在内核中会对每个TCP连接的状态进行跟踪,跟踪信息将会放在位于内核内存中的conntrackdatabase中,这个数据库的大小有限,当系统中存在过多的TCP连接时,数据库容量不足,IP_TABLE无法为新的TCP连接建立跟踪信息,于是表现为在connect()调用中阻塞。此时就必须修改内核对最大跟踪的TCP连接数的限制,方法同修改内核对本地端口号范围的限制是类似的:
       第一步,修改/etc/sysctl.conf文件,在文件中添加如下行:
       net.ipv4.ip_conntrack_max = 10240
       这表明将系统对最大跟踪的TCP连接数限制设置为10240。请注意,此限制值要尽量小,以节省对内核内存的占用。
       第二步,执行sysctl命令:
       [speng@as4 ~]$ sysctl -p
       如果系统没有错误提示,就表明系统对新的最大跟踪的TCP连接数限制修改成功。如果按上述参数进行设置,则理论上单独一个进程最多可以同时建立10000多个TCP客户端连接。



    转自:http://blog.csdn.net/macky0668/article/details/6802329
  • 长连接和Keepalive

    2011-11-29 18:02:45




    TCP协议中有长连接和短连接之分。短连接在数据包发送完成后就会自己断开,长连接在发包完毕后,会在一定的时间内保持连接,即我们通常所说的Keepalive(存活定时器)功能。
    默认的Keepalive超时需要7,200,000 milliseconds,即2小时,探测次数为5次。它的功效和用户自己实现的心跳机制是一样的。开启Keepalive功能需要消耗额外的宽带和流量,尽管这微不足道,但在按流量计费的环境下增加了费用,另一方面,Keepalive设置不合理时可能会因为短暂的网络波动而断开健康的TCP连接。

    keepalive并不是TCP规范的一部分。在Host Requirements RFC罗列有不使用它的三个理由:(1)在短暂的故障期间,它们可能引起一个良好连接(good connection)被释放(dropped),(2)它们消费了不必要的宽带,(3)在以数据包计费的互联网上它们(额外)花费金钱。然而,在许多的实现中提供了存活定时器。

    一些服务器应用程序可能代表客户端占用资源,它们需要知道客户端主机是否崩溃。存活定时器可以为这些应用程序提供探测服务。Telnet服务器和Rlogin服务器的许多版本都默认提供存活选项。

    个人计算机用户使用TCP/IP协议通过Telnet登录一台主机,这是能够说明需要使用存活定时器的一个常用例子。如果某个用户在使用结束时只是关掉了电源,而没有注销(log off),那么他就留下了一个半打开(half-open)的连接。如果客户端消失,留给了服务器端半打开的连接,并且服务器又在等待客户端的数据,那么等待将永远持续下去。存活特征的目的就是在服务器端检测这种半打开连接。

    也可以在客户端设置存活器选项,且没有不允许这样做的理由,但通常设置在服务器。如果连接两端都需要探测对方是否消失,那么就可以在两端同时设置(比如NFS)。



    keepalive工作原理:

    若在一个给定连接上,两小时之内无任何活动,服务器便向客户端发送一个探测段。(我们将在下面的例子中看到探测段的样子。)客户端主机必须是下列四种状态之一:

    1) 客户端主机依旧活跃(up)运行,并且从服务器可到达。从客户端TCP的正常响应,服务器知道对方仍然活跃。服务器的TCP为接下来的两小时复位存活定时器,如果在这两个小时到期之前,连接上发生应用程序的通信,则定时器重新为往下的两小时复位,并且接着交换数据。

    2) 客户端已经崩溃,或者已经关闭(down),或者正在重启过程中。在这两种情况下,它的TCP都不会响应。服务器没有收到对其发出探测的响应,并且在75秒之后超时。服务器将总共发送10个这样的探测,每个探测75秒。如果没有收到一个响应,它就认为客户端主机已经关闭并终止连接。

    3) 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。

    4) 客户端主机活跃运行,但从服务器不可到达。这与状态2类似,因为TCP无法区别它们两个。它所能表明的仅是未收到对其探测的回复。

     

    服务器不必担心客户端主机被关闭然后重启的情况(这里指的是操作员执行的正常关闭,而不是主机的崩溃)。当系统被操作员关闭时,所有的应用程序进程(也就是客户端进程)都将被终止,客户端TCP会在连接上发送一个FIN。收到这个FIN后,服务器TCP向服务器进程报告一个文件结束,以允许服务器检测这种状态。

    在第一种状态下,服务器应用程序不知道存活探测是否发生。凡事都是由TCP层处理的,存活探测对应用程序透明,直到后面234三种状态发生。在这三种状态下,通过服务器的TCP,返回给服务器应用程序错误信息。(通常服务器向网络发出一个读请求,等待客户端的数据。如果存活特征返回一个错误信息,则将该信息作为读操作的返回值返回给服务器。)在状态2,错误信息类似于“连接超时”。状态3则为“连接被对方复位”。第四种状态看起来像连接超时,或者根据是否收到与该连接相关的ICMP错误信息,而可能返回其它的错误信息。

    linux内核包含对keepalive的支持。其中使用了三个参数:tcp_keepalive_time(开启keepalive的闲置时 长)tcp_keepalive_intvlkeepalive探测包的发送间隔)和tcp_keepalive_probes (如果对方不予应答,探测包的发送次数);在liunx中,keepalive是一个开关选项,可以通过函数来使能。具体地说,可以使用以下代码:
    setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));

    tcp检测到对端socket不再可用时(不能发出探测包,或探测包没有收到ACK的响应包),select会返回socket可读,并且在recv时返回-1,同时置上errnoETIMEDOUT。此时TCP的状态是断开的。



    keepalive参数设置代码如下:
    // 开启KeepAlive
    BOOL bKeepAlive = TRUE;
    int nRet = ::setsockopt(socket_handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&bKeepAlive, sizeof(bKeepAlive));
    if (nRet == SOCKET_ERROR)
    {
    return FALSE;
    }

    // 设置KeepAlive参数
    tcp_keepalive alive_in                = {0};
    tcp_keepalive alive_out                
    = {0};
    alive_in.keepalivetime                
    = 5000;                // 开始首次KeepAlive探测前的TCP空闭时间
    alive_in.keepaliveinterval        = 1000;                // 两次KeepAlive探测间的时间间隔
    alive_in.onoff                                = TRUE;
    unsigned 
    long ulBytesReturn = 0;
    nRet 
    = WSAIoctl(socket_handle, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
    &alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);
    if (nRet == SOCKET_ERROR)
    {
    return FALSE;
    }

    开启Keepalive选项之后,对于使用IOCP模型的服务器端程序来说,一旦检测到连接断 开,GetQueuedCompletionStatus函数将立即返回FALSE,使得服务器端能及时清除该连接、释放该连接相关的资源。对于使用 select模型的客户端来说,连接断开被探测到时,以recv目的阻塞在socket上的select方法将立即返回SOCKET_ERROR,从而得 知连接已失效,客户端程序便有机会及时执行清除工作、提醒用户或重新连接。

    TCP连接非正常断开的检测(KeepAlive探测)

    此处的”非正常断开”指TCP连接不是以优雅的方式断开,如网线故障等物理链路的原因,还有突然主机断电等原因

    有两种方法可以检测:1.TCP连接双方定时发握手消息 2.利用TCP协议栈中的KeepAlive探测

    第二种方法简单可靠,只需对TCP连接两个Socket设定KeepAlive探测。


    在windows下使用,要包含MSTcpIP.h的头文件。点击下面的链接即可下载这个文件
      MSTcpIP

    备注:长连接虽好,但是比较好用但是占用系统资源比较大。个人建议如无特殊需要,用自己的心跳包机制最好


    评论

    # re: 长连接和Keepalive 2011-08-26 17:45 
    你好, 请问一下 我现在 通过web访问 apache 然后 apache去交互另外一个server(可能是脚本).需要登录验证 然后返回DataInfo.这样apache接受到信息后 就与另一个server断开了链接。这个server有时候会返回一些必要的信息到apache,但是开始交互的TCP协议交互完就断开了。
    我先用keepalive 绑定 apache与 交互的另一个server(可能是接口)一直长连接 来实现。
    不知道这个可以实现吗?


    http://www.cppblog.com/zhangyq/archive/2010/02/28/108615.html




    Nginx设置Keep-Alive为close




    nginx不能在响应头部添加Keep-Alive,详见:http://wiki.nginx.org/HttpCoreModule#keepalive_timeout

    http1.1 中默认的keep-alive为connection(使用持久化连接),在http1.0中则默认为close,在大并发量的情况下可能需要将客户端的 连接close掉,以保障服务器的正常运转。(因为每一台服务器它所能建立的最大连接数是有上限的,lnux下ulimit n xxx)

    以腾讯首页为例,就有很多是请求是在客户端发生请求后,服务器响应完就立即关闭了。

    image

    nginx不像apache,直接有指令keep-alive off/on;它使用的是keepalive_timeout [time],默认的时长为75,可以在http、server、location使用此指令。

     

    在本机进行的模拟测试:

    nginx.conf指定的VHOST中添加了规则:

    location /gtj/ {
        alias C:/phpApp/gtj/;
        keepalive_timeout  0;
        expires 5m;
    }

    客户端请求后,可以用httpwatch抓取返回的头部信息:

    image








    转自:
    http://www.20ju.com/content/V170118.htm




  • 从PROC文件系统与SYSFS系统获得系统运行时数据

    2011-11-23 15:11:10

    从PROC文件系统与SYSFS系统获得系统运行时数据




    ===================
    - PROC文件系统介绍
    ===================

    ; 显示内存信息,对对应命令: vmstat/free
    $ cat /proc/meminfo
    $ cat /proc/vmstat
    $ cat /proc/vmmemctl

    ; 显示设备相关信息
    $ cat /proc/devices

    ; 显示磁盘相关信息,第二条命令显示了分区名称,主要设备号与次要设备号,对应命令: fdisk -l
    $ cat /proc/diskstats
    $ cat /proc/partitions

    ; 显示启动时间
    $ cat /proc/uptime
    $ cat /proc/version

    ; 显示系统中断以及相关信息,用于查看设备所请求的IRQ中断,其中'I8042'为键盘
    ; 第二个命令显示系统IO所占用的地址范围
    ; 第三个命令查看系统设备读写的地址空间,编程会用得着
    $ cat /proc/interrupts
    $ cat /proc/ioports
    $ cat /proc/iomem

    ; 查看CPU信息,查看CPU对指令集的支持
    $ cat /proc/cpuinfo | awk '/flags/'
    $ cat /proc/cpuinfo | awk '/vendor/'
    $ cat /proc/cpuinfo | awk '/MHz/'

    ; 查看内核所编译的文件系统,即,查看内核所支持的文件系统
    $ cat /proc/filesystems

    ; 查看系统装载的模块,对应命令: lsmod
    $ cat /proc/modules

    ; 查看系统平均负载
    $ cat /proc/loadavg
    ; 查看系统启动命令行,传送到内核的命令行参数
    $ cat /proc/cmdline

    ; 系统调用列表
    $ cat /proc/kallsyms


    + 网络
    ; 显示系统ARP表,"HWADDR"全0表示IP地址未被占用
    $ cat /proc/net/arp
    ; 显示SNMP相关信息,上面一行表示各个字段,下面一行表示值,以下同
    $ cat /proc/net/snmp
    ; 显示接口总流量
    $ cat /proc/net/dev
    ; 显示路由表,注意,这里显示的不是点分10进制,而10完全16进制
    $ cat /proc/net/route
    ; 显示无线相关信息,包含接收到的AP,信号质量等
    $ cat /proc/net/wireless

    + 进程<CPU/IO/Fd>
    ; 基准目录<vw>: /proc/#Pid/
    ; 查看内存映射表,包括其对动态链接库的引用,堆栈的位置,可以用于故障排除
    $ cat $vw/maps
    $ cat $vw/smaps
    ; 查看进程运作状况,如SLEEP参数表明了进程的繁忙程度
    $ cat $vw/status
    ; 查看进程的IO情况,也可以通过此查看进程是否为IO密集型进程
    $ cat $vw/io
    ; 查看进程打开的文件,对对应命令: lsof
    $ ls $vw/fd
    ; 查看进程工作目录
    $ ls -l $vw/cwd
    ; 查看进程可执行文件
    $ ls -l $vw/exe
    ; 查看传入进程的环境变量
    $ cat $vw/environ
    ; 查看传入进程的命令行
    $ cat $vw/cmdline | tr "\000" "\n"
    ; 查看对进程的限制,如打开文件数,运行作业数等
    $ cat $vw/limits
    ; 查看进程锁定的元素
    $ cat $vw/locks

    + 设备
    ; 查看光驱相关信息,注意DRIVENAME,进行挂载时用得着
    $ cat /proc/sys/dev/cdrom/info

    + 总线
    ; 查看PCI总线,对应命令: lspci/setpci
    $ cat /proc/bus/pci/devices
    ; 查看USB总线,对应命令: lsusb
    $ cat /proc/bus/usb/devices
    ; 查看键盘,鼠标,扬声器
    $ cat /proc/bus/input/devices
    $ cat /proc/bus/input/handler
    ; 查看SCSI总线
    $ cat /proc/scsi/scsi
    ; 查看SCSI设备
    $ cat /proc/scsi/device_info
    =====================
    * SYS 文件系统
    =====================

    ; 查看网卡原始MAC
    $ cat /sys/class/net/ethX/address
    ; 查看网卡统计数据
    $ cat /sys/class/net/ethX/statistics/*
    ; 查看接口状态
    $ cat /sys/class/net/ethX/operstate
     
    举个小例子
    这段代码统计在10秒内ETH0接口接收的网络流量,单位是BPS
    #!/bin/bash
    cd /sys/class/net/eth0/statistics
    startRX=`cat rx_bytes`
    sleep 10
    endRX=`cat rx_bytes`
    bytesTotal=`expr $endRX - $startRX`
    bps=`expr $bytesTotal '/' 10`
    echo "The average traffic is RX: ${bps}Bytes/sec"
      后记:从上文可以看到,LINUX性能数据收集工具均是从/PROC文件系统读取性能数据,另外,既然已经知道系统性能数据来源,在系统中没有安装这些工 具的情况下,我们也可以自行编写脚本进行数据采集了,另外,在对PROC文件系统不了解的情况下,不可对PROC文件系统中的任何文件进行写操作,特别是 线上的系统,否则本人概不负责
     
    作者 “NOTHING IS SERIOUS!”

    转自:http://www.2cto.com/os/201109/102448.html







  • 淘宝开源代码: http://code.taobao.org/

    2011-11-23 15:09:26


    淘宝开源代码:
    http://code.taobao.org/

    监控工具:tsar
    http://tsar.taobao.org/

  • Linux服务器性能评估与优化

    2011-11-22 16:15:25

    Linux服务器性能评估与优化【转载】

    转载:http://www.517sou.net/Article/104.aspx
    http://blog.csdn.net/macky0668/article/details/6720772



    一、影响Linux服务器性能的因素 

    1. 操作系统级

    Ø       CPU

    Ø       内存

    Ø       磁盘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.常用组合方式 

    •           用vmstat、sar、iostat检测是否是CPU瓶颈

    •           用free、vmstat检测是否是内存瓶颈

    •           用iostat检测是否是磁盘I/O瓶颈

    •           用netstat检测是否是网络带宽瓶颈

    四、Linux性能评估与优化

     

    1. 系统整体性能评估(uptime命令)

     

    [root@web1 ~]# uptime

    16:38:00 up 118 days,  3:01,  5 users,  load average: 1.22, 1.02, 0.91

    这里需要注意的是:load average这个输出值,这三个值的大小一般不能大于系统CPU的个数,例如,本输出中系统有8个CPU,如果load average的三个值长期大于8时,说明CPU很繁忙,负载很高,可能会影响系统性能,但是偶尔大于8时,倒不用担心,一般不会影响系统性能。相反,如果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    162240   8304  67032   0    0    13    21   1007   23     0  1   98   0   0

     0  0    0    162240   8304  67032   0    0     1     0     1010   20     0  1   100 0   0

     0  0    0    162240   8304  67032   0    0     1     1     1009   18     0  1    99  0   0

    l        Procs

         r列表示运行和等待cpu时间片的进程数,这个值如果长期大于系统CPU的个数,说明CPU不足,需要增加CPU。

         b列表示在等待资源的进程数,比如正在等待I/O、或者内存交换等。

    l        Cpu

        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

                               

    对上面每项的输出解释如下:

    l        %user列显示了用户进程消耗的CPU 时间百分比。

    l        %nice列显示了运行正常进程所消耗的CPU 时间百分比。

    l        %system列显示了系统进程消耗的CPU时间百分比。

    l        %iowait列显示了IO等待所占用的CPU时间百分比

    l        %steal列显示了在内存相对紧张的环境下pagein强制对不同的页面进行的steal操作 。

    l        %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:       8111       7185        926          0        243           6299

    -/+ buffers/cache:     643       7468

    Swap:       8189          0         8189

         一般有这样一个经验公式:应用程序可用内存/系统物理内存>70%时,表示系统内存资源非常充足,不影响系统性能,应用程序可用内存/系统物理内存<20%时,表示系统内存资源紧缺,需要增加系统内存,20%<应用程序可用内存/系统物理内存<70%时,表示系统内存资源基本能满足应用需求,暂时不影响系统性能。

    3.内存性能评估

     

    (1)利用free指令监控内存

    free是监控linux内存使用状况最常用的指令,看下面的一个输出:

    [root@webserver ~]# free  -m

                    total         used       free     shared    buffers     cached

    Mem:       8111       7185        926          0        243           6299

    -/+ buffers/cache:     643       7468

    Swap:       8189          0         8189

         一般有这样一个经验公式:应用程序可用内存/系统物理内存>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    162240   8304  67032   0    0    13    21   1007   23     0  1  98   0  0

     0  0    0    162240   8304  67032   0    0     1     0     1010   20     0  1  100 0  0

     0  0    0    162240   8304  67032   0    0     1     1     1009   18     0  1  99   0  0

    l        memory

             swpd列表示切换到内存交换区的内存数量(以k为单位)。如果swpd的值不为0,或者比较大,只要si、so的值长期为0,这种情况下一般不用担心,不会影响系统性能。

             free列表示当前空闲的物理内存数量(以k为单位)

             buff列表示buffers cache的内存数量,一般对块设备的读写才需要缓冲。

             cache列表示page cached的内存数量,一般作为文件系统cached,频繁访问的文件都会被cached,如果cache值较大,说明cached的文件数较多,如果此时IO中bi比较小,说明文件系统效率比较好。

    l        swap

    si列表示由磁盘调入内存,也就是内存进入内存交换区的数量。

    so列表示由内存调入磁盘,也就是内存交换区进入内存的数量。

    一般情况下,si、so的值都为0,如果si、so的值长期不为0,则表示系统内存不足。需要增加系统内存。

    4.磁盘I/O性能评估 

    (1)磁盘存储基础

    l             熟悉RAID存储方式,可以根据应用的不同,选择不同的RAID方式。

    l             尽可能用内存的读写代替直接磁盘I/O,使频繁访问的文件或数据放入内存中进行操作处理,因为内存读写操作比直接磁盘读写的效率要高千倍。

    l             将经常进行读写的文件与长期不变的文件独立出来,分别放置到不同的磁盘设备上。

    l              对于写操作频繁的数据,可以考虑使用裸设备代替文件系统。

            

           使用裸设备的优点有:

    ü           数据可以直接读写,不需要经过操作系统级的缓存,节省了内存资源,避免了内存资源争用。

    ü           避免了文件系统级的维护开销,比如文件系统需要维护超级块、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        6479462     286537372

     

    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组合显示系统的网络运行状态

    五、Oracle在Linux下的性能优化

     

    Oracle数据库内存参数的优化

    Ø       与oracle相关的系统内核参数

    Ø       SGA、PGA参数设置

    Oracle下磁盘存储性能优化

    Ø       文件系统的选择(ext2/ext3、xfs、ocfs2)

    Ø       Oracle  ASM存储

     1.优化oracle性能参数之前要了解的情况

    1)物理内存有多大

    2)操作系统估计要使用多大内存

    3)数据库是使用文件系统还是裸设备

    4)有多少并发连接

    5)应用是OLTP类型还是OLAP类型

    2.oracle数据库内存参数的优化

    (1)系统内核参数

    修改 /etc/sysctl.conf 这个文件,加入以下的语句:

    kernel.shmmax = 2147483648

    kernel.shmmni = 4096

    kernel.shmall = 2097152

    kernel.sem = 250 32000 100 128

    fs.file-max = 65536

    net.ipv4.ip_local_port_range = 1024 65000

    参数依次为:

    Kernel.shmmax:共享内存段的最大尺寸(以字节为单位)。

    Kernel.shmmni系统中共享内存段的最大数量。

    Kernel.shmall:共享内存总量,以页为单位。

    fs.file-max:文件句柄数,表示在Linux系统中可以打开的文件数量。

    net.ipv4.ip_local_port_range:应用程序可使用的IPv4端口范围。

     

    需要注意的几个问题

    关于Kernel.shmmax

         Oracle SGA 由共享内存组成,如果错误设置 SHMMAX可能会限制SGA 的大小,SHMMAX设置不足可能会导致以下问题:ORA-27123:unable to attach to shared memory segment,如果该参数设置小于Oracle SGA设置,那么SGA就会被分配多个共享内存段。这在繁忙的系统中可能成为性能负担,带来系统问题。

         Oracle建议Kernel.shmmax最好大于sga,以让oracle共享内存区SGA在一个共享内存段中,从而提高性能。

    关于Kernel.shmall

         表示系统共享内存总大小,以页为单位。

         一个32位的Linux系统,8G的内存,可以设置kernel.shmall = 2097152,即为: 2097152*4k/1024/1024 = 8G就是说可用共享内存一共8G,这里的4K是32位操作系统一页的大小,即4096字节。

    关于Kernel.shmmni

         表示系统中共享内存段的最大数量。系统默认是4096,一般无需修改,在SUN OS下还有Kernel.shmmin参数,表示共享内存段最小尺寸,勿要混肴!
    (2)SGA、PAG参数的设置

     

    A Oracle在内存管理方面的改进

         Oracle 9i通过参数PGA_AGGREGATE_TARGET参数实现PGA自动管理  Oracle 10g通过参数SGA_TARGET参数实现了SGA的自动管理,

         Oracle 11g实现了数据库所有内存块的全自动化管理,使得动态管理SGA和PGA成为现实。

     

    自动内存管理的两个参数:

         MEMORY_TARGET:表示整个ORACLE实例所能使用的内存大小,包括PGA和SGA的整体大小,即这个参数是动态的,可以动态控制SGA和PGA的大小。

         MEMORY_MAX_TARGET:这个参数定义了MEMORY_TARGET最大可以达到而不用重启实例的值,如果没有设置MEMORY_MAX_TARGET值,默认等于MEMORY_TARGET的值。

         使用动态内存管理时,SGA_TARGET和PGA_AGGREGATE_TARGET代表它们各自内存区域的最小设置,要让Oracle完全控制内存管理,这两个参数应该设置为0。

    B Oracle五种内存管理方式

    Ø         自动内存管理,即AMM (Automatic Memory Management)

    Ø         自动共享内存管理,即ASMM(Automatic Shared Memory Management)

    Ø         手动共享内存管理

    Ø         自动PGA管理

    Ø         手动PGA管理

    自动内存管理(AMM)

    默认安装oracle11g的实例就是AMM方式。通过如下查看:

    示例如下:

    SQL> show parameters target
    NAME                                       TYPE                  VALUE
    ------------ ---------------------      ------------------    ---------------------- archive_lag_target                     integer                      0
    db_flashback_retention_target   integer                    1860
    fast_start_io_target                    integer                      0
    fast_start_mttr_target                 integer                      0
    memory_max_target                  big integer              1400M
    memory_target                          big integer              1400M

    pga_aggregate_target                big integer                0
    sga_target                                  big integer                0

    注意:如果初始化参数 LOCK_SGA = true ,则 AMM 是不可用的。

    自动共享内存管理

    自动共享内存管理是oracle10g引进的,如果要使用自动共享内存管理,只需设置MEMORY_TARGET=0,然后显式指定SGA_TARGET即可。

    示例如下:

    SQL> alter system set memory_target=0 scope=both;
    System altered.
    SQL> alter system set sga_target=1024m scope=both;
    System altered.
    SQL>

    手工共享内存管理

    Oracle9i以及以前版本,只能手工设置共享内存管理,如果要使用手动共享内存管理,首先需要设置SGA_TARGET 与 MEMORY_TARGET为0。

    SGA包含主要参数有:

    share_pool_size:共享池大小,建议300-500M之间。

    Log_buffer:日志缓冲区大小,建议1-3M之间。

    Large_pool_size:大缓冲池大小,非MTS系统,建议在20-30M之间。

    Java_pool_size:java池大小,没有java应用时,建议10-20M之间。

    db_cache_size:数据缓冲区大小,根据可使用内存大小,尽可能大。

     

    自动PAG管理

    Oracle9i版本引入了自动PGA管理,如果使用的是AMM管理方式,则无需担心PGA的配置,但是如果对对AMM管理不放心的话,可以设置自动PGA管理,设置

         WORKAREA_SIZE_POLICY = AUTO

    然后指定PGA_AGGREGATE_TARGET大小即可。,

     

    手工PAG管理

    如果要做到精确的控制PGA,还可以设置手动管理PGA,设置

    WORKAREA_SIZE_POLICY = manual

    然后分别指定PGA相关参数即可:

    PGA相关参数有:

    SORT_AREA_SIZE

    SORT_AREA_RETAINED_SIZE,

     

    3.Oracle下磁盘存储性能优化

     

    ①      选择文件系统存取数据

    文件系统的选择

         单一文件系统(ext2、ext3、xfs等)

         集群文件系统(gfs、ocfs2)

    文件系统存储优缺点:

         优点:管理维护方便。

         缺点:数据读写要经过操作系统级的缓存,效率不是很高。

    ②      ASM(Automatic Storage Management)

    ASM优点:

         数据可直接读写,无需经过操作系统存取效率很高,读写效率与直接的原始设备基本相同。

         Oracle提供了专门的管理和维护工具

    关于作者

     

     高俊峰,网名:南非蚂蚁

    IXPUB “存储设备与容灾技术”及“ Linux与开源世界”版主。

     喜欢oracle和 Unix/Linux技术,平时主要活动在ITPUB.net﹑IXPUB.net﹑ChinaUnix.net等大型技术社区,一直致力与oracle 数据库﹑Unix/Linux操作系统管理﹑优化领域,现在主要从事oracle数据库管理和项目规划设计工作,擅长oracle数据库的备份恢复,性能调优,对Unix/Linux集群应用也有一定的研究。

  • strace命令用法——strace_truss_ltrace

    2011-11-22 16:09:00

    linux的strace命令(详解)
    本文详细讲述linux下的strace命令的用法。

    strace 命令是一种强大的工具,它能够显示所有由用户空间程序发出的系统调用。
      strace 显示这些调用的参数并返回符号形式的值。strace 从内核接收信息,而且不需要以任何特殊的方式来构建内核。
      下面记录几个常用 option .
      1 -f -F选项告诉strace同时跟踪fork和vfork出来的进程
      2 -o xxx.txt 输出到某个文件。
      3 -e execve 只记录 execve 这类系统调用
      —————————————————
      进程无法启动,软件运行速度突然变慢,程序的”SegmentFault”等等都是让每个Unix系统用户头痛的问题,
      本文通过三个实际案例演示如何使用truss、strace和ltrace这三个常用的调试工具来快速诊断软件的”疑难杂症”。
      
      
      truss和strace用来跟踪一个进程的系统调用或信号产生的情况,而 ltrace用来跟踪进程调用库函数的情况。truss是早期为System V R4开发的调试程序,包括Aix、FreeBSD在内的大部分Unix系统都自带了这个工具;
      而strace最初是为SunOS系统编写的,ltrace最早出现在GNU/DebianLinux中。
      这两个工具现在也已被移植到了大部分Unix系统中,大多数Linux发行版都自带了strace和ltrace,而FreeBSD也可通过Ports安装它们。
      
      你不仅可以从命令行调试一个新开始的程序,也可以把truss、strace或ltrace绑定到一个已有的PID上来调试一个正在运行的程序。三个调试工具的基本使用方法大体相同,下面仅介绍三者共有,而且是最常用的三个命令行参数:
      
      -f :除了跟踪当前进程外,还跟踪其子进程。
      -o file :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。
      -p pid :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。
      
       使用上述三个参数基本上就可以完成大多数调试任务了,下面举几个命令行例子:
      truss -o ls.truss ls -al: 跟踪ls -al的运行,将输出信息写到文件/tmp/ls.truss中。
      strace -f -o vim.strace vim: 跟踪vim及其子进程的运行,将输出信息写到文件vim.strace。
      ltrace -p 234: 跟踪一个pid为234的已经在运行的进程。
      
       三个调试工具的输出结果格式也很相似,以strace为例:
      
      brk(0) = 0×8062aa8
      brk(0×8063000) = 0×8063000
      mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0×92f) = 0×40016000
      
      每一行都是一条系统调用,等号左边是系统调用的函数名及其参数,右边是该调用的返回值。 truss、strace和ltrace的工作原理大同小异,都是使用ptrace系统调用跟踪调试运行中的进程,详细原理不在本文讨论范围内,有兴趣可以参考它们的源代码。



    =========================================================

    http://blog.linuxmine.com/i554

    strace命令用法
     
    调用:
    strace [ -dffhiqrtttTvxx ] [ -acolumn ] [ -eexpr ] ...
    [ -ofile ] [ -ppid ] ... [ -sstrsize ] [ -uusername ] [ command [ arg ... ] ]

    strace -c [ -eexpr ] ... [ -Ooverhead ] [ -Ssortby ] [ command [ arg ... ] ]
    功能:
    跟踪程式执行时的系统调用和所接收的信号.通常的用法是strace执行一直到commande结束.
    并且将所调用的系统调用的名称、参数和返回值输出到标准输出或者输出到-o指定的文件.
    strace是一个功能强大的调试,分析诊断工具.你将发现他是一个极好的帮手在你要调试一个无法看到源码或者源码无法在编译的程序.
    你将轻松的学习到一个软件是如何通过系统调用来实现他的功能的.而且作为一个程序设计师,你可以了解到在用户态和内核态是如何通过系统调用和信号来实现程序的功能的.
    strace的每一行输出包括系统调用名称,然后是参数和返回值.这个例子:
    strace cat /dev/null
    他的输出会有:
    open(\"/dev/null\",O_RDONLY) = 3
    有错误产生时,一般会返回-1.所以会有错误标志和描述:
    open(\"/foor/bar\",)_RDONLY) = -1 ENOENT (no such file or directory)
    信号将输出喂信号标志和信号的描述.跟踪并中断这个命令\"sleep 600\":
    sigsuspend({}
    --- SIGINT (Interrupt) ---
    +++ killed by SIGINT +++
    参数的输出有些不一致.如shell命令中的 \">>tmp\",将输出:
    open(\"tmp\",O_WRONLY|O_APPEND|A_CREAT,0666) = 3
    对于结构指针,将进行适当的显示.如:\"ls -l /dev/null\":
    lstat(\"/dev/null\",{st_mode=S_IFCHR|0666},st_rdev=makdev[1,3],...}) = 0
    请注意\"struct stat\" 的声明和这里的输出.lstat的第一个参数是输入参数,而第二个参数是向外传值.
    当你尝试\"ls -l\" 一个不存在的文件时,会有:
    lstat(/foot/ball\",0xb004) = -1 ENOENT (no such file or directory)
    char*将作为C的字符串类型输出.没有字符串输出时一般是char* 是一个转义字符,只输出字符串的长度.
    当字符串过长是会使用\"...\"省略.如在\"ls -l\"会有一个gepwuid调用读取password文件:
    read(3,\"root::0:0:System Administrator:/\"...,1024) = 422
    当参数是结构数组时,将按照简单的指针和数组输出如:
    getgroups(4,[0,2,4,5]) = 4
    关于bit作为参数的情形,也是使用方括号,并且用空格将每一项参数隔开.如:
    sigprocmask(SIG_BLOCK,[CHLD TTOU],[]) = 0
    这里第二个参数代表两个信号SIGCHLD 和 SIGTTOU.如果bit型参数全部置位,则有如下的输出:
    sigprocmask(SIG_UNBLOCK,~[],NULL) = 0
    这里第二个参数全部置位.

    参数说明:
    -c 统计每一系统调用的所执行的时间,次数和出错的次数等.
    -d 输出strace关于标准错误的调试信息.
    -f 跟踪由fork调用所产生的子进程.
    -ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
    -F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
    -h 输出简要的帮助信息.
    -i 输出系统调用的入口指针.
    -q 禁止输出关于脱离的消息.
    -r 打印出相对时间关于,,每一个系统调用.
    -t 在输出中的每一行前加上时间信息.
    -tt 在输出中的每一行前加上时间信息,微秒级.
    -ttt 微秒级输出,以秒了表示时间.
    -T 显示每一调用所耗的时间.
    -v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
    -V 输出strace的版本信息.
    -x 以十六进制形式输出非标准字符串
    -xx 所有字符串以十六进制形式输出.
    -a column
    设置返回值的输出位置.默认为40.
    -e expr
    指定一个表达式,用来控制如何跟踪.格式如下:
    [qualifier=][!]value1[,value2]...
    qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的qualifier是 trace.感叹号是否定符号.例如:
    -eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none.
    注意有些shell使用!来执行历史记录里的命令,所以要使用\\.
    -e trace=set
    只跟踪指定的系统调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
    -e trace=file
    只跟踪有关文件操作的系统调用.
    -e trace=process
    只跟踪有关进程控制的系统调用.
    -e trace=network
    跟踪与网络有关的所有系统调用.
    -e strace=signal
    跟踪所有与系统信号有关的系统调用
    -e trace=ipc
    跟踪所有与进程通讯有关的系统调用
    -e abbrev=set
    设定strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.
    -e raw=set
    将指定的系统调用的参数以十六进制显示.
    -e signal=set
    指定跟踪的系统信号.默认为all.如signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
    -e read=set
    输出从指定文件中读出的数据.例如:
    -e read=3,5
    -e write=set
    输出写入到指定文件中的数据.
    -o filename
    将strace的输出写入文件filename
    -p pid
    跟踪指定的进程pid.
    -s strsize
    指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
    -u username
    以username的UID和GID执行被跟踪的命令.

     

     

    用strace调试程序

           在理想世界里,每当一个程序不能正常执行一个功能时,它就会给出一个有用的错误提示,告诉你在足够的改正错误的线索。但遗憾的是,我们不是生活在理想世界里,起码不总是生活在理想世界里。有时候一个程序出现了问题,你无法找到原因。

      这就是调试程序出现的原因。strace是一个必不可少的调试工具,strace用来监视系统调用。你不仅可以调试一个新开始的程序,也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上面)。

      首先让我们看一个真实的例子:

      [BOLD]启动KDE时出现问题[/BOLD]

      前一段时间,我在启动KDE的时候出了问题,KDE的错误信息无法给我任何有帮助的线索。

      代码:

      _KDE_IceTransSocketCreateListener: failed to bind listener
      _KDE_IceTransSocketUNIXCreateListener: ...SocketCreateListener() failed
      _KDE_IceTransMakeAllCOTSServerListeners: failed to create listener for local

      Cannot establish any listening sockets DCOPServer self-test failed.


      对我来说这个错误信息没有太多意义,只是一个对KDE来说至关重要的负责进程间通信的程序无法启动。我还可以知道这个错误和ICE协议(Inter Client Exchange)有关,除此之外,我不知道什么是KDE启动出错的原因。

      我决定采用strace看一下在启动dcopserver时到底程序做了什么:

      代码:

      strace -f -F -o ~/dcop-strace.txt dcopserver


      这里 -f -F选项告诉strace同时跟踪fork和vfork出来的进程,-o选项把所有strace输出写到~/dcop-strace.txt里面,dcopserver是要启动和调试的程序。

      再次出现错误之后,我检查了错误输出文件dcop-strace.txt,文件里有很多系统调用的记录。在程序运行出错前的有关记录如下:

      代码:

      27207 mkdir("/tmp/.ICE-unix", 0777) = -1 EEXIST (File exists)
      27207 lstat64("/tmp/.ICE-unix", {st_mode=S_IFDIR|S_ISVTX|0755, st_size=4096, ...}) = 0
      27207 unlink("/tmp/.ICE-unix/dcop27207-1066844596") = -1 ENOENT (No such file or directory)
      27207 bind(3, {sin_family=AF_UNIX, path="/tmp/.ICE-unix/dcop27207-1066844596"}, 38) = -1 EACCES (Permission denied)
      27207 write(2, "_KDE_IceTrans", 13) = 13
      27207 write(2, "SocketCreateListener: failed to "..., 46) = 46
      27207 close(3) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13
      27207 write(2, "SocketUNIXCreateListener: ...Soc"..., 59) = 59
      27207 umask(0) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13
      27207 write(2, "MakeAllCOTSServerListeners: fail"..., 64) = 64
      27207 write(2, "Cannot establish any listening s"..., 39) = 39


      其 中第一行显示程序试图创建/tmp/.ICE-unix目录,权限为0777,这个操作因为目录已经存在而失败了。第二个系统调用(lstat64)检查 了目录状态,并显示这个目录的权限是0755,这里出现了第一个程序运行错误的线索:程序试图创建属性为0777的目录,但是已经存在了一个属性为 0755的目录。第三个系统调用(unlink)试图删除一个文件,但是这个文件并不存在。这并不奇怪,因为这个操作只是试图删掉可能存在的老文件。

      但 是,第四行确认了错误所在。他试图绑定到/tmp/.ICE-unix/dcop27207-1066844596,但是出现了拒绝访问错误。. ICE_unix目录的用户和组都是root,并且只有所有者具有写权限。一个非root用户无法在这个目录下面建立文件,如果把目录属性改成0777, 则前面的操作有可能可以执行,而这正是第一步错误出现时进行过的操作。

      所以我运行了chmod 0777 /tmp/.ICE-unix之后KDE就可以正常启动了,问题解决了,用strace进行跟踪调试只需要花很短的几分钟时间跟踪程序运行,然后检查并分析输出文件。

      说 明:运行chmod 0777只是一个测试,一般不要把一个目录设置成所有用户可读写,同时不设置粘滞位(sticky bit)。给目录设置粘滞位可以阻止一个用户随意删除可写目录下面其他人的文件。一般你会发现/tmp目录因为这个原因设置了粘滞位。KDE可以正常启动 之后,运行chmod +t /tmp/.ICE-unix给.ICE_unix设置粘滞位。

      [BOLD]解决库依赖问题[/BOLD]

      starce 的另一个用处是解决和动态库相关的问题。当对一个可执行文件运行ldd时,它会告诉你程序使用的动态库和找到动态库的位置。但是如果你正在使用一个比较老 的glibc版本(2.2或更早),你可能会有一个有bug的ldd程序,它可能会报告在一个目录下发现一个动态库,但是真正运行程序时动态连接程序 (/lib/ld-linux.so.2)却可能到另外一个目录去找动态连接库。这通常因为/etc/ld.so.conf和 /etc/ld.so.cache文件不一致,或者/etc/ld.so.cache被破坏。在glibc 2.3.2版本上这个错误不会出现,可能ld-linux的这个bug已经被解决了。

      尽管这样,ldd并不能把所有程序依赖的动态库列出 来,系统调用dlopen可以在需要的时候自动调入需要的动态库,而这些库可能不会被ldd列出来。作为glibc的一部分的NSS(Name Server Switch)库就是一个典型的例子,NSS的一个作用就是告诉应用程序到哪里去寻找系统帐号数据库。应用程序不会直接连接到NSS库,glibc则会通 过dlopen自动调入NSS库。如果这样的库偶然丢失,你不会被告知存在库依赖问题,但这样的程序就无法通过用户名解析得到用户ID了。让我们看一个例 子:

      whoami程序会给出你自己的用户名,这个程序在一些需要知道运行程序的真正用户的脚本程序里面非常有用,whoami的一个示例输出如下:
      代码:

      # whoami
      root


      假设因为某种原因在升级glibc的过程中负责用户名和用户ID转换的库NSS丢失,我们可以通过把nss库改名来模拟这个环境:
      代码:

      # mv /lib/libnss_files.so.2 /lib/libnss_files.so.2.backup
      # whoami
      whoami: cannot find username for UID 0


      这里你可以看到,运行whoami时出现了错误,ldd程序的输出不会提供有用的帮助:
      代码:

      # ldd /usr/bin/whoami
      libc.so.6 => /lib/libc.so.6 (0x4001f000)
      /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)


      你只会看到whoami依赖Libc.so.6和ld-linux.so.2,它没有给出运行whoami所必须的其他库。这里时用strace跟踪whoami时的输出:
      代码:

      strace -o whoami-strace.txt whoami

      open("/lib/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
      open("/lib/i686/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
      stat64("/lib/i686/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
      open("/lib/i686/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
      stat64("/lib/i686", 0xbffff190) = -1 ENOENT (No such file or directory)
      open("/lib/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
      stat64("/lib/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
      open("/lib/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
      stat64("/lib", {st_mode=S_IFDIR|0755, st_size=2352, ...}) = 0
      open("/usr/lib/i686/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
      stat64("/usr/lib/i686/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
      open("/usr/lib/i686/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)


      你可以发现在不同目录下面查找libnss.so.2的尝试,但是都失败了。如果没有strace这样的工具,很难发现这个错误是由于缺少动态库造成的。现在只需要找到libnss.so.2并把它放回到正确的位置就可以了。

      [BOLD]限制strace只跟踪特定的系统调用[/BOLD]

      如果你已经知道你要找什么,你可以让strace只跟踪一些类型的系统调用。例如,你需要看看在configure脚本里面执行的程序,你需要监视的系统调用就是execve。让strace只记录execve的调用用这个命令:

      代码:

      strace -f -o configure-strace.txt -e execve ./configure


      部分输出结果为:
      代码:

      2720 execve("/usr/bin/expr", ["expr", "a", ":", "(a)"], [/* 31 vars */]) = 0
      2725 execve("/bin/basename", ["basename", "./configure"], [/* 31 vars */]) = 0
      2726 execve("/bin/chmod", ["chmod", "+x", "conftest.sh"], [/* 31 vars */]) = 0
      2729 execve("/bin/rm", ["rm", "-f", "conftest.sh"], [/* 31 vars */]) = 0
      2731 execve("/usr/bin/expr", ["expr", "99", "+", "1"], [/* 31 vars */]) = 0
      2736 execve("/bin/ln", ["ln", "-s", "conf2693.file", "conf2693"], [/* 31 vars */]) = 0


      你 已经看到了,strace不仅可以被程序员使用,普通系统管理员和用户也可以使用strace来调试系统错误。必须承认,strace的输出不总是容易理 解,但是很多输出对大多数人来说是不重要的。你会慢慢学会从大量输出中找到你可能需要的信息,像权限错误,文件未找到之类的,那时strace就会成为一 个有力的工具了。

    转自: http://www.yuanma.org/data/2007/0201/article_2213.htm





    ====================================================

    linux的strace命令(详解)
    本文详细讲述linux下的strace命令的用法。

    strace 命令是一种强大的工具,它能够显示所有由用户空间程序发出的系统调用。
      strace 显示这些调用的参数并返回符号形式的值。strace 从内核接收信息,而且不需要以任何特殊的方式来构建内核。
      下面记录几个常用 option .
      1 -f -F选项告诉strace同时跟踪fork和vfork出来的进程
      2 -o xxx.txt 输出到某个文件。
      3 -e execve 只记录 execve 这类系统调用
      —————————————————
      进程无法启动,软件运行速度突然变慢,程序的”SegmentFault”等等都是让每个Unix系统用户头痛的问题,
      本文通过三个实际案例演示如何使用truss、strace和ltrace这三个常用的调试工具来快速诊断软件的”疑难杂症”。
      
      
      truss和strace用来跟踪一个进程的系统调用或信号产生的情况,而 ltrace用来跟踪进程调用库函数的情况。truss是早期为System V R4开发的调试程序,包括Aix、FreeBSD在内的大部分Unix系统都自带了这个工具;
      而strace最初是为SunOS系统编写的,ltrace最早出现在GNU/DebianLinux中。
      这两个工具现在也已被移植到了大部分Unix系统中,大多数Linux发行版都自带了strace和ltrace,而FreeBSD也可通过Ports安装它们。
      
      你不仅可以从命令行调试一个新开始的程序,也可以把truss、strace或ltrace绑定到一个已有的PID上来调试一个正在运行的程序。三个调试工具的基本使用方法大体相同,下面仅介绍三者共有,而且是最常用的三个命令行参数:
      
      -f :除了跟踪当前进程外,还跟踪其子进程。
      -o file :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。
      -p pid :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。
      
       使用上述三个参数基本上就可以完成大多数调试任务了,下面举几个命令行例子:
      truss -o ls.truss ls -al: 跟踪ls -al的运行,将输出信息写到文件/tmp/ls.truss中。
      strace -f -o vim.strace vim: 跟踪vim及其子进程的运行,将输出信息写到文件vim.strace。
      ltrace -p 234: 跟踪一个pid为234的已经在运行的进程。
      
       三个调试工具的输出结果格式也很相似,以strace为例:
      
      brk(0) = 0×8062aa8
      brk(0×8063000) = 0×8063000
      mmap2(NULL, 4096, PROT_READ, MAP_PRIVATE, 3, 0×92f) = 0×40016000
      
      每一行都是一条系统调用,等号左边是系统调用的函数名及其参数,右边是该调用的返回值。 truss、strace和ltrace的工作原理大同小异,都是使用ptrace系统调用跟踪调试运行中的进程,详细原理不在本文讨论范围内,有兴趣可以参考它们的源代码。
      举两个实例演示如何利用这三个调试工具诊断软件的”疑难杂症”:
      
      案例一:运行clint出现Segment Fault错误
      
      操作系统:FreeBSD-5.2.1-release
      clint是一个C++静态源代码分析工具,通过Ports安装好之后,运行:
      
      # clint foo.cpp
      Segmentation fault (core dumped)
       在Unix系统中遇见”Segmentation Fault”就像在MS Windows中弹出”非法操作”对话框一样令人讨厌。OK,我们用truss给clint”把把脉”:
      
      # truss -f -o clint.truss clint
      Segmentation fault (core dumped)
      # tail clint.truss
       739: read(0×6,0×806f000,0×1000) = 4096 (0×1000)
       739: fstat(6,0xbfbfe4d0) = 0 (0×0)
       739: fcntl(0×6,0×3,0×0) = 4 (0×4)
       739: fcntl(0×6,0×4,0×0) = 0 (0×0)
       739: close(6) = 0 (0×0)
       739: stat(”/root/.clint/plugins”,0xbfbfe680) ERR#2 ‘No such file or directory’
      SIGNAL 11
      SIGNAL 11
      Process stopped because of: 16
      process exit, rval = 139
      我们用truss跟踪clint的系统调用执行情况,并把结果输出到文件clint.truss,然后用tail查看最后几行。
      注意看clint执行的最后一条系统调用(倒数第五行):stat(”/root/.clint/plugins”,0xbfbfe680) ERR#2 ‘No such file or directory’,问题就出在这里:clint找不到目录”/root/.clint/plugins”,从而引发了段错误。怎样解决?很简单: mkdir -p /root/.clint/plugins,不过这次运行clint还是会”Segmentation Fault”9。继续用truss跟踪,发现clint还需要这个目录”/root/.clint/plugins/python”,建好这个目录后 clint终于能够正常运行了。
      
      案例二:vim启动速度明显变慢
      
      操作系统:FreeBSD-5.2.1-release
      vim版本为6.2.154,从命令行运行vim后,要等待近半分钟才能进入编辑界面,而且没有任何错误输出。仔细检查了.vimrc和所有的vim脚本都没有错误配置,在网上也找不到类似问题的解决办法,难不成要hacking source code?没有必要,用truss就能找到问题所在:
      
      # truss -f -D -o vim.truss vim
      
      这里-D参数的作用是:在每行输出前加上相对时间戳,即每执行一条系统调用所耗费的时间。我们只要关注哪些系统调用耗费的时间比较长就可以了,用less仔细查看输出文件vim.truss,很快就找到了疑点:
      
      735: 0.000021511 socket(0×2,0×1,0×0) = 4 (0×4)
      735: 0.000014248 setsockopt(0×4,0×6,0×1,0xbfbfe3c8,0×4) = 0 (0×0)
      735: 0.000013688 setsockopt(0×4,0xffff,0×8,0xbfbfe2ec,0×4) = 0 (0×0)
      735: 0.000203657 connect(0×4,{ AF_INET 10.57.18.27:6000 },16) ERR#61 ‘Connection refused’
      735: 0.000017042 close(4) = 0 (0×0)
      735: 1.009366553 nanosleep(0xbfbfe468,0xbfbfe460) = 0 (0×0)
      735: 0.000019556 socket(0×2,0×1,0×0) = 4 (0×4)
      735: 0.000013409 setsockopt(0×4,0×6,0×1,0xbfbfe3c8,0×4) = 0 (0×0)
      735: 0.000013130 setsockopt(0×4,0xffff,0×8,0xbfbfe2ec,0×4) = 0 (0×0)
      735: 0.000272102 connect(0×4,{ AF_INET 10.57.18.27:6000 },16) ERR#61 ‘Connection refused’
      735: 0.000015924 close(4) = 0 (0×0)
      735: 1.009338338 nanosleep(0xbfbfe468,0xbfbfe460) = 0 (0×0)
      
      vim试图连接10.57.18.27这台主机的6000端口(第四行的connect()),连接失败后,睡眠一秒钟继续重试(第6行的 nanosleep())。以上片断循环出现了十几次,每次都要耗费一秒多钟的时间,这就是vim明显变慢的原因。可是,你肯定会纳闷:”vim怎么会无缘无故连接其它计算机的6000端口呢?”。问得好,那么请你回想一下6000是什么服务的端口?没错,就是X Server。看来vim是要把输出定向到一个远程X Server,那么Shell中肯定定义了DISPLAY变量,查看.cshrc,果然有这么一行:setenv DISPLAY ${REMOTEHOST}:0,把它注释掉,再重新登录,问题就解决了。
      
      
      案例三:用调试工具掌握软件的工作原理
      
      操作系统:Red Hat Linux 9.0
      用调试工具实时跟踪软件的运行情况不仅是诊断软件”疑难杂症”的有效的手段,也可帮助我们理清软件的”脉络”,即快速掌握软件的运行流程和工作原理,不失为一种学习源代码的辅助方法。下面这个案例展现了如何使用strace通过跟踪别的软件来”触发灵感”,从而解决软件开发中的难题的。
      大家都知道,在进程内打开一个文件,都有唯一一个文件描述符(fd:file descriptor)与这个文件对应。而本人在开发一个软件过程中遇到这样一个问题:
      已知一个fd,如何获取这个fd所对应文件的完整路径?不管是Linux、FreeBSD或是其它Unix系统都没有提供这样的API,怎么办呢?我们换个角度思考:Unix下有没有什么软件可以获取进程打开了哪些文件?如果你经验足够丰富,很容易想到lsof,使用它既可以知道进程打开了哪些文件,也可以了解一个文件被哪个进程打开。好,我们用一个小程序来试验一下lsof,看它是如何获取进程打开了哪些文件。lsof: 显示进程打开的文件。
      
      /* testlsof.c */
      #include #include #include #include #include
      int main(void)
      {
       open(”/tmp/foo”, O_CREAT|O_RDONLY); /* 打开文件/tmp/foo */
       sleep(1200); /* 睡眠1200秒,以便进行后续操作 */
       return 0;
      }
      
      将testlsof放入后台运行,其pid为3125。命令lsof -p 3125查看进程3125打开了哪些文件,我们用strace跟踪lsof的运行,输出结果保存在lsof.strace中:
      
      # gcc testlsof.c -o testlsof
      # ./testlsof &
      [1] 3125
      # strace -o lsof.strace lsof -p 3125
      
      我们以”/tmp/foo”为关键字搜索输出文件lsof.strace,结果只有一条:
      
      
      # grep ‘/tmp/foo’ lsof.strace
      readlink(”/proc/3125/fd/3″, “/tmp/foo”, 4096) = 8
      
      原来lsof巧妙的利用了/proc/nnnn/fd/目录(nnnn为pid):Linux内核会为每一个进程在/proc/建立一个以其pid为名的目录用来保存进程的相关信息,而其子目录fd保存的是该进程打开的所有文件的fd。目标离我们很近了。好,我们到/proc/3125/fd/看个究竟:
      
      # cd /proc/3125/fd/
      # ls -l
      total 0
      lrwx—— 1 root root 64 Nov 5 09:50 0 -> /dev/pts/0
      lrwx—— 1 root root 64 Nov 5 09:50 1 -> /dev/pts/0
      lrwx—— 1 root root 64 Nov 5 09:50 2 -> /dev/pts/0
      lr-x—— 1 root root 64 Nov 5 09:50 3 -> /tmp/foo
      # readlink /proc/3125/fd/3
      /tmp/foo
      
      答案已经很明显了:/proc/nnnn/fd/目录下的每一个fd文件都是符号链接,而此链接就指向被该进程打开的一个文件。我们只要用readlink()系统调用就可以获取某个fd对应的文件了,代码如下:
      
      
      #include #include #include #include #include #include
      int get_pathname_from_fd(int fd, char pathname[], int n)
      {
       char buf[1024];
       pid_t pid;
       bzero(buf, 1024);
       pid = getpid();
       snprintf(buf, 1024, “/proc/%i/fd/%i”, pid, fd);
       return readlink(buf, pathname, n);
      }
      int main(void)
      {
       int fd;
       char pathname[4096];
       bzero(pathname, 4096);
       fd = open(”/tmp/foo”, O_CREAT|O_RDONLY);
       get_pathname_from_fd(fd, pathname, 4096);
       printf(”fd=%d; pathname=%sn”, fd, pathname);
       return 0;
      }
      
      出于安全方面的考虑,在FreeBSD 5 之后系统默认已经不再自动装载proc文件系统,因此,要想使用truss或strace跟踪程序,你必须手工装载proc文件系统:mount -t procfs proc /proc;或者在/etc/fstab中加上一行:
      
      proc /proc procfs rw 0 0

  • 使用 Strace 和 GDB 调试工具的乐趣

    2011-11-22 16:06:36



    UNIX 家族总是为用户提供了丰富的工具。UNIX 是一个工具财宝箱,有了这些工具,您不仅可以完成具有创造性的工作,还可以在深入研究该操作系统的同时得到教育和娱乐。strace(用来跟踪任何程序的 系统调用)和 GDB 调试工具(用来在受控的环境中运行程序的功能齐全的调试工具)是实现这个目标的两个有价值的工具。

    UNIX 的设计由大量的函数调用(称为系统调用)组成,其中包括一些简单的任务,如在屏幕上显示字符串来设置任务优先级。所 有的 UNIX 程序都是通过调用操作系统提供的这些底层服务来完成它们的任务,使用 strace 工具,您可以清楚地看到这些调用过程及其使用的参数。通过这种方式,您可以操作这些程序,以了解它们与操作系统之间的底层交互。

    开始游戏

    让我们以一个简单的 UNIX 命令 pwd 作为开始,然后更深入地研究该命令在完成其任务的过程中进行了哪些工作。启动 xterm 以创建一个进行实验的受控环境,然后输入下面的命令:

    $ pwd
    

    这个 pwd 命令显示了当前的工作目录。在我的计算机上,当时的输出是:

    /home/bill/
    

    一个如此简单的函数掩饰了该命令底层的复杂性(顺便说一下,所有的计算机程序都是这样的)。要真正地了解其复杂性,请使用 strace 工具再次运行 pwd 命令:

    $ strace pwd
    

    通过该命令,您可以看到,在显示和列举当前工作目录的过程中,UNIX 计算机执行了相当多的操作(请参见清单 1)。


    清单 1:strace pwd 命令的输出
    execve("/bin/pwd", ["pwd"], [/* 39 vars */]) = 0
    uname({sys="Linux", node="sammy", ...}) = 0
    brk(0)                                  = 0x804c000
    old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4001...
    	.
    	.
    	.
    	fstat64(3, {st_mode=S_IFREG|0644, st_size=115031, ...}) = 0
    old_mmap(NULL, 115031, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000
    close(3)                                = 0
    open("/lib/tls/libc.so.6", O_RDONLY)    = 3
    read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360U\1"..., 1024) = 1024
    fstat64(3, {st_mode=S_IFREG|0755, st_size=1547996, ...}) = 0
    old_mmap(0x42000000, 1257224, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x42000000
    mprotect(0x4212e000, 20232, PROT_NONE)  = 0
    old_mmap(0x4212e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x12e000)...
    old_mmap(0x42131000, 7944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,...
    close(3)                                = 0
    set_thread_area({entry_number:-1 -> 6, base_addr:0x40016ac0, limit:1048575, seg_32bit...
    munmap(0x40017000, 115031)              = 0
    brk(0)                                  = 0x804c000
    brk(0x804d000)                          = 0x804d000
    brk(0)                                  = 0x804d000
    open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
    fstat64(3, {st_mode=S_IFREG|0644, st_size=30301680, ...}) = 0
    mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000
    close(3)                                = 0
    brk(0)                                  = 0x804d000
    brk(0x804e000)                          = 0x804e000
    getcwd("/home/bill", 4096)              = 11
    fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 6), ...}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4021700...
    write(1, "/home/bill\n", 11/home/bill
    )            = 11
    munmap(0x40217000, 4096)                = 0
    exit_group(0)                           = ?
    

    UNIX 系统调用的具体细节

    关于检索和显示当前工作目录所需的所有系统调用的详细细节,已经超出了本文的讨论范围,但我会介绍如何获取这些信息。清单 1 中的每一行都以类似 C 的格式,清楚地说明了一项系统调用及其参数,这也是 C 程序员希望看到的。Strace 同样以这种方式显示这些调用,不管在实际创建该程序时使用的是何种编程语言。

    如果要了解清单 1 中的所有细节信息,对于所有这些系统调用,UNIX 为您提供了大量的文档。清单 1 中“最重要”的函数是 getcwd() 函数,它表示获取当前工作目录。当前的 xterm 显示了 strace pwd 的输出,同时再启动另一个 xterm 并输入下面的命令以查看 UNIX 对该函数的显示:

    $ man getcwd
    

    您所看到的应该是 getcwd() 函数完整的清单以及这个重要的 C 函数需要的和返回的参数清单。同样地,您可以输入 man brkman fstat64 等等。通常,UNIX 系统通过文档对这些系统函数进行了详细的说明,如果花些时间仔细地研究它们,您将逐渐地了解到 UNIX 的功能是多么的强大,以及学习这些底层系统细节是多么的容易。在所有的操作系统中,UNIX 最善于帮助您理解其底层的处理过程。

    观察 nweb

    对于下面几个步骤,您需要使用更庞大且更复杂的程序,而不是像 pwd 这样简单的 UNIX 命令。简单的超文本传输协议 (HTTP) 服务器,如 nweb,是非常适合的。当您在 Internet 上冲浪 的时候,HTTP 服务器侦听浏览器请求,然后通过发送所请求的对象,如 Web 页面和图形文件,以此响应浏览器的请求。

    下载并安装 nweb,该软件由 IBM developerWorks 投稿作家 Nigel Griffiths 编写。 '"(请参阅参考资料部分提供的 Nigel 的文章“nweb: ?"a tiny, safe Web server (static pages only)”(developerWorks,2004 年 6 月)的链接。)

    下载 es-nweb.zip 到 $HOME/downloads 目录,然后输入清单 2 中所示的简单命令,以提取、编译并启动该程序:

    注意:我假设您需要为 Linux® 工作站编译这个程序。如果实际情况并非如此,那么有关在其他的 UNIX 操作系统上对该程序进行编译的详细信息,请阅读这篇 nweb 文章。


    清单 2. 用于提取、编译和启动 nweb 的命令
    $ cd src
    $ mkdir nweb
    $ cd nweb
    $ unzip $HOME/downloads/es-nweb.zip
    $ gcc -ggdb -O -DLINUX nweb.c -o nweb
    $ ./nweb 9090 $HOME/src/nweb &
    

    注意:清单 2 中的 -ggdb 选项和 Nigel 的文章中的内容有些不同,该选项用于告诉 GCC 编译器对该程序进行优化,以便使用 GDB 调试工具对其进行调试,您将在以后用到该调试工具。

    接下来,要确认 nweb 服务器已经运行,可以使用清单 3 中所示的 ps 命令来对它进行检查。


    清单 3. ps 命令
    $ ps
      PID TTY          TIME CMD
     2913 pts/5    00:00:00 bash
     4009 pts/5    00:00:00 nweb
     4011 pts/5    00:00:00 ps
    

    最后,要确认 nweb 确实正在运行并且状态正常,可以在您的计算机上启动一个 Web 浏览器并在地址栏中输入 http://localhost:9090

    针对 nweb 使用 strace

    现在,让我们来进行一些有趣的工作。启动另一个 xterm,然后使用 strace 来跟踪正在运行的 nweb 服务器。要完成该任务,您必须清楚该程序的进程 ID,并且必须具有适当的权限。您仅仅可以看到一组特定的系统调用,即那些与网络相关的系统调用。输入清单 4 第一行所示的命令作为开始,其中使用了前面显示的 nweb 的进程 ID。您应该看到如下的输出(清单 4 中的第二行)。


    清单 4. 开始对 nweb 进行跟踪
    $ strace -e trace=network -p 4009
    accept(0,
    

    请注意,在调用网络 accept() 函数的过程中停止了跟踪操作。在浏览器中刷新几次 http://localhost:9090 页面,请注意每次刷新该页面时 strace 的显示。这是不是很棒呢?您所看到的是,当 Web 浏览器调用 HTTP 服务器 (nweb) 时,服务器所进行的底层网络调用。简单地说,nweb 正在接受 来自您的浏览器的调用。

    您可以在运行 strace 的具有窗口焦点的 xterm 中按下 Ctrl+C 以停止对网络调用的跟踪。

    再来研究 GDB 调试工具

    正如您所看到的,strace 可以作为了解用户程序如何通过某些系统调用与操作系统进行交互的一个很好的程序。GDB 调试工具本身也可以附加于一个正在运行的进程,并帮助您进行更深入的研究。

    GDB 调试工具非常有用,Internet 上提供了大量的有关该工具的可用信息。通常,调试工具是很有价值的工具,并且任何负责开发和维护计算机系统的人员应该了解如何使用它们。因此,在 nweb 运行于另一个 xterm 会话的同时,按下 Ctrl+C 停止 strace,然后输入清单 5 中所示的命令启动 GDB 调试工具。


    清单 5. 启动 GDB 调试工具
    $ gdb --quiet
    (gdb) attach 4009
    Attaching to process 4009
    Reading symbols from /home/bill/src/nweb/nweb...done.
    Reading symbols from /lib/tls/libc.so.6...done.
    Loaded symbols for /lib/tls/libc.so.6
    Reading symbols from /lib/ld-linux.so.2...done.
    Loaded symbols for /lib/ld-linux.so.2
    0xffffe410 in ?? ()
    (gdb)
    

    -quiet 选项告诉 GDB 调试工具仅显示其提示符,而不要显示所有其他的启动信息。如果需要显示额外的文本信息,可以去掉 -quiet 选项。

    attach 4009 命令启动对当前正在运行的 nweb 服务器的调试工作,并且 GDB 调试工具通过读取有关该进程的所有的符号信息来做出同样方式的响应。下一步,使用 info 命令来列举您所研究的程序的相关信息(请参见清单 6)。


    清单 6. info 命令列出程序信息
    (gdb) info proc
    process 4009
    cmdline = './nweb'
    cwd = '/home/bill/src/nweb'
    exe = '/home/bill/src/nweb/nweb'
    (gdb)
    

    info 命令(请参见清单 7)的另一个有用的变种是 info functions,然而,函数的列表可能很长。


    清单 7. info functions 命令得到的函数列表
    (gdb) info functions
    All defined functions:
    
    File nweb.c:
    void log(int, char *, char *, int);
    int main(int, char **);
    void web(int, int);
    
    File __finite:
    int __finite();
    	.
    	.
    	.
    (gdb)	
    

    因为使用 -ggdb 选项对 nweb 程序进行了编译,所以可执行文件中包含了大量的调试信息,允许该调试工具查看文件中列举的已定义的函数,如清单 7 所示。

    list 和 disassemble 命令

    有两个重要的 GDB 调试工具命令,它们分别是 listdisassemble。通过使用清单 8 中所示的代码尝试使用这些命令。


    清单 8. list 命令
    (gdb) list main
    121             exit(1);
    122     }
    123
    124
    125     main(int argc, char **argv)
    126     {
    127             int i, port, pid, listenfd, socketfd, hit;
    128             size_t length;
    129             char *str;
    130             static struct sockaddr_in cli_addr; /* static = initialised to zeros */
    (gdb) 
    131             static struct sockaddr_in serv_addr; /* static = initialised to zeros */
    132
    133             if( argc < 3  || argc > 3 || !strcmp(argv[1], "-?") ) {
    134                     (void)printf("hint: nweb Port-Number Top-Directory\n\n"
    135             "\tnweb is a small and very safe mini web server\n"
    136             "\tnweb only servers out file/web pages with extensions named below\n"
    137             "\t and only from the named directory or its sub-directories.\n"
    138             "\tThere is no fancy features = safe and secure.\n\n"
    139             "\tExample: nweb 8181 /home/nwebdir &\n\n"
    140             "\tOnly Supports:");
    

    正如您所看到的,list 命令以源文件的形式列出了正在运行的程序,并标注了相应的行号。按下 Return 键(如第 130 行和第 131 行之间所示)以接着上次的列表继续进行列举。现在,尝试使用 disassemble 命令,可以缩写为 disass(请参见清单 9)。


    清单 9. disassemble 命令
    (gdb) disass main
    Dump of assembler code for function main:
    0x08048ba2 <main+0>:    push   ebp
    0x08048ba3 <main+1>:    mov    ebp,esp
    0x08048ba5 <main+3>:    push   edi
    0x08048ba6 <main+4>:    push   esi
    0x08048ba7 <main+5>:    push   ebx
    0x08048ba8 <main+6>:    sub    esp,0xc
    0x08048bab <main+9>:    mov    ebx,DWORD PTR [ebp+12]
    0x08048bae <main+12>:   and    esp,0xfffffff0
    	.
    	.
    	.
    0x08048c01 <main+95>:   call   0x8048664 <printf>
    0x08048c06 <main+100>:  add    esp,0x10
    0x08048c09 <main+103>:  inc    esi
    0x08048c0a <main+104>:  cmp    DWORD PTR [ebx+esi],0x0
    ---Type <return> to continue, or q <return> to quit---
    

    反汇编清单显示了该 main 函数的汇编语言清单。在本示例中,汇编代码指示出运行该代码的计算机使用的是 Intel® Pentium® 处理器。如果该程序运行于不同类型的处理器上,如基于 IBM Power PC® 的计算机,那么您的代码看上去将有很大的区别。

    在其运行的过程中进行监视

    因为您所监视的是一个正在运行的程序,所以可以设置相应的断点,然后在它响应浏览器请求并向提出请求的浏览器传输 .html 和 .jpg 文件的同时,对该程序进行监视清单 10 介绍了如何完成该任务。


    清单 10. 设置断点
    (gdb) break 188
    Breakpoint 1 at 0x8048e70: file nweb.c, line 188.
    (gdb) commands 1
    Type commands for when breakpoint 1 is hit, one per line.
    End with a line saying just "end".
    >continue
    >end
    (gdb) c
    Continuing.
    

    此时,GDB 调试工具已设置为在 nweb 服务器接受 浏览器请求处进行中断,该调试工具将仅仅显示相应的请求并继续处理其他的请求,而不会中断正在运行的程序。刷新几次浏览器中的 http://localhost:9090/ 页面,可以观察到,GDB 调试工具显示了断点并继续运行。

    在刷新浏览器页面的同时,您应该看到如清单 11 所示的断点信息,在 GDB 调试工具 xterm 中滚动输出。与 strace 相同,您可以按下 Ctrl+C 来停止对 nweb 服务器的调试。在停止了跟踪操作之后,您可以输入 quit 命令以退出 GDB 调试工具。


    清单 11. GDB 调试工具 xterm 中的断点信息
    Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
    188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
    Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
    188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
    Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
    188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
    Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188
    188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0)
    Program received signal SIGINT, Interrupt.
    0xffffe410 in ?? ()
    (gdb) quit
    The program is running.  Quit anyway (and detach it)? (y or n) y
    Detaching from program: /home/bill/src/nweb/nweb, process 4009
    $
    

    请注意,您正告诉 GDB 调试工具停止对一个仍在内存中活动的程序的调试。即使是在退出了调试工具之后,您还可以刷新浏览器页面,并将看到 nweb 仍在运行。可以输入 kill 4009 命令来停止该程序,或者在您退出会话时,该页面将会消失。

    和平常一样,您可以通过其 man 和 info 页面来了解各种各样的工具,如 strace 和 GDB 调试工具。请确保使用 UNIX 为您提供的这些工具!

    了解尽可能多的信息

    了解关于您所使用的计算机的尽可能多的信息,绝不是件坏事,并且还可以从这个过程中获得乐趣。实际上,UNIX 通过提供各种工具,如 strace 和 GDB 调试工具以及包含在相应的 man 和 info 页面中的大量的信息,鼓励您对系统进行研究和学习。计算机是人类智慧的延伸,并且我们对其了解得越多,它们将变得越有用。


    转自:http://www.ibm.com/developerworks/cn/aix/library/au-unix-strace.html

  • 修改linux文件描述符限制

    2011-11-10 18:57:05


    修改linux文件描述符限制

       Linux管理用户可以在etc/security/limits.conf配置文件中设置他们的文件描述符极限,如下例所示。  
     softnofile 1024   
      hardnofile 4096   
    系统级文件描述符极限还可以通过将以下三行添加到/etc/rc.d/rc.local启动脚本中来设置:  
     #Increasesystem-widefiledescriptorlimit.  
     echo4096>/proc/sys/fs/file-max  
     echo16384>/proc/sys/fs/inode-max

    参考文档:
    http://baike.baidu.com/view/1303430.htm
    http://www.blogjava.net/alexwan/archive/2009/05/18/271269.html




    文件描述符是一个简单的整数,用以标明每一个被进程所打开的文件和socket。第一个打开的文件是0,第二个是1,依此类推。Unix 操作系统通常给每个进程能打开的文件数量强加一个限制。更甚的是,unix 通常有一个系统级的限制。
     
    查看命令:
            ulimit -n
            在修改之前一般得到的结果是1024;
           
     临时修改:
            ulimit -HSn 65536
            这样就增大了文件描述符的限制。

     持久性修改有两种方法:
    (1)将ulimit -HSn 65536写入对应用户的.bash_profile文件中,如/root/.bash_profile;
    (2)将ulimit -HSn 65536写入到/etc/profile文件中,那么这个设置就对所有用户有效;

    这样在下次进入系统是就不用再设置了。
    上面这个方法对解决too many open file的错误很有效。

    PS:如果你的进程是通过脚本启动的,当然也可以将
    ulimit -HSn 65536
    写到脚本文件中。
           


    Let life be beautiful like summer flowers and death like autumn leaves.



521/3123>
Open Toolbar