zoukankan      html  css  js  c++  java
  • linux性能优化

    linux性能调优

    cpu密集型
    例如web服务器像nginx node.js需要CPU进行批处理和数学计算都属于此类型
    io密集型
    例如数据库常见的mysql,大量消耗内存和存储系统,对CPU和网络要求不高,这种应用使用CPU来发起IO请求,然后进入sleep状态。

    cpu
    memory
    i/o
    network

    第一节:cpu 性能瓶颈
    计算机中,cpu是最重要的一个子系统,负责所有计算任务;基于摩尔定律的发展,cpu是发展最快的一个硬件,所以瓶颈很少出现在cpu上;我们线上环境的cpu都是多核的,并且基于SMP(symmetric multiprocessing)结构的。通过观察线上机器cpu使用率会发现,使用率很低很低,不到5%; 说明我们的资源浪费情况多么严重啊;(但为什么不能一台机器多部署几个应用呢,后边我会解释); 我们线上的cpu一个核支持超级线程,也就是一个核上可以并行运行几个线程)
    1. 通过调整进程优先级调整: nice 命令来调整进程优先级别;可调范围(-20到 19) 如: renice 5 pid
    2.通过调整cpu的亲和度来集中处理某一个中断类型:将系统发出的中断都绑定在一个cpu上,这样其他cpu继续执行自己正在执行的线程,不被中断打扰,从而较少了线程上下文切换时间,增强性能;
    注: cpu亲和度的概念: 在多核cpu中,linux操作系统抢占式调度系统,按照cpu时间片/中断/等 不断调度进程给cpu去执行的;如果在一个时间片调度线程1在cpu1上运行,另外一个时间片调度线程1在cpu2上去运行,这样会造成线程执行速度慢,性能降低。为什么呢? 我们知道SMP上多核都是共享L1 ,L2 CPU Cache的。并且各个核的内存空间都是不可共享的,一个线程如果多次时间片上在不同的cpu上运行,会造成cache的不断失效和写入;性能会降低; 而linux的进程调度有个亲和度算法可以将尽量将进程每次都调度到同一个cpu上处理;linux调度时当然也有Loadbalance算法保证进程调度的均匀负载的;
    例如: echo 03 > /proc/irq/19/smp-affinity (将中断类型为19的中断绑定到第三个cpu上处理)


    第二节:内存性能瓶颈
    首先,linux的内存管理是聪明和智能的;linux通过(virtual memory manage)来管理内存的; 对于大多数应用,linux是不直接写到硬盘上去的,而是先写到 virtual memory manage 管理的文件系统缓存(也在内存中的)里 .方便应用的后续的读请求;因为和磁盘的I/O操作是昂贵的;linux会根据一些算法策略适当的时候同步到硬盘的;这就是为什么我们运行linux一段时间后,发现可用内存那么少的原因,多数被cache+buffer占用咧;
    所以我们提高性能的办法就是减少写到磁盘的次数,提高每次写磁盘时的效率质量;
    1. 通过调节缓存的脏数据同步到硬盘的策略:(脏数据表示没有被当前的线程使用的数据)
    例如: echo 10 > /proc/sys/vm/dirty_background_rato (当脏数据占据物理内存10%时,触发pdflush同步到硬盘):小心调节,会大幅度的影响性能;
    echo 2000 > /proc/sys/vm/dirty_expire_centisecs (当脏数据在物理内存的逗留时间超过2000ms时被同步到硬盘);
    2.通过调节swap参数,来优化linux虚拟内存管理:基于程序的局部性原理,linux通过虚拟内存机制来实现并发运行进程,linux发现物理内存不够用时,会根据LRU算法将一部分内存swap out到硬盘;当运行被换出的那个线程时,在swap in 到内存里;
    例如: echo 10 > /proc/sys/vm/swappiness(值为0表示尽量都用物理内存,值为100表示积极的使用swap分区;)这个参数很重要;小心调节; 一般为60;

    第三节: 磁盘I/O可调性能参数
    linux的子系统VFS(virtural file system)虚拟文件系统;从高层将各种文件系统,以及底层磁盘特性隐藏,对程序员提供:read,write,delete等文件操作;这就是之所以我们可以在linux上mount多种不同格式的文件系统的,而window确不行; 当然基于:虚拟文件系统,文件系统,文件系统驱动程序,硬件特性方面,都能找到性能瓶颈;
    1.选择适合应用的文件系统;
    2. 调整进程I/O请求的优先级,分三种级别:1代表 real time ; 2代表best-effort; 3代表idle ;
    如:ionice -c1 -p1113(给进程1113的I/O优先级设置为最高优先级)
    3.根据应用类型,适当调整page size 和block size;
    4.升级驱动程序;

    第四节 :网络可调性能参数
    对于我们web应用来说,网络性能调整如此重要,linux的网络支持是无与伦比的;是作为网络服务器的首先;对于web服务来说:除了应用的响应速度外,linux网络管理子系统,网卡,带宽都可能成为性能瓶颈;
    1.查看网卡设置是否全双工传输的: echtool eth0
    2. 设置MTU(最大传输单元),在带宽G以上的时候,要考虑将MTU增大,提高传输性能;如: ifconfig eth0 mtu 9000 up
    3. 增加网络数据缓存;传输数据时linux是将包先放入缓存,填满缓存后即发送出去;读操作类似;
    sysctl -w net.ipv4.tcp_rmem="4096 87380 8388608" :设置tcp读缓存:最小缓存,初始化时,最大缓存
    sysctl -w net.ipv4.tcp_wmem="4096 87380 8388608" :设置tcp写缓存:最小缓存,初始化时,最大缓存
    4.禁用window_scaling,并且直接设置window_size;(就像我们经常设置jvm的参数:xms = xmx一样
    sysctl -w net.ipv4.tcp_window_scaling=0
    5.设置TCP连接可重用性: 对于TIME_OUT状态的TCP连接可用于下一个TCP重用,这样减少了三次握手和创建时间,非常提高性能,尤其对于web server;
    如: 开启可重用tcp功能: sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.tcp_tw_recyle=1
    6.禁用掉没必要的tcp/ip协议功能:比如icmp;broadcast包的接收;
    7. linux对于keeplive的tcp连接有一个默认的过期时间;可以减小这个时间,让没用的连接释放掉,毕竟tcp连接数是有限的嘛;
    如: sysctl -w net.ipv4.tcp_keepalive_time=1800 (设置过期时间,1800s)
    8.设置最大tcp正在连接状态(还没ESTABLISHED)队列长度;避免由于太多的tcp连接过来,导致服务器挂掉;比如DoS攻击
    如:sysctl -w net.ipv4.tcp_max_syn_backlog=4096
    9. 绑定tcp类型的中断到一个cpu上;(让cpu去亲和这个类型中断,避免频繁的中断,影响线程调度性能)


    我个人在工作中常用到的有:
    htop vmstat iotop sar strace iftop ss lsof ethtool mtr等

    CPU 性能监控以及调优
    我们可以 通过检查cpu使用量,通过工具观测上下文切换、中断以及代码调用等方面来进行优化。

    首先明确几个术语:
    缓存:为了提供内存i/o性能cpu提供硬件级缓存。查看缓存可以用过 lscpu -p命令来查看

    # lscpu
    L1d cache: 32K
    L1i cache: 32K
    L2 cache: 256K
    L3 cache: 8192K
    1级缓存为静态缓存,分为数据缓存和指令缓存。
    2级和3级缓存为动态缓存,其中2级缓存为共享缓存。

    为了提高cpu缓存命中率我们通常的做法是把cpu绑定在某一个核上,也就是”cpu亲和性”
    linux下我们可以通过”taskset”命令来实现

    # taskset -pc 0 73890
    pid 73890's current affinity list: 0
    pid 73890's new affinity list: 0
    但是这样还是有问题。例如不能保证本地内存分配,所以这时候我们需要使用numa来解决问题

    NUMA:非一致性内存访问机制。每个屋里核心都有一段自己使用的内存成为本地节点,都有自己的内存控制器,距离最近的内存节点成称为邻均节点。

    numa.png-21.6kB
    上图为numa的简单的拓扑,来源于互联网。

    numactl可以将程序绑定到特定的numa节点

    # numactl --show #查看当前的numa配置
    policy: default
    preferred node: current
    physcpubind: 0
    cpubind: 0
    nodebind: 0
    membind: 0
    注:数据库服务器不要用numa,如果要使用请在数据库启动请使用numactl —interleave=all。作为运维可能都被坑过。

    cpu调度策略

    实时调度策略
    SCHED_FIFO 静态调度策略,一旦占用cpu则一直运行,一直运行直到有更高优先级任务到达或自己放弃。
    SCHED_RR 时间轮询策略,当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平。
    实时调度策略作用值为1-99,数字越大优先级越高。
    一般策略
    SCHED_OTHER 默认调度策略通过nice和counter值决定权值,nice越小,counter越大,被调度的概率越大,也就是曾经使用了cpu最少的进程将会得到优先调度。作用值为100-139,数字越小优先级越高。
    SCHED_BATCH
    SCHED_IDLE
    chrt 修改实时优先级,生产中一般不要修改,默认是rr调度

    SCHED_OTHER 使用nice、renice修改。
    另外other支持动态调整,如果手动直接nice修改即可。

    context switches:上下文切换

    linux内核将每一个core当作一个独立的处理器。一个内核可以同时运行50~50000个进程。每个线程将会分配一个时间片,直到这个线程的时间片用完,或是被更高优先级的线程抢占,它才会被重新放回cpu队列。切换线程的过程就是context switch。context switch越高,则内核调度的工作负担越大。

    vmstat 既可以看到 cs的高低

    run queue 运行队列

    每个cpu都有一个运行队列。线程,要么在sleep状态(阻塞并等待IO),要么在运行状态。运行队列越长,则等待cpu处理这个线程的时间越长。运行队列是全局的会被所有CPU共享

    load就是用来描述运行队列的。它的值等于当前正在处理的线程+运行队列里面的线程。

    比如当前系统核数是2,有两个线程正在执行行,还有4个线程在运行队列里面,那么它的load=2+4。

    vmstat w uptime 都可以观测运行队列负载情况。

    cpu性能监控
    说了这么多,那正常情况下需要观察哪些值呢?
    首先numa 以及算法都是特殊情况下优化的,一般情况下不会去动这些,需要根据你的业务场景来进行绑定调整,像虚拟化,云计算等可能就需要进行调整。

    那么我们日常需要观测的性能点是:

    cpu利用率
    us 60%-70%
    sy 30%-35%
    id 0%-5%
    cs上下文切换
    cs和cpu利用率相关,如果能保持上面所说的利用率大量的切换可以接受
    运行队列
    小于等于4最好
    例子:

    # vmstat 1 5
    procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
    r b swpd free buff cache si so bi bo in cs us sy id wa st
    3 0 1150840 271628 260684 5530984 0 0 2 1 0 0 22 4 73 0 0
    5 0 1150840 270264 260684 5531032 0 0 0 0 5873 6085 13 13 73 0 0
    5 0 1150840 263940 260684 5531040 0 0 0 4 6721 7507 15 13 72 0 0
    4 0 1150840 263320 260684 5531068 0 0 0 0 6111 7117 10 13 76 0 0
    4 0 1150840 262328 260684 5531072 0 0 0 0 6854 7673 18 13 68 0 0
    例子中cpu中断(in)以及上下文切换(cs)都比较高,说明内核不得不来回切换进程,同时in也是比较高说明cpu一直在请求资源。

    内存memory
    术语
    MMU:
    CPU是不能与硬盘打交道的,只有数据被载入到内存中才可以被CPU调用。cpu在访问内存的时候需要先像内存监控程序请求,由监控程序控制和分配内存的读写请求,这个监控程序叫做MMU(内存管理单元)

    线性地址到物理地址的映射,如果按照1个字节1个字节映射的话,需要一张非常大的表,这种转换关系会非常的复杂。因此把内存空间又划分成了另外一种存储单元格式,通常为4K。

    每个进程如果需要访问内存的时候都需要去查找page table的话需要借助缓冲器TLB,但每次产找tlb没有或者大量查找还是会造成缓慢,所以又有了page table的分级目录。page table可以分为1级目录,2级目录和偏移量。

    另外让系统管理大量内存有两种方法:

    增加硬件内存管理单元中页表数
    增大页面大小
    第一种方法不太现实,所有我们考虑第二种方法。即:大页面。
    32位系统4m大页框64位系统2m大页框,页框越粗浪费越严重。
    查看系统的大页面:

    cat /proc/meminfo
    AnonHugePages: 309248 kB
    HugePages_Total: 0
    HugePages_Free: 0
    HugePages_Rsvd: 0
    HugePages_Surp: 0
    Hugepagesize: 2048 kB
    DirectMap4k: 6144 kB
    DirectMap2M: 1042432 kB
    DirectMap1G: 0 kB
    AnonHugePages:透明大页面,THP是一个提取层,可自动创建、管理和使用超大页面的大多数方面。
    另外HP必须在引导时设置。
    手动设置大页面的页数:
    sysctl vm.nr_hugepages = 20

    DMA:直接读取内存
    在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须经过DMA请求、DMA响应、DMA传输、DMA结束4个步骤。

    虚拟内存:
    32位的系统上每一个进程在访问内存的时候,每一个进程都当做自己有4个G的内存空间可用,这叫虚拟内存(地址),虚拟内存转化成物理内存是通过MMU来完成的。生产中我们尽量不使用虚拟内存。

    影响系统性能的几个内存参数:

    overcommit_memory 过量使用内存
    0 默认设置系统决定是否过量使用。
    1 不过量使用
    2 过量使用但有一定的比例默认百分值五十由overcommit_ratio决定(他就是默认的50),举个例子物理内存8g,swap4g,可以过量使用10g。
    注:生产中尽量避免过量使用,例如redis要关闭过量使用。
    spappines
    -将不活跃的进程换进swap。注:尽量不去使用swap。
    生产中设置:
    echp 10 > /proc/sys/vm/swappines
    回收内存
    这个值设定为 1、2 或者 3 让内核放弃各种页缓存和 slab 缓存的各种组合。
    1 系统无效并释放所有页缓冲内存即buffers
    2 系统释放所有未使用的 slab 缓冲内存。即cached
    3 系统释放所有页缓冲和 slab 缓冲内存。
    生产中使用:
    1.运行sync
    echo 3>/proc/sys/vm/drop_caches
    i/o
    IO子系统一般是linux系统中最慢的部分。一个原因是它距离CPU的距离,另一个原因是它的物理结构。因此尽量要减少磁盘IO。

    磁盘调度策略:

    # cat /sys/block/sda/queue/scheduler
    noop anticipatory deadline [cfq]
    其中当前使用cfq策略。
    cfq:完全公平调度。在其时间片段中,进程每次最多可有八个请求(默
    认)。调度程序会尝试根据历史数据估计某个程序是否会在近期发出更多 I/O,然后 CFQ 会闲置,等待那个
    I/O,即使有其他进程正在等待发出 I/O
    deadline:每一个请求在指定的期限前必须得到服务。
    noop:没有策略
    anticipatory:已被抛弃,写多读少的场景使用。

    linux内核以page为单位访问磁盘IO,一般为4K。
    查看page: /usr/bin/time -v date

    MPF
    linux会将内存物理地址空间映射到虚拟内存,内核仅会映射需要的内存页。当应用启动时,内核依次搜索CPU cache和物理内存,查找是否有相应的内存页,如果不存在,则内核将会发起一次MPF(major page fault),将磁盘中的数据读出并缓存到内存中。

    如果在buffer cache找到了对应的内存页,则将会产生一个MnPF(minor page fault).

    /usr/bin/time -v helloworld
    第一次执行会发现大部分是MPF
    第二次执行会发现大部分是MnPF

    The File Buffer Cache

    file buffer cache用来减少MPF,增加MnPF,它将会持续增长,直到可用内存比较少或是内核需要为其它应用来释放一些内存。free内存比较少,并不能说明系统内存紧张,只能说明linux系统充分使用内存来做cache.

    # cat /proc/meminfo
    MemTotal: 1004772 kB
    MemFree: 79104 kB
    Buffers: 105712 kB
    将数据页写回磁盘
    可以使用fsync()或是sync()立即写回,如果没有直接调用这些函数,pdflush会定期刷回磁盘。

    iotop可以显示所有进程的IO占用情况
    lsof可以查看所有的调用并打开的文件

    其他命令:
    vmstat sar iostat top htop等

  • 相关阅读:
    03--软件包管理工具 apt
    02--linux操作系统基础学习笔记
    01--vim常用快捷键
    00--Linux常用命令大全
    07 --C语言字符串函数
    06--C语言数学函数
    (备忘)Rect和RectF的区别
    在android程序中加入widget(窗口小部件)并与之交互的关键代码
    (原)android的alertdialog中加入edittext但是不弹出软键盘等问题的解决与原因
    (转)dp和dip是同一个单位
  • 原文地址:https://www.cnblogs.com/muzinan110/p/11052370.html
Copyright © 2011-2022 走看看