性能之巅——洞悉系统、企业与云计算 Brendan Gregg

1.绪论

  • 系统性能是对整个系统的研究,包括所有的硬件组件和整个软件栈。所有数据路径上和软硬件上所发生的的事情都包括在内,都可能影响性能
  • 性能领域包含以下方面
    • 设置性能目标和建立性能模型
    • 基于软件或硬件原型进行性能特征归纳
    • 对开发代码进行性能分析(软件合并之前)
    • 执行软件非回归性测试(软件发布前或发布后)
    • 针对软件发布的基准测试
    • 目标环境中的概念验证测试
    • 生产环境部署的配置优化
    • 监控生产环境中运行的软件
    • 特定问题的性能分析
  • 分析视角:负载分析和资源分析
  • 性能分析是复杂的,系统或组件之间会互相干扰

2.方法

  • 术语
    • IOPS:每秒发生的输入/输出操作的次数
    • 吞吐量:评价工作执行速率。数据方面Byte/S。数据库方面 每秒操作数或每秒业务数
    • 响应时间:一次操作完成的时间。包含等待和服务的时间,也包含用来返回结果的时间
    • 延时:描述操作里用来等待的时间。有时也可指整个操作的时间,等同于响应时间
    • 使用率:对于服务所请求的资源,使用率描述在所给定的时间区间内资源的繁忙程度。对于存储资源来说,使用率指的就是所消耗的存储容量(例如,内存使用率)。
    • 饱和度:指的是某一资源无法满足服务的排队工作量。
    • 瓶颈:在系统性能力,瓶颈指的是限制系统性能的那个资源。分辨和移除系统瓶颈是系统性能的一项重要工作。
    • 工作负载:系统的输入或者是对系统所施加的负载叫做工作负载。对于数据库来说,工作负载就是客户端发出的数据库请求和命令。
    • 缓存:用于复制或者缓冲一定量数据的高速存储区域,目的是为了避免对较慢的存储层级的直接访问,从而提高性能。
  • 资源分析:以对系统资源【CPU、内存、磁盘、网卡、总线】的分析为起点。IOPS、吞吐量、使用率、饱和度。
  • 工作负载分析:检查应用程序的性能:所施加的工作负载和应用程序是如何响应的。
    • 请求:所施加的工作负载
    • 延时:应用程序的响应时间
    • 完成度:查找错误
系统性能分析方法
  • 街灯讹方法:使用熟悉的观测工具,使用试错的方式反复摸索,对所知道的参数进行设置,看看是否有帮助。
  • 随机变动讹方法:用户随机猜测问题可能存在的位置,然后做改动,直到问题解决。为了判断性能是否提升,或对每次变动结果做出判断,用户会选择一项指标进行研究。风险:做不了解的改动,在负载高峰期可能会引发更恶劣的问题,因此还需要准备一个回滚方案。
  • 责怪他人讹方法:为了避免成为牺牲品,向指责的人要屏幕截图,图中标明运行的是何种工具,输出是怎样中断的。
    • 1.找到一个不是你负责的系统或者环境的组件。
    • 2.假定问题与那个组件相关的
    • 3.把问题扔给负责那个组件的团队。
    • 4.如果证明错了,返回步骤1
  • Ad Hoc核对清单法:当需要检查和调试系统时,技术支持人员会花一点时间一步步地过一遍核对清单。Ad Hoc核对清单能有效保证所有人都知道如何检查最糟糕的问题,能覆盖所有显而易见的问题。
  • 科学法:问题,假设,预测,试验,分析
  • 工具法:这个视角的核对清单高速你那些工具能用,那些指标能读,以及怎样解释这些指标。逐个枚举会很耗时。
    • 列出可用到的性能工具
    • 对于每一个工具,列出它提供的有用的指标
    • 对于每一个指标,列出阐述该指标可能的规则。
  • USE方法:对所有资源,查看它的使用率、饱和度和错误。
    • 概念
      • 资源:所有服务器物理元器件(CPU、总线)
      • 使用率:在规定时间间隔内,资源用于服务工作的百分比。
      • 饱和度:资源不能再服务更多额外工作的程度,通常有等待队列。
      • 错误:错误事件的个数。
    • 指标
      • CPU使用率;CPU饱和度:分配队列长度
      • 内存使用率;内存饱和度:匿名换页或线程换出(页面扫描是另一个指标),或者OOM事件
      • 网络接口使用率:接收吞吐量/最大带宽,传输吞吐量/最大带宽
      • 存储设备I/O使用率:设备繁忙程度;存储设备I/O饱和度:等待队列长度。
    • 使用建议
      • 使用率:100%的使用率通常是瓶颈的信号(检查饱和度并确认影响)
      • 饱和度:任何程度的饱和度都是问题(非零)。饱和程度可以用排队长度或者排队所花的时间来度量
      • 错误:错误是值得研究的,尤其是随着错误增加性能会变差的那些错误。
  • 工作负载特征归纳:由施加的负载导致的问题。这个方法关注于系统的输入,而不是所产生的性能。你的系统可能没有任何架构或配置上的问题,但是系统的负载超出了它所能承受的合理范围。
  • 向下挖掘分析:深度分析开始于在高级别检查问题,然后依据之前发现缩小关注的范围,忽略那些无关的部分,更深入发掘那些相关的部分。整个过程会探究到软件栈较深的级别,如果需要,甚至还可以到硬件层,以求找到问题的根源。分为以下三个阶段:
    • 监测:用于持续记录高层级的统计数据,如果问题出现,与预辨别和报警
    • 识别:对于给定的问题,缩小研究的范围,找到可能的瓶颈
    • 分析:对特定的系统部分做进一步的检查,找到问题根源并量化问题。
  • 延时分析:检查完成一项操作所用的时间,然后把时间再分为小的时间段,接着对有着最大延时的时间段做再次划分,最后定位并量化问题的根本原因。分析可以从施加工作负载开始,检查工作负载是如何在应用程序中处理的,然后深入到操作系统的库、系统调用、内核以及设备驱动。
  • 静态性能调整:架构设置的问题。静态性能分析是在系统空闲没有施加负载的时候执行的。
  • 微基准测试:测量的是施加了简单人造工作负载的性能。微基准测试可以用于支持科学方法,将假设和预测放到测试中验证,或者作为容量规划的一部分来执行。
  • 可视化识别:通过试验收集到足够多的数据结果,就可以把它们绘制成性能随规模变化的曲线,这样的曲线可以揭示一定的规律。
    • 线图、散点图、热图
  • 容量规划可以检测系统处理负载的情况,以及系统如何随着负载的增加而扩展。
  • 统计:
    • 平均值:几何平均值、调和平均值
    • 标准方差
    • 百分位数、中位数
  • 监视:基于时间的规律;启动以来的信息统计。

3.操作系统

  • 上下文切换:内核程序切换CPU让其在不同的地址空间上做操作(上下文)。
  • I/O执行频繁的工作负载,如web服务器,会经常执行在内核上下文中。计算密集型的工作负载会尽量不打扰内核,因此它们能不中断地在CPU上运行。
  • 中断和中断线程
    • 中断服务程序通过注册来处理设备中断。这类程序的设计要点是需要运行得尽可能快,以减少对活动线程中断的影响。如果中断要做的工作不少,尤其是还可能被锁阻塞,那么最好用中断线程来处理,由内核调度
    • 对于Linux而言,设备驱动分为两部分,上半部用于快速处理中断,到下半部的调度工作在之后处理。上半部快速处理中断是很重要的,因为上半部运行在中断禁止模式,会推迟中断的产生,如果运行的时间太长,就会造成延时问题。下半部可以作为tasklet或者工作队列,之后由内核做线程调度,如果需要,也可以休眠。
  • 进程环境:包括进程地址空间内的数据和内核里的元数据(上下文)
  • Linux支持自愿内核抢占,在内核代码中的逻辑停止点可以做检查并执行抢占。这就避免了完全抢占式内核的某些复杂性,对于常见工作负载提供低延时的抢占。
  • Futex:提供高性能的用户级别的同步原语

4.观测工具

工具类型
  • 计数器
    • vmstat:虚拟内存和物理内存的统计
    • mpstat:每个CPU的使用情况
    • iostat:每个磁盘I/O的使用情况
    • netstat:网络接口统计,TCP/IP栈的统计,以及每个连接的一些统计信息
    • sar:各种各样的统计
    • ps:进程状态
    • top
    • pmap:将进程的内存段和使用统计一起列出
  • 跟踪
    • 系统日志
    • tcpdump
    • blktrace:块I/O跟踪
    • perf:Linux性能事件,跟踪静态或者动态指针
    • strace:基于Linux系统的系统调用跟踪
    • gdb
  • 剖析profiling:通过对目标收集采样或快照来归纳目标特征。
    • oprofile:Linux系统剖析
    • perf
  • 监视
    • sar 读取自己统计信息的归档数据来打印历史统计信息
观测来源
  • /proc 提供一个内核统计信息的文件系统接口。
    • 与进程性能观测相关的文件
      • limits:实际的资源限制
      • maps:映射的内存区域
      • sched:CPU调度器的各种统计
      • schedstat:CPU运行时间、延时和时间分片
      • smaps:映射内存区域的使用统计
      • stat:进程状态和统计,包括总的CPU和内存的使用情况
      • statm:以页为单位的内存使用总结
      • status:stat和statm的信息。用户可读
      • task:每个任务的统计目录
    • 与性能观测相关的系统级别的文件
      • cpuinfo:物理处理器信息,包括虚拟CPU、型号、时钟频率和缓存大小
      • diskstats:对于所有磁盘设备的磁盘I/O统计
      • interrupts:每个CPU的中断计数器
      • loadavg:负载平均值
      • meminfo:系统内存使用明细
      • net/dev:网络接口统计
      • net/tcp:活跃的TCP套接字信息
      • schedstat:系统级别的CPU调度器统计
      • self:关联当前进程ID路径的符号链接,
      • slabinfo:内核slab分配器缓存统计。
      • stat:内核和系统资源的统计,CPU、磁盘、分页、交换区、进程。
      • zoneinfo:内存区信息

第五章 应用程序

  • 执行I/O的开销包括初始化缓冲区、系统调用、上下文切换、分配内核元数据、检查进程权限和限制、映射地址到设备、执行内核和驱动代码来执行I/O,以及,在最后释放元数据和缓冲区。
  • 缓存:操作系统用缓存提高文件系统的读性能和内存的分配性能,应用程序使用缓存也出于类似的原因
  • 缓冲区:为了提高写性能,数据在送入下一层级之前会合并在缓冲区中,这增加了I/O大小,提升了操作的效率。

第六章 CPU

  • Linux平均负载表示可运行和正在运行的队列长度以及不可中断进程个数
  • 查看cpu数 grep ‘model name’ /proc/cpuinfo | wc -l
  • uptime
# uptime
15:41:50 up 62 days, 21:29,  1 user,  load average: 0.51, 0.43, 0.40
  • top
    • VIRT 是进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内。
    • RES 是常驻内存的大小,也就是进程实际使用的物理内存大小,但不包括 Swap 和共享内存。
    • SHR 是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等。
    • %MEM 是进程使用物理内存占系统总内存的百分比。
  • vmstat:
    • r表示正在运行或等待运行队列,
    • b表示不可中断状态进程数
    • us:用户态时间
    • sy:系统态时间(内核)
    • id:空闲
    • wa:等待I/O,及线程被阻塞等待磁盘I/O时CPU空闲时间
    • st: 偷取时间,CPU在虚拟化的环境下其他租户上的开销
# vmstat -w 
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
 r  b         swpd         free         buff        cache   si   so    bi    bo   in   cs  us  sy  id  wa  st
 2  0            0       882408         2616      5561352    0    0     0    18    2    2   7   5  88   0   0
  • mpstat:多处理器CPU统计
    • %irq:硬件中断CPU用量
    • %soft:软件中断CPU用量
# mpstat -P ALL 1
Linux 3.10.0-1160.6.1.el7.x86_64 (iZ2zeb9lhklwm0ado2pjwsZ)      08/12/2021      _x86_64_        (4 CPU)

04:00:23 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
04:00:24 PM  all   29.75    0.00    4.50    3.75    0.00    0.25    0.00    0.00    0.00   61.75
04:00:24 PM    0   22.22    0.00    1.01    2.02    0.00    1.01    0.00    0.00    0.00   73.74
04:00:24 PM    1   25.00    0.00    2.00    1.00    0.00    1.00    0.00    0.00    0.00   71.00
04:00:24 PM    2   19.19    0.00    9.09   10.10    0.00    0.00    0.00    0.00    0.00   61.62
04:00:24 PM    3   51.00    0.00    6.00    3.00    0.00    0.00    0.00    0.00    0.00   40.00
  • 历史CPU用量 sar
    • -P ALL 输出各CPU使用量
    • -u 输出平均CPU使用量
    • -q 包含运行队列长度runq-sz(等待数加上运行数,与vmstat中的r相同)和平均负载
  • 进程状态 ps aux
  • pidstat 按进程或线程打印CPU用量
    • -p ALL 打印所有进程,包含空闲进程
    • -t 打印线程
  • time 用来运行命令并报告CPU用量
$ time ls
dump.rdb  logs 

real    0m0.045s
user    0m0.001s
sys     0m0.002s

perf

  • annotate 读取perf.data(由perf record创建)并显示注释过的代码
  • evlist 列出一个perf.data文件里的事件名称
  • record 运行一个命令,并把剖析信息记录在perf.data中
  • report 读取perf.data并显示剖析信息
  • sched 跟踪/测量调度器属性(延时)的工具
  • script 读取perf.data并显示跟踪输出
  • stat 运行一个命令并收集性能计数器统计信息
  • top
  • 系统剖析
perf record -a -g -F 997 sleep 10
perf report --stdio
  • 进程剖析
perf record -g commend
  • 调度器延时
perf sched record sleep 10
perf sched latency
 -------------------------------------------------------------------------------------------------------------------------------------------
  Task                  |   Runtime ms  | Switches | Avg delay ms    | Max delay ms    | Max delay start           | Max delay end          |
 -------------------------------------------------------------------------------------------------------------------------------------------
  runc:[2:INIT]:(22)    |      4.263 ms |       22 | avg:   1.403 ms | max:   6.768 ms | max start: 5438093.891314 s | max end: 5438093.898082 s
  nginx:(4)             |   2946.288 ms |    22128 | avg:    0.038 ms | max:   17.533 ms | max at: 22252848.950345 s
  ksoftirqd/3:24        |    289.859 ms |    16674 | avg:    0.034 ms | max:   10.897 ms | max at: 22252859.206264 s
  sh:(2)                |      5.145 ms |       12 | avg:    0.032 ms | max:    0.253 ms | max at: 22252864.076503 s
  rcu_sched:9           |    168.639 ms |    13918 | avg:    0.031 ms | max:    8.001 ms | max at: 22252841.928397 s
  php-fpm:(1180)        |  36112.868 ms |   403985 | avg:    0.026 ms | max:   13.764 ms | max at: 22252850.055355 s
  • 软件跟踪
    • -e 跟踪事件,事件列表使用perf list获取
    • page fault缺页异常分为两种类型,一种叫做major page fault,这种类型的缺页可以通过 Disk IO来满足,另一种叫做minor page fault,这种缺页可以直接利用内存中的缓存页满足。
    # -e 跟踪上下文切换
    perf record  -g -a -e context-switches sleep 30
    perf report --stdio
    
  • 可视化 火焰图
概念
  • CPU指令执行
    • 指令预取
    • 指令解码
    • 执行
    • 内存访问
    • 寄存器写回
  • 指令流水线是一种CPU架构,通过同时执行不同指令的不同部分,来达到同时执行多个指令的结果
  • 指令宽度描述了同时处理的目标指令数量。现代处理器一般为宽度3或者宽度4,意味着它们可以在每个周期里最多完成3~4个指令
  • 每指令周期数CPI:指令运行需要周期数。CPI较高代表CPU经常陷入停滞,通常 都是在访问内存。内存访问密集的负载,可以通过下面的方法提高性能,如何用更快的内存(DRAM)、提高内存本地性(软件配置),或者减少内存I/O数量。
  • 使用率:CPU内核时间和用户时间
  • 饱和度:队列长度
软件
  • 调度器

    • 分时:可运行线程之间的多任务,优先级执行最高优先级任务
    • 抢占:一旦有高优先级线程变为可运行状态,调度器能够抢占当前运行的线程,这样较高优先级的线程可以马上开始运行
    • 负载均衡:把可运行的线程移到空闲或者不繁忙的CPU队列中。
  • 调度类:

    • RT:为实时类负载提供固定的高优先级。内核支持用户和内核级别的抢占,允许RT任务以短延时分发。优先级范围为0~99
    • O(1):O(1)调度器在Linux2.6作为默认用户进程分时调度器引入。名字来源于算法复杂度O(1)。
    • CFS:完全公平调度,Linux2.6.23的默认分时调度器。这个调度器使用红黑树取代了传统运行队列来管理任务,以任务的CPU时间为键值。这样使得CPU的少量消费者相对于CPU消耗型负载更容易被找到,提高了交互和I/O消耗型负载的性能
  • 调度器策略:用户级进程可以通过sched_setscheduler()设置调度器策略以调整调度类的行为。RT类支持SCHED_RR和SCHED_FIFO策略。而CFS类支持SCHED_NORMAL和SCHED_BATCH。

    • RR:SCHED_RR是轮转调度。一旦一个线程用完了它的时间片,它就被挪到了自己优先级运行队列的尾部,这样同等优先级的其他线程可以运行
    • FIFO:SCHED_FIFO是一种先进先出调度,一直运行队列头的线程直到它自愿退出,或者一个更高优先级的线程抵达。线程会一直运行,即便在运行队列当中存在相同优先级的其他进程
    • NORMAL:SCHED_NORMAL(也称为SCHED_OTHER)是一种分时调度,是用户进程的默认策略。调度器根据调度类动态调整优先级。对于CFS,时间片是动态的。
    • BATCH:SCHED_BATCH和SCHED_NORMAL类似,但期望线程是CPU消耗型的,这样就不会打断其他I/O消耗型交互工作。
基于资源容量规划
  • 确定目标用户数或者应用程序请求频率
  • 转化为每用户或每请求CPU使用率,对于现有系统,CPU用量可以通过监控获得,再除以现有用户数或请求数,对于未投入使用系统,负载生成工具可以模拟用户,以获得CPU用量
  • 推算出当CPU资源达到100%使用率时的用户或者请求数,这就是系统理论上限
基准测试
  • CPU指令:整数运算、浮点操作、内存加载和存储、分支和其他指令
  • 内存访问:调查不同CPU缓存的延时和主存吞吐量
  • 高级语言:类似CPU指令测试,不过使用高级解释或者编译语言编写
  • 操作系统操作:测试CPU消耗性系统库和系统调用函数,例如getpid()和进程创建
  • CPU基准测试工具 sysbench
# 8线程,最多计算100 000个质数
sysbench --threads=8 --cpu-max-prime=100000 cpu run
性能调优
  • CPU绑定:把进程或线程绑定在单个CPU或一组CPU上,增加进程的CPU缓存温度,提高内存I/O性能
    • 进程绑定:配置一个进程只跑在单个CPU上,或者预定义CPU组中的一个
    • 独占CPU组:分出一组CPU,让这些CPU只能运行指定的进程。这可以更大地提升CPU缓存效率,因为当进程空闲时,其他进程不能使用CPU,保证了缓存的温度。
    • Linux独占CPU组可以通过cpuset实现。
    mkdir /dev/cpuset
    mount -t cpuset cpuset /dev/cpuset
    cd /dev/cpuset
    mkdir prodset # 创建一个叫prodset的cpuset
    cd prodset
    echo 7-10 >cpus # 分配7-10号cpu
    echo 1 > cpu_exclusive # 设置prodset为独有的exclusive
    echo 1159 > tasks # 分配PID 1159 到prodset
    
    # 查看进程绑定,3表示11,两个cpu都可运行
    taskset -p 35726
    pid 35726's current affinity mask: 3 
    
    # 设置进程绑定第二个cpu,cpu是从0开始算的
    taskset -pc 1 35726
    pid 35726's current affinity list: 0,1
    pid 35726's new affinity list: 1
    
    # 启动程序时绑定进程到第二个cpu
    taskset -c 1 nginx
    
  • 调度优先级
    • 以nice19运行命令:nice -n 19 command
    • renice 更改一个已经在运行进程的优先级
    • Linux chrt命令可以显示并直接设置优先级和调度策略
cpu上下文切换
  • CPU 寄存器,是 CPU 内置的容量小、但速度极快的内存。而程序计数器,则是用来存储 CPU 正在执行的指令位置、或者即将执行的下一条指令位置。它们都是 CPU 在运行任何任务前,必须的依赖环境,因此也被叫做 CPU 上下文。
  • CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
  • 系统调用:一直是同一个进程在运行。
    • 一次系统调用的过程,其实是发生了两次 CPU 上下文切换。CPU 寄存器里原来用户态的指令位置,需要先保存起来。接着,为了执行内核态代码,CPU 寄存器需要更新为内核态指令的新位置。最后才是跳转到内核态运行内核任务。而系统调用结束后,CPU 寄存器需要恢复原来保存的用户态,然后再切换到用户空间,继续运行进程。
    • 系统调用过程中,并不会涉及到虚拟内存等进程用户态的资源,也不会切换进程,但实际上,系统调用过程中,CPU 的上下文切换还是无法避免的。
    • 系统调用过程通常称为特权模式切换,而不是上下文切换。
  • 进程上下文切换:是指从一个进程切换到另一个进程运行。只有在进程调度的时候,才需要切换上下文。
    • 进程是由内核来管理和调度的,进程的切换只能发生在内核态。所以,进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。
    • 进程的上下文切换就比系统调用时多了一步:在保存当前进程的内核状态和 CPU 寄存器之前,需要先把该进程的虚拟内存、栈等保存下来;而加载了下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈。
    • 根据 Tsuna 的测试报告,每次上下文切换都需要几十纳秒到数微秒的 CPU 时间。这个时间还是相当可观的,特别是在进程上下文切换次数较多的情况下,很容易导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间。
    • Linux 通过 TLB(Translation Lookaside Buffer)来管理虚拟内存到物理内存的映射关系。当虚拟内存更新后,TLB 也需要刷新,内存的访问也会随之变慢。特别是在多处理器系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程。
    • 进程调度时机
      • 其一,为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行。
      • 其二,进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行。
      • 其三,当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度。
      • 其四,当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行。
      • 最后一个,发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序。
  • 线程上下文切换
    • 线程与进程最大的区别在于,线程是调度的基本单位,而进程则是资源拥有的基本单位。所谓内核中的任务调度,实际上的调度对象是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。
    • 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时是不需要修改的。
    • 线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时也是需要保存的。
    • 线程的上下文切换其实就可以分为两种情况:
      • 第一种, 前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上下文切换是一样。
      • 第二种,前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。
    • 虽然同为上下文切换,但同进程内的线程切换,要比多进程间的切换消耗更少的资源,而这,也正是多线程代替多进程的一个优势。
  • 中断上下文切换
    • 为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行。
    • 跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。所以,即便中断过程打断了一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。中断上下文,其实只包括内核态中断服务程序执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数等。
    • 对同一个 CPU 来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。同样道理,由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束。
  • 过多的上下文切换,会把 CPU 时间消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上,缩短进程真正运行的时间,成了系统性能大幅下降的一个元凶。
  • 中断类型查看 watch -d cat /proc/interrupts
资源控制
  • cgroups

第七章 内存

  • 概念:
    • 常驻内存:当前处于主存中的内存
    • 匿名内存:无文件系统位置或者路径名的内存,它包括进程地址空间的工作数据,称作堆。
    • 地址空间:内存上下文。每个进程和内核都有对应的虚拟地址空间。
    • 段:标记为特殊用途的一块内存区域,例如用来存储可执行或者可写的页。
  • 换页:
    • 文件系统换页:文件系统换页由读写位于内存中的映射文件页引发,对于使用文件内存映射的应用程序和使用了页缓存的文件系统,这是正常的行为。有需要时,内核可以调出一些页释放内存。这种说法变得有些复杂:如果一个文件系统页在主存中修改过(“脏的”),页面换出要求将该页写回磁盘。相反,如果文件系统页没有修改过(“干净的”),因为磁盘已经存在一份副本,页面换出仅仅是释放这些内存以便立即使用。
    • 匿名换页:牵涉进程的私有数据:进程堆和栈。被称为匿名是由于它在操作系统中缺乏有名字的地址(例如,没有文件系统路径)。匿名页面换出要求迁移到物理交换设备或者交换文件。Linux用交换(swapping)来命名这种类型的换页。匿名换页拖累性能,因此称为“坏的”换页。当应用程序访问被调出的页时,会被读页的磁盘I/O阻塞。这就是匿名页面的换出,它会给应用程序带来同步延时。匿名页面换出可能不会直接影响应用程序性能,因为它由内核异步执行。
  • 缺页:
    • 轻微缺页:映射可以由内存其他页满足
    • 严重缺页:需要访问存储设备的缺页
  • linux过度提交:允许分配超过系统可以存储的内存–超过物理内存和交换设备的总和。它依赖于按需换页以及应用程序通常不会使用分配给它们的大部分内存。
  • 文件系统缓存:系统启动之后内存的占用增加是正常的,因为操作系统会将可用内存用于文件系统缓存以提高性能。该原则是:如果有可用的主内存,就有效地使用它。初级用户有时看到启动后可用内存减少到接近零,这不会对应用程序造成影响,因为在应用程序需要的时候,内存应该能够很快从系统缓存中释放内存。
  • 主内存的使用率可由已占用的内存除以总内存得出。文件系统缓存占用的内存可以被当做未使用,因为它可以被应用程序重用。
  • 对内存的需求超过主存的情况被称作主存饱和。这时操作系统会使用换页、交换或者在LINUX中用OOM终结者来释放内存。以上任一操作都标志着主存饱和。
  • 当虚拟内存处理多任务物理内存时,在虚拟地址空间中实际分配和内存堆放通常由分配器来处理。用户态库或者内核程序向程序员提供简单的内存使用接口(例如malloc()、free())。分配器对性能有显著地影响,一个系统通常会提供多个可选择的用户分配器库。
硬件
  • 主存:动态随机存取内存DRAM
    • 延时
    • 架构:对称多处理器架构SMP,内存访问延时相同。非均匀访存模型NUMA系统:对主存的访问时间随着相对CPU的位置不同而变化。
  • 总线
    • 共享系统总线:单个或多个处理器,通过一个共享的系统总线、一个内存桥控制器以及内存总线
    • 直连:单个处理器通过内存总线直接连接内存
    • 互联:多处理器中每一个通过一条内存总线与各自的内存直连,并且处理器之间通过一个CPU互联连接起来。
  • CPU缓存
  • MMU(内存管理单元)
  • 内存带宽计算公式:带宽=内存核心频率×内存总线位数×倍增系数。
    • 先容我从DDR的技术说起,DDR采用时钟脉冲上升、下降沿各传一次数据,1个时钟信号可以传输2倍于SDRAM的数据,所以又称为双倍速率SDRAM。它的倍增系数就是2。DDR2仍然采用时钟脉冲上升、下降支各传一次数据的技术(不是传2次),但是一次预读4bit数据,是DDR一次预读2bit的2倍,因此,它的倍增系数是2X2=4。
      DDR3作为DDR2的升级版,最重要的改变是一次预读8bit,是DDR2的2倍,DDR的4倍,所以,它的倍增系数是2X2X2=8。
      下面计算一下一条标称DDR3 1066的内存条在默认频率下的带宽:
      1066是指有效数据传输频率,除以8才是核心频率。一条内存只用采用单通道模式,位宽为64bit。所以内存带宽=(1066/8)×64×8=68224Mbit。由此可知,如果内存工作在标称频率的时候,可以直接用标称频率×位宽,简化公式。再根据8bit(位)=1Byte(字节),得68224/8=8528MByte=8.328125GB。再以两条标称1066超频到1200的DDR3内存,组成双通道后的带宽:超频到1200后,内存核心频率应为1200/8=150MHz,而双通道的位宽=128bit:带宽=150×128×8=153600Mbit=18.75GB
  • CPU缓存:处理器通常会在芯片中包含硬件缓存以提高内存访问性能。
    • L1:通常分为指令缓存和数据缓存
    • L2:同时缓存指令和数据
    • L3:更大一级的缓存。
  • MMU(内存管理单元):负责虚拟到物理地址的转换。它按页做转换,而页内的偏移量则直接映射。
  • 内存管理单元
软件
  • 页扫描:内核页面换出守护进程管理利用换页释放内存。当主存中可用的空闲列表低于某一个阈值时,页面换出守护进程会开始页扫描。页扫描仅按需启动,

  • Linux页面换出守护进程称作kswapd(),它扫描非活动和活动内存的LRU(最近最少使用)页列表以释放页面。

  • 进程地址空间:一段范围的虚拟页,由硬件和软件同时管理,按需映射到物理页。

    • 堆增长:对于大多数分配器,free()不会将内存还给操作系统,相反,会保留它们以备将来分配。这意味着进程的常驻内存只会增长,并且是正常现象
  • 内存分配器

    • 内核级分配器slab和SLUB
    • 用户级分配器libmalloc、libumem和mtmalloc
  • 工具

    • 页扫描 :sar -B 检查pgscan列
    • vmstat:虚拟内存统计信息命令vmstat 1 3 -a -Sm
    • sar:系统活动报告工具,可以用来观测当前活动并且能够配置保存和报告历史统计数据。
        • B 换页统计信息
        • pgpgin/s 页面换入 KB/s
        • pgpgout/s 页面换出 KB/s
        • fault/s 严重及轻微缺页 次数/s
        • majflt/s 严重缺页 次数/s
        • pgfree/s 页面加入空闲链表 次数/s
        • pgscank/s 被后台页面换出守护进程扫描过的页面(kswapd) 次数/s
        • pgscand/s 直接页面扫描 次数/s
        • pgsteal/s 页面及交换高速缓存回收 次数/s
        • %vmeff 页面盗取/页面扫描比例,显示页面回收的比例。高数值意味着成功地从非活动列表中回收页(健康),低数值意味着系统在挣扎。
        • H 大页面统计信息
        • kbhugfree 空闲巨型页面存储器 KB
        • kbhugused 占用的巨型页面存储器 KB
        • %hugused
        • r 内存使用率
        • kbmemused 占用存储器(不包括内核)
        • kbbuffers 缓冲告诉缓存尺寸
        • kbcached 页面高速缓存尺寸
        • kbcommit 提交的主存储器:服务当前工作负载需要量的估计
        • kbactive 活动列表存储器尺寸
        • kbinact 非活动列表存储器尺寸
        • R 内存统计信息
        • frmpg/s 释放的存储器页面,负值表明分配
        • bufpg/s 缓冲高速缓存增长值(增长)
        • campg/s 页面高速缓存增加值(增长)
    • pmap:列出进程的内存映射,显示他们的大小、权限及映射的对象。
    • slabtop 内核是slab缓存使用情况
    • ps
    ps -eo pid,pmem,vsz,rss,comm
    # %MEM:主存使用(物理内存、RSS)占总内存的百分比
    # RSS:常驻集合大小(KB)
    # VSZ:虚拟内存大小(KB)
    
  • 最重要的内存调优是保证应用程序保留在主存中,并且避免换页和交换经常发生。

  • 更大的页面能提高TLB缓存的命中率(增加它的覆盖范围)来提升内存I/O性能。现代处理器支持多个页面大小,例如默认的4KB以及2MB的大页面

第八章 文件系统

  • 文件系统通过缓存、缓冲以及异步I/O等手段来缓和磁盘(或者远程系统)的延时对应用程序的影响。

  • 文件系统缓存:主存(通常是DRAM)的一块区域,用来缓存文件系统的内容,可能包含各种数据和元数据。

  • 逻辑I/O:由应用程序发给文件系统的I/O

  • 物理I/O:由文件系统直接发给磁盘的I/O(或者通过裸I/O)。

  • 文件系统延时是文件系统性能的一项主要的指标,指的是一个文件系统逻辑请求从开始到结束的时间,它包括了消耗在文件系统、内核磁盘I/O子系统以及等待磁盘设备–物理I/O的时间。

  • 文件系统用缓存(caching)提高读性能,而用缓冲(buffering)(在缓冲中)提高写性能。

  • 一连串的文件系统逻辑I/O,按照每个I/O的文件偏移量,可以分为随机I/O与顺序I/O。顺序I/O里每个I/O都开始于上一个I/O结束的地址。随机I/O里找不出I/O之间的关系,偏移量随机变化。

  • 文件系统可以测量逻辑I/O的访问模式,从中识别出顺序I/O,然后通过预取或者预读来提高性能。

  • 预取是文件系统解决这个问题的通常做法。通过检查当前和上一个I/O的文件偏移量,可以检测出当前是否是顺序读负载,并且做出预测,在应用程序请求前向磁盘发出读命令,以填充文件系统缓存。这样,如果应用程序真的发出了读请求,就会命中缓存。

    • 预取的预测一旦准确,应用程序的读性能将会有显著提升,磁盘在应用程序请求前就把数据读出来了。而一旦预测不准,文件系统会发起应用程序不需要的I/O,不仅污染了缓存,页消耗了磁盘与I/O传输的资源。
  • 写回缓存广泛地应用于文件系统,用来提高性能。它的原理是,当数据写入主存后(从应用程序地址空间复制到内核空间),就认为写入已经结束并返回,之后再异步地把数据刷入磁盘。文件系统写入“脏”数据的过程称为刷新(flushing)。牺牲了可靠性。

  • 同步写完成的标志是,所有的数据以及必要的文件系统元数据被完整地写入到永久存储介质中。由于包含磁盘I/O的延时,所以肯定比异步写(写回缓存慢的多)。同步写有两种形式:单次I/O的同步写,和一组已写I/O的同步提交。

    • 单次同步写:linux中使用O_SYNC标志打开一个文件后,这个文件的写I/O即为同步。
    • 同步提交已写内容:一个应用程序可以在检查点使用fsync()系统调用,同步提交之前异步写入的数据,通过合并同步写提高性能。
  • 裸I/O:绕过了整个文件系统,直接发给磁盘地址。例子:数据库

  • 直接I/O:允许应用程序绕过缓存使用的文件系统。

    • 直接I/O可用于备份文件系统的应用程序,防止只读一次的数据污染文件系统缓存。裸I/O和直接I/O还可以用于那些在进程堆里自建缓存的应用程序,避免了双重缓存的问题。
  • 非阻塞I/O:一般而言,文件系统I/O要么立即结束(如从缓存返回),要么需要等待(比如等待磁盘设备I/O)。如果需要等待,应用程序线程会被阻塞并让出CPU,在等待期间给出其他线程执行的机会。但是某些情况下,非阻塞I/O正合适,因为可以避免线程创建带来的额外性能和资源开销。在调用open()系统调用时,可以传入O_NONBLOCK或者O_NDELAY选项使用非阻塞I/O。这样读写时就会返回错误代码EAGAIN,让应用程序过一会儿再重试,而不是阻塞调用。

  • 内存映射文件:把文件映射到进程地址空间,并直接存取内存地址的方法来提高文件系统I/O性能、这样可以避免调用read()和write()存取文件数据时产生的系统调用和上下文切换开销。

  • Linux文件系统缓存

    • 缓冲区高速缓存:从2.4开始,缓冲区高速缓存就被存放在了页缓存中。防止双重缓存和同步的开销。
    • 页缓存:缓存了虚拟内存的页面,包括了文件系统的页面,提升了文件和目录的性能。在Linux2.6.32以前,有一个脏页写回(pdflush)线程池,池中根据需要有 2~8 个线程。现在这已经被写回线程(flusher thread,线程名为flush)所取代,每个设备分配一个线程。这样能平衡每个设备的负载,提高吞吐量。
    • 目录项缓存Dcache记录了目录项到VFS inode的映射关系。它提高了路径名查找的性能。目录项缓存也可反向缓存,记录缺失目录项的查找。
    • inode缓存:这个缓存的对象是VFS inode(struct inode),每个都描述了文件系统一个对象的属性。这些属性可以通过stat()系统调用获得,并被操作系统频繁访问。
  • 基于块的文件系统把数据存储在固定大小的块里,被存储在元数据块里的指针引用。

  • 基于区段的文件系统预先给文件(区段)分配连续的空间,并随需增长。虽然带来了额外的空间开销,但提高了连续数据流的性能,也由于更高的文件数据本地化效应,提高了随机I/O的性能。

  • 文件系统日志(或者记录)记录了文件系统的更改,这样在系统宕机时,能原子地回放更改–要么完全成功,要么完全失败。日志被同步写入磁盘,有些文件系统还会把日志写入到一个单独的设备上。

  • fsck(file system check)用来检查和维护不一致的文件系统。

  • ext系统:

    • (ext3)
      • 日志:一种顺序模式,仅针对元数据,另一种是日志模式,针对数据和元数据。日志提高了系统宕机后的启动速度,避免fsck。由于合并了一些元数据的写操作,它有可能提高某些写负载的性能。
      • 日志设备:允许使用外部日志设备,避免日志负载和读负载相互竞争。
      • orlov块分配器:这项技术把顶层目录散布到各个柱面组,这样目录和其中的内容更有可能被放在一起,减少随机I/O。
      • 目录索引:在文件系统里引入哈希B树,提高目录的查找速度。
    • (ext4新加)
      • 区段:区段提高了数据的连续性,减少了随机I/O,提高了连续I/O的大小
      • 预分配:通过fallocate()系统调用,让应用程序预分配一些可能连续的空间,提高之后的写性能。
      • 延时分配:块分配推迟到写入磁盘时,方便合并写请求(通过多块分配器),降低碎片化。
      • 更快的fsck:标记未分配的块和inode项,减少fsck时间。
  • 卷把多块磁盘组合成一块虚拟磁盘,在此之上建立文件系统。在整块磁盘上建立文件系统时(不是分片或者分区),卷能够隔离负载,降低竞争,缓和性能问题。

  • linux分析工具:strace -ttT -p 845

  • 高级负载特征归纳/检查清单

    • 文件系统缓存命中率是多少?未命中率是多少
    • 文件系统缓存有多大?当前使用情况如何?
    • 现在还使用了其他什么缓存(目录、inode、高速缓冲区)和它们的使用情况?
    • 那个应用程序或者用户在使用文件系统?
    • 那些文件和目录正在被访问?是创建和删除吗?
    • 碰到了什么错误吗?是不是由于一些非法请求,或者文件系统自身的问题?
    • 为什么要发起文件系统I/O(用户程序的调用路径)?
    • 应用发起的文件系统I/O的同步的比例占到多少?
    • I/O抵达时间的分布是怎样的?
  • Linux工具

    • free -m
    • top
    • vmstat buff缓冲区高速缓存大小,cache显示页缓存大小
    • sar -v 1
      • dentunusd:目录项缓存未用计数
      • file-nr:使用中的文件描述符个数
      • inode-nr :使用中的inode个数
    • slabtop:
      • dentry:目录项缓存
      • inode_cache:inode缓存
      • ext4_inode_cache::ext4的inode缓存
    • /proc/meminfo
    • dd if=/dev/zero of=file1 bs=1024k count=1k
    • dd if=file1 of=/dev/null bs=1024k
    • 使用哈希B树以提高大目录的查找速度 tune2fs -O dir_index /dev/hdx
    • 重建文件系统目录的索引 e2fsck -D -f /dev/hdx
    • mount可以使用选项noatime以禁用文件访问时间戳更新,可以减少后端I/O,提高文件系统性能

第九章 磁盘

  • 磁盘I/O可能造成严重的应用程序延时,因此是系统性能分析的一个重要目标。在高负载下,磁盘成为了瓶颈,CPU持续空闲以等待I/O结束。
  • I/O响应时间:
    • 服务时间:I/O得到主动处理的时间,不包括在队列中等待的时间
    • 等待时间:I/O在队列中等待服务的时间
  • 对操作系统而言,服务时间可以从I/O请求发到磁盘设备开始计算,到结束中断发生为止。它并不包括在操作系统队列里等待的时间,仅仅反映了磁盘设备到操作请求的总体性能。
  • 而对于磁盘而言,服务时间指从磁盘开始主动服务I/O算起,不包括磁盘队列里等待的时间。
  • 最好的磁盘I/O就是没有I/O。许多软件栈尝试通过缓存读和缓存写来避免磁盘I/O抵达磁盘。
  • 一个读频率较高的系统可以通过增加缓存来获取性能提升,而一个写频率较高的系统可以通过增加磁盘来提高最大吞吐量和IOPS。
  • I/O等待是针对单个CPU的性能指标,表示当CPU分发队列(在睡眠态)里有线程被阻塞在磁盘I/O上时消耗的空闲时间。
  • 工具
    • iostat -xt 1:avgrq-sz是合并请求之后的数字,小尺寸(16个扇区或更小)可以视为无法合并的随机I/O负载的现象。大尺寸有可能是大I/O,或者合并的连续负载。
    Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
    vdb               0.00   463.00    0.00  113.00     0.00  2752.00    48.71     0.29    2.72    0.00    2.72   0.38   4.30
    rrqm/s:每秒合并放入驱动请求队列的读请求数
    r/s:每秒发给磁盘设备的读请求数
    avgrq-sz:平均请求大小,单位为扇区(512B)
    avgqu-sz:在驱动请求队列和在设备中活跃的平均请求数。
    %util:设备忙处理I/O请求的百分比(使用率)
    
    • iotop:发现那个进程引发了磁盘I/O
    • sar -d 历史磁盘统计 wr_sec/s,每秒磁盘写入扇区数(512B)
    • pidstat -d 1 。kB_ccwr/s:每秒取消的写入KB数(例如,写回前的覆盖写)
    • perf
    perf list|grep block:
    perf record -age block:block_rq_issue sleep 10
    perf report |more
    
    • blktrace启动内核块驱动跟踪机制获取跟踪裸数据,供blkparse处理以产生可读的输出
    # 两命令等价
    blktrace -d /dev/vdb1 -o -|blkparse -i -
    btrace /dev/vdb1
    btrace -a issue /dev/vdb1 # 仅跟踪D活动(发出I/O)
    仅跟踪读(-a read)
    仅跟踪写(-a write)
    仅跟踪同步(-a sync)
    

第十章 网络

  • 网络性能:
    • 网络延时
    • 吞吐量
    • 丢包
  • 网络分析是跨硬件和软件的。硬件指的是物理网络,包括网络接口卡、交换机,路由器和网关。系统软件指的是内核协议栈,通常是TCP/IP,以及每个所涉及的协议的行为
  • SYN洪水是一种Dos攻击类型,它从伪造的IP地址发送大量的SYN包到TCP侦听端口。这会在TCP等待完成握手时填满积压队列,进而阻塞真实的客户连接。
  • 对于过去基于ICMP的网络工具攻击(包括“死亡之ping”),防火墙管理员通常以阻塞所有ICMP包的方式应对。这会阻止有用的“不能分段”报文到达发送方,并且一旦包超过1500将导致网络包被静默地丢弃。为避免这个问题,许多系统坚持使用默认的1500MTU。
  • 延时:
    • 主机名解析延时:DNS解析
    • ping延时:测量IMCP echo请求到echo响应所需的时间。该时间用来衡量主机对之间包括网络跳跃的网络延时,而且它测量的是包往返的总时间。
    • 连接延时:传输任何数据前建立网络连接所需的时间
    • 首字节延时:从连接建立到接收到第一个字节数据所需的时间。这包括远程主机接受连接、调度提供服务的线程,并且执行线程以及发送第一个字节所需的时间。
    • 往返时间:网络包往返两个端点所需的时间
    • 连接生命周期:指一个网络连接从建立到关闭所需的时间。一些协议支持长连接策略因而之后的操作可以利用现有的连接,进而避免这种操作系统开销以及建立连接的延时。
  • 缓冲:尽管存在多种网络延时,利用发送端和接收端的缓冲,网络吞吐量仍能保持高速率。TCP利用缓冲以及可变的发送窗口提升吞吐量。网络套接字也保有缓冲,并且应用程序可能也会利用它们自己的缓冲在发送前聚集数据。
  • TCP的积压队列实现会把SYN请求在用户级进程接收前列队于内核中。
  • TCP:就性能而言,即使在高延时的网络中,利用缓冲和可变窗口,TCP也能够提供高吞吐量。TCP会利用阻塞控制以及由发送方设置的阻塞窗口,因而不仅能保持高速而且在跨越不同并变化的网络中保持合适的传输速率。阻塞控制能避免会导致网络阻塞进而损害性能的过度发送
    • 可变窗口:允许在收到确认前在网络上发送总和小于窗口大小的多个包,以在高延时的网络中提供高吞吐量。窗口的大小由接收方通知以表明当前它愿意接收的包的数量
    • 阻塞避免:阻止发送过多数据进而导致饱和,它会导致丢包而损害性能
    • 缓启动:TCP阻塞控制的一部分,它会以较小的阻塞窗口开始而后按一定时间内接收到的确认(ACK)逐渐增加。如果没有接收到,阻塞窗口会降低。
    • 选择性确认(SACK):允许接收方通知发送方收到非连续的数据块,以减少需要重传输的数量。
    • 快速重传输:TCP能基于重复收到的确认重传输被丢弃的包,而不是等待计时器超时。这只是往返时间的一部分而不是通常更慢的计时器
    • 快速恢复:通过重设连接开始慢启动,以在检测到重复确认后恢复TCP性能
  • 延时确认:累计确认可以允许TCP延迟一段时间发送ACK,以便将ACK和相同方向上需要传输的数据结合发送。限制最大延时时长,免得引起不必要的超时重传
  • Nagle算法:当一个TCP连接在传数据(已发送未确认的数据),小的报文段(长度小于SMSS)就不能被发送,直到所有的在传数据都收到ACK。并且,在收到ACK后,TCP需要收集这些小数据,将其整合到一个报文段中发送。ACK返回越快,数据传输也越快。传输的包数目更少而长度更大,但同时传输时延也更长。
  • 硬件
    • 接口:物理网络接口在连接的网络上发送并接收称为帧的报文。它们处理包括传输错误在内的电器、光学或者无线信号。
    • 控制器:物理网络接口由控制器提供给系统,它集成在系统板或者利用扩展卡。控制器由微处理器驱动并通过I/O传输通道(例如PCI)接入系统。其中任意一个都可能成为网络吞吐量或者IOPS的瓶颈
    • 交换机、路由器:交换机提供两个连入的主机专用的通信路径,允许多对主机间的多个传输不受影响。路由器在网络间传输数据包,并且用网络协议和路由表来确认最佳传递路径。
  • 软件:网络栈、TCP和设备驱动程序
    • 网络栈:现代内核中网络栈是多线程的,并且传入的包被多个CPU处理,Linux3.7实现了如下方法平衡CPU负载:
      • RSS,接收端缩放:现代的NIC能支持多个队列并且计算包哈希以置于不同队列,而后依次按直接中断由不同的CPU处理。这个哈希值可能基于IP地址以及TCP端口号,因此源自同一个连接的包能被同一个CPU处理
      • RPS,接收数据包转向:对于不支持多个队列的NIC的RSS实现。一个短中断服务例程映射传入的数据包给CPU处理,用一个类似的哈希按数据包头的字段映射数据包到CPU
      • RFS,接收流转向:类似于RPS,不过偏向于前一个处理套接字的CPU,以调高CPU缓存命中率以及内存本地性。针对的是软中断处理数据栈之后保证应用程序能和软中断在同一个cpu上,增加缓存命中。
      • 加速接收数据流转向:对于支持该功能的NIC,这是RFS的硬件实现。它用流信息更新NIC以确定中断那个CPU。
      • XPS,传输数据包转向:对于支持多个传输队列的NIC,这支持多个传输队列。XPS通过创建CPU到网卡发送队列的对应关系,来保证处理发送软中断请求的CPU和向外发送数据包的CPU是同一个CPU,用来保证发送数据包时候的局部性。
  • 积压队列:
    • SYN积压队列:TCP握手完成前处理未完成的连接。
    • 侦听积压队列:等待应用程序接收的已建立的会话。accept前的队列。由listen的积压队列参数设置。
  • iperf测试最大TCP和UDP吞吐量工具
    • iperf -c 10.0.0.2 -l 128k -P 2 -i 1 -t 60
    • -l 128k:使用128k套接字缓冲区
    • -P 2:两个客户机线程的并行模式
    • -i 1:打印间隔
    • -t 60:测试60s
  • 调优
    • 套接字和缓冲区 net.ipv4.tcp_rmem/tcp_wmem
    • TCP积压队列
      • 第一个积压队列tcp_max_syn_backlog
      • 第二个net.core.somaxconn
    • 设备积压队列:net.core.netdev_max_backlog
    • 复用TIME_WAIT会话 tcp_tw_reuse和tcp_tw_recycle
  • 工具
    • netstat
      • -s 网络栈统计信息
      • -i 网络接口信息
      • -r 列出路由表
    • ss -s
    • sar
      • -n DEV 网络接口统计
      • -n EDEV 网络接口错误
      • -n SOCK 套接字使用
    • traceroute 路由追踪
    • iftop
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值