• 实时linux


    前言

    NFV(网络功能虚拟化)由运营商联盟提出,为了加速部署新的网络服务,运营商倾向于放弃笨重昂贵的专用网络设备,转而使用标准的IT虚拟化技术来拆分网络功能模块。在传统CT网络中对于服务质量保证的要求是非常高的,简而言之就是高带宽,高可靠,低时延。这些要求对于虚拟化技术而言本身就具有非常大的挑战。在虚拟化场景下,Hypervisor对vcpu本身要进行调度,而在Guest中vcpu对正在运行的程序也需要调度。这种二层调度使得低时延在虚拟化场景下是一个很难解决的问题。而解决低时延很大程度上需要使用实时操作系统。

    我们知道,相对比vxworks,linux内核属于非实时操作系统,原因主要是:

    (1)实时任务抢占时间是不可预期的。

    (2)为什么抢占是不可预期的呢?这涉及到内核中的抢占点知识,其中spin_lock锁,在unlock时是一个抢占点,但是spinlock本身内部是不可以抢占的,这种api在内核中大量使用,事实上是spin_lock与spin_unlock之间临界区代码片段不可预期的。

    具体用一个例子来说明,为什么linux不是实时的。

    某场景:

    一个普通任务运行过程中,通过系统调用进入内核态拿了一把spin_lock这样的锁,在拿锁过程中,发生了硬件中断,于是cpu立即去处理硬件中断,在这个硬件中断处理函数(ISR)中唤醒了一个RT任务,硬件中断处理完后,还有可能处理软中断,也有可能没有,根据设备驱动实际场景决定(中断底半步)。当中断顶半步&底半步全部执行完后,事实上RT任务还是得不到运行的,因为前面有一个普通任务拿了spinlock锁,spinlock是会关抢占的,所以还要等到普通任务调用到spin_unlock的那一刻,RT任务才能进行抢占。

    由上面例子可以看出,从唤醒RT任务到RT任务被执行,这段时间是不可预期的,所以通常linux不是一个硬实时的系统。

    如何让linux变成一个硬实时操作系统呢?首先要知道什么是实时操作系统,实时操作系统的重要特性就是系统中的实时任务,要在一个可预期的时间范围内必须得到执行。当一个高优先级任务被唤醒执行,或主动执行时,他必须可以立即抢占其他任务,得到cpu的执行权,这段时间必须是可预期的。像我们所熟知的vxworks实时系统,可以做到10ns以内可预期。

    我们的linux内核属于宏内核,和vxworks微内核设计思想不一样,linux大量用在服务器、嵌入式领域。服务器更追求的是高密度计算,系统吞吐能力。很多产品、工程场景,并不要求有多么精准的实时性。
     

    实时性优化思路

    实时性就是指能够在规定的时间内已足够快的速度予以处理,这要求操作系统能够及时的响应各种中断事件。并且在调度算法上要求中断处理进程能够得到及时的调度。以此来保证事件的处理。 在虚拟化场景中涉及操作系统有两个。Hypervisor操作系统和Guest操作系统。Hyperviosr操作系统中主要跑vcpu的进程,硬件中断处理程序,以及管理程序等等。为了提高实时性需要修改Hyperviosr调度算法,进程锁,中断屏蔽等机制。在Guest操作系统中也需要使用实时操作系统来进行优化。同时,为了保证Guest的vcpu在Hypervisor上得到及时的调度,需要在Hyperviosr对vcpu进行隔离,物理cpu和vcpu进行绑定,减少vcpu调度到其他cpu上,保证cache命中率。

    实时KVM优化

    Hyperviosr侧的优化

    • 首先要将linux修改成实时系统。

      1. PREEMPT_RT

      PREEMPT_RT是针对kernel进行修改,使得kernel成为实时操作系统的patch。它主要优化了spinlocks,interrrupts等,减少了不能够相应中断的操作。

      相应可以在这里找到https://rt.wiki.kernel.org/index.php/Main_Page

              然后调整内核参数,以满足实时性的要求。

    几乎每一个潜在的系统因素都来自于内核。比如,某个驱动程序可能会关闭中断而阻断高优先级的程序的调度。非实时内核中的自旋锁也是另外一个潜在的原因,因为 linux 在持有自旋锁的同时不能进行 schedule() 调度。这些问题可以通过运行 PREEMPT_RT(实时内核补丁集)构建的内核控制。除了临界区代码,一个 PREEMPT_RT 内核致力于使 linux 的每一部分都是可抢占的。

    1. cpu隔离/cpu绑定

    在kernel启动时候通过isolcups进行cpu隔离,使得Hyperviso上的控制程序跑在其他cpu中,隔离出来的cpu主要给Guest使用。然后在创建虚拟机的时候同时使用cpu绑定技术,将Guest的cpu绑定到被隔离的cpu上。

    1. 减少cpu中断

    nohz_full 提供一种动态的无时钟设置,在内核”CONFIG_NO_HZ_FULL=y”的前提下,指定哪些CPU核心可以进入完全无滴答状态。配置了CONFIG_NO_HZ_FULL=y后,当cpu上只有一个任务在跑的时候,不发送调度时钟中断到此cpu也就是减少调度时钟中断,不中断空闲CPU,从而可以减少耗电量和减少系统抖动。默认情况下所有的cpu都不会进入这种模式,需要通过nohz_full参数指定那些cpu进入这种模式。

    rcu_nocbs 当cpu有RCU callbacks pending的时候,nohz_full设置可能不会生效,使用rcu_nocbs来指定cpu进行卸载RCU callback processing

    mce=off 彻底禁用MCE(Machine Check Exception)。MCE是用来报告主机硬件相关问题的一种日志机制.

    1. 强制cpu进入高性能状态

    idle=poll 从根本上禁用休眠功能(也就是禁止进入C-states状态)

    intel_pstate=disable禁用 Intel CPU 的 P-state 驱动(CONFIG_X86_INTEL_PSTATE),也就是Intel CPU专用的频率调节器驱动P-state表明处理器处于省电模式但仍旧在执行一些工作。

    processor.max_cstate 无视ACPI表报告的值,强制指定CPU的最大C-state值(必须是一个有效值):C0为正常状态,其他则为不同的省电模式(数字越大表示CPU休眠的程度越深/越省电)。

    tsc=reliable 表示TSC时钟源是绝对稳定的,关闭启动时和运行时的稳定性检查。

    具体参数见如下设置

      isolcpus=1-4 nohz_full=1-4 rcu_nocbs=1-4 mce=off idle=poll intel_pstate=disable processor.max_cstate=1 pcie_asmp=off tsc=reliable
    • 关闭Hypervisor侧影响性能的程序

      1. 关闭内存交换
       swapoff -a
    1. 关闭ksm
       echo 0 > /sys/kernel/mm/ksm/merge_across_nodes
    echo 0 > /sys/kernel/mm/ksm/run
    1. 关闭看门狗
      echo 0 > /proc/sys/kernel/watchdog
    echo 0 > /proc/sys/kernel/nmi_watchdog
    1. 调整隔离cpu上的ksoftirqd和rcuc的优先级
      host_isolcpus="1-4"
    startVal=$(echo ${host_isolcpus} | cut -f1 -d-)
    endVal=$(echo ${host_isolcpus} | cut -f2 -d-)
    i=0
    while [ ${startVal} -le ${endVal} ]; do
    tid=`pgrep -a ksoftirq | grep "ksoftirqd/${startVal}$" | cut -d ' ' -f 1`
    chrt -fp 2 ${tid}

    tid=`pgrep -a rcuc | grep "rcuc/${startVal}$" | cut -d ' ' -f 1`
    chrt -fp 3 ${tid}

    cpu[$i]=${startVal}
    i=`expr $i + 1`
    startVal=`expr $startVal + 1`
    done
    1. 禁止带宽限制
       echo -1 > /proc/sys/kernel/sched_rt_period_us
    echo -1 > /proc/sys/kernel/sched_rt_runtime_us

    6.设置中断亲和性 将中断都设置到0号cpu上。

      for irq in /proc/irq/* ; do
    echo 0 > ${irq}/smp_affinity_list
    done

    虚拟机的启动设置

    • 将vcpu绑定都内核隔离出来的物理cpu中
        <cputune>
    <vcpupin vcpu="0" cpuset="1"/>
    <vcpupin vcpu="1" cpuset="2"/>
    <vcpupin vcpu="2" cpuset="3"/>
    <vcpupin vcpu="3" cpuset="4"/>
    </cputune>
    • 禁用kvmclock 使用tsc
       <clock offset='utc'>
    <timer name='kvmclock' present='no'/>
    </clock>

    虚拟机内部优化

    • 启动项优化
    isolcpus=3 nohz_full=3 rcu_nocbs=3  mce=off idle=poll
    • 虚拟机内部其他优化
     swapoff -a
    echo 0 > /sys/kernel/mm/ksm/merge_across_nodes
    echo 0 > /sys/kernel/mm/ksm/run
    echo 0 > /proc/sys/kernel/watchdog
    echo 0 > /proc/sys/kernel/nmi_watchdog
    echo -1 > /proc/sys/kernel/sched_rt_period_us
    echo -1 > /proc/sys/kernel/sched_rt_runtime_us
    • 禁止时钟迁移
    echo 0 > /proc/sys/kernel/timer_migration

    实时性测试

    对于实时性的测试,采用的是cyclictest。 在10分钟内测试下cpu的实时性。具体命令如下

    cyclictest -m -n -p95 -h60 -i200 -D 10m

    测试结果 优化前

    # /dev/cpu_dma_latency set to 0us
    policy: fifo: loadavg: 0.00 0.01 0.03 1/129 2407

    T: 0 ( 2404) P:95 I:200 C:2999375 Min: 5 Act: 22 Avg: 16 Max: 1475

    优化后

    # /dev/cpu_dma_latency set to 0us
    policy: fifo: loadavg: 0.00 0.01 0.01 1/152 2441

    T: 0 ( 2440) P:95 I:200 C:2999967 Min: 6 Act:7 Avg:7 Max: 12

    可以看到优化前在实时性方面原始的KVM还是会出现毛刺。在优化后基本上能达到很好的结果。

  • 相关阅读:
    汪博士解读PMP考试
    ASP.NET编程实战宝典(光盘内容另行下载,地址见书封底)
    [模板]tarjan算法求SCC
    [POJ 3071]Football[概率DP]
    [数学]根式有理化[高中数学技巧]
    [平面几何]角格点问题
    [数学]对数均值不等式
    [模板][快速排序&归并排序]
    [POJ]P3126 Prime Path[BFS]
    每日一题_191219
  • 原文地址:https://www.cnblogs.com/dream397/p/14580714.html
Copyright © 2020-2023  润新知