vm中linux自动连网_Linux VM中的计时介绍

vm中linux自动连网

在Linux上保持时间并不简单,虚拟化增加了其他挑战和机遇。 在本文中,我将回顾与KVM,Xen和Hyper-V相关的计时技术以及Linux内核的相应部分。

计时是记录某物花费多长时间的过程或活动。 我们需要“仪器”来测量时间。 Linux内核有几种抽象来表示此类设备:

  • Clocksource是一种可以在需要时提供时间戳的设备。 换句话说,Clocksource是允许您获得其价值的任何滴答计数器。
  • Clockevent设备是一个闹钟-您要求该设备发出将来某个时间的信号(例如,“在1毫秒内唤醒我”),并且在触发警报时,您会收到信号。
  • sched_clock()函数与clocksource类似,但该特定读物应“便宜”(意味着可以快速获得其值),因为sched_clock()用于任务调度,并且调度经常发生。 我们准备牺牲精度和其他特性来提高速度。

假设您正在编写一个应用程序,例如,您需要获取当前时间来进行时间戳记。 您可能会想到这样的事情:



   
   
#include <stdio.h>
#include <time.h>

int timestamp_function(...)
{
        struct timespec tp;
        int res = clock_gettime(CLOCK_REALTIME, &tp);

     … do something with the timestamp …
}

什么是CLOCK_REALTIME ?我们还有什么其他时钟? 男人2 clock_gettime给出了答案:

  • CLOCK_REALTIME时钟提供自1970年1月1日以来经过的时间。该时钟受NTP调整的影响,当系统管理员调整系统时间时,它可以向前和向后跳转。
  • CLOCK_MONOTONIC时钟提供从固定起点(通常是从引导系统开始)开始的时间。 此时钟受NTP影响,但不能向后跳。
  • CLOCK_MONOTONIC_RAW时钟与CLOCK_MONOTONIC的时间相同,但是此时钟不受NTP调整的影响。
  • CLOCK_REALTIME_COARSECLOCK_MONOTONIC_COARSE是更快但精度不高的CLOCK_REALTIMECLOCK_MONOTONIC的变体。

还有其他几个与正在运行的进程或线程相关的时钟,但让我们暂时跳过它们。

一些应用程序经常打时间戳,每秒打数千次,对于这些应用程序,我们必须确保clock_gettime()速度很快。 在Linux中如何运作? 该算法是:

  1. 从vDSO(虚拟动态共享对象)中调用clock_gettime( )。 vDSO是内核提供给每个应用程序的共享库,它包含可以从用户空间运行而无需切换到内核的代码。
  2. 对于CLOCK_REALTIME_COARSECLOCK_MONOTONIC_COARSE ,通过读取适当的timekeeper结构(内核提供给用户空间以仅供读取)给出即时答案。
  3. 对于CLOCK_REALTIMECLOCK_MONOTONIC ,检查是否可以从用户空间读取当前正在使用的时钟源,如果可以,则使用其读取值推断适当的计时器值。
  4. 如果无法从用户空间读取正在使用的时钟源,请通过执行系统调用切换到内核,并让内核读取当前时钟源并外推适当的计时器值。

直接从用户空间读取时钟源时的vDSO优化很重要。 这是我对一亿个clock_gettime()读取的测试程序的测试结果。 这些测试是在启用和未启用vDSO优化的情况下,在KVM guest虚拟机上执行的:



   
   
kvmclock without vDSO:
# time ./clock_gettime_many

real    0m15.606s
user    0m2.684s
sys     0m12.916s

kvmclock with vDSO:
# time ./clock_gettime_many

real    0m2.365s
user    0m2.362s
sys     0m0.001s

纯用户空间方法比执行系统调用快七倍。 我们绝对想要这个。 但是,什么使时钟源适合于这种快速读取呢?

时钟源

通常,我们要求时钟源:

  • 永不退步。
  • 永不止步。
  • 避免“跳”。
  • 具有良好的分辨率(频率)。
  • 快速阅读。
  • 可用于用户空间代码。

PC硬件具有许多传统的计时设备,但是它们缺乏上述特征。 即:

  • PIT :仅适用于计数抖动(系统计时器中断); 低解析度。
  • CMOS RTC :低分辨率(1s)时钟,可选32768Hz定时器; 无法从用户空间读取。
  • ACPI(PM)计时器 :频繁溢出; 读起来慢 无法从用户空间访问。
  • HPET :并不总是存在; 不一定快速阅读。
  • LAPIC计时器 :未知频率; 无法从用户空间读取。

所有现代的x86虚拟机管理程序都对该硬件进行了虚拟化,但是所有访问的虚拟化成本都很高,以致于无法将这些设备中的任何一个用作Linux中的可靠时钟源。

TSC

在裸露的x86硬件上,当今最常用的时钟源是TSC(时间戳计数器)。 TSC是一种特殊的自动递增CPU寄存器,与使用前面提到的旧式硬件相比,它具有许多优点。 它具有很高的精度,甚至可以从用户空间使用一条汇编指令( rdtsc )读取。 TSC有其自身的问题,包括:

  • 其频率未知,需要使用PIT,CMOS或ACPI计时器进行测量。
  • 该寄存器是可写的,并且在不同的CPU上读数可能有所不同。
  • TSC可以在处理器的某些低功耗C状态下停止。 在现代硬件上通常不会发生这种情况。
  • 过去曾观察到TSC在某些大型NUMA系统上不同步。 幸运的是,这种系统的数量是有限的。
  • SMI处理程序可能会重置计数器。

虚拟化带来了其他挑战。 当虚拟机迁移到另一个主机时,其TSC值会有所不同,因此我们看到该值出现“跳跃”。 而且,我们在启动时测量的频率不再是实际的TSC频率。 引入了两种类似的方法来解决这些问题:用于Xen和KVM虚拟机管理程序guest虚拟机的pvclock (半虚拟时钟)和用于Hyper-V客户机的TSC页面 。 这些是固定频率的时钟,因此除了读取TSC值外,我们还需要做一些数学运算才能获得读数。

时钟

Xen和KVM虚拟机管理程序提出了所谓的pvclock协议,以增强TSC并使其适用于虚拟访客。 该协议基于主机和来宾之间共享的简单的每CPU结构:



   
   
struct pvclock_vcpu_time_info {
        u32   version;
        u32   pad0;
        u64   tsc_timestamp;
        u64   system_time;
        u32   tsc_to_system_mul;
        s8    tsc_shift;
        u8    flags;
        u8    pad[2];
};

要获取当前的TSC读数,客人必须执行以下数学运算:


PerCPUTime =  ((RDTSC() - tsc_timestamp) >> tsc_shift) * tsc_to_system_mul + system_time

标志字段指示即使我们在不同的CPU上进行后续调用时,是否也可以信任读数以保持单调性承诺,并且这确定了我们使用vDSO时钟源的能力。 如果不能保证单调性,Linux需要跟踪最后一次读取,以确保即使从一个CPU迁移到另一个CPU,也没有应用程序会看到时间倒退。 幸运的是,在现代硬件上这种情况很少发生,而且我们的阅读速度很快。

Hyper-V TSC页面

Microsoft用自己的TSC页面 Proctol重新发明了pv_clock协议,该协议类似于pv_clock,但有很大的不同。 TSC页面是每个虚拟机(而不是每个CPU)的单一结构,因此它无法补偿TSC在多个CPU上不同步的情况。 我们不确定,但是猜测是在这种情况下,管理程序将尝试同步TSC或完全禁用TSC页面机制。

TSC页面的协议为:



   
   
struct ms_hyperv_tsc_page {
        volatile u32 tsc_sequence;
        u32 reserved1;
        volatile u64 tsc_scale;
        volatile s64 tsc_offset;
        u64 reserved2[509];
};

要获取当前的TSC读数,客人必须执行以下数学运算:


PerVMTime = ((VirtualTsc * tsc_scale) >> 64) + tsc_offset

tsc_sequence字段中的特殊值0表示该方法已禁用,我们应该回过头来从Hyper-V提供的另一个虚拟MSR(特定于模型的寄存器)中读取值。 这从用户空间代码中是不可能的,并且通常要慢得多。

用于虚拟化TSC的硬件扩展

自从硬件辅助虚拟化的早期以来,英特尔就提供了对硬件中的虚拟来宾进行TSC偏移的选项,这意味着来宾的rdtsc读数将返回主机的TSC值+偏移。 不幸的是,这还不足以支持不同主机之间的迁移,因为TSC频率可能不同,因此引入了pvclockTSC页面协议。 在2015年末,英特尔推出了TSC缩放功能(该功能已经在AMD处理器中使用了几年),从理论上讲,这是一个改变游戏规则的功能,使pvclockTSC页面协议变得多余。 但是,立即转换为将普通TSC用作虚拟化来宾的时钟源似乎是不切实际的。 必须确保所有潜在的迁移接收者主机都支持该功能,但是该功能尚未广泛使用。 还必须进行广泛的测试,以确保从半虚拟化协议切换不会有任何缺点。

主机范围的时间同步

因此,我们正在KVM上运行虚拟化来宾,并使用kvmclock (实现了pvclock协议),或者我们正在运行Hyper-V来宾并将Hyper-V TSC页面用作时钟源。 访客和主机之间(或同一主机上的不同访客之间)我们的时间是否同步? 我们正在读取相同的TSC值,因此生成的时间应该相同,对吗? 好吧,不完全是。 主机和来宾的CLOCK_REALTIME时钟均受NTP调整的影响,并且可能会随时间变化。

为了解决该问题,在Linux-4.11中引入了一种解决方案:用于KVM和Hyper-V的PTP设备。 这些设备实际上与PTP时间同步协议无关,并且不能与网络设备一起使用,但是它们将自身显示为PTP( / dev / ptp * )设备,因此它们可以由现有的时间同步软件使用。

要启用与主机的时间同步,我们必须执行以下操作:

  1. 对于KVM guest 虚拟机 ,我们需要加载ptp_kvm模块。 要使其在重新启动后加载,我们可以执行以下操作:
    
    # echo ptp_kvm > /etc/modules-load.d/ptp_kvm.conf 
    (在Fedora / RHEL7上)。 Hyper-V guest虚拟机不需要此功能,因为实现设备的模块会自动加载。
  2. / dev / ptp0作为参考时钟添加到NTP守护程序配置中。 如果是时效性,它将是:
    
    # echo "refclock PHC /dev/ptp0 poll 3 dpoll -2 offset 0" >> /etc/chrony.conf
    
  3. 重启NTP服务器:
    
    systemctl restart chronyd
    
  4. 检查时间同步状态:
    
    # chronyc sources | grep PHC0
    

众所周知,KVM guest虚拟机比Hyper-V guest虚拟机产生更好的结果,因为设备背后的机制非常不同。 Hyper-V主机每五秒发送一次其来宾时间样本,而KVM来宾可以选择直接向系统管理程序进行超级调用以获取其时间。

在KVM(空闲主机,单客户机)上的测试结果:


# for f in `seq 1 5`; do chronyc sources | grep PHC0 ; sleep 10s; done
#* PHC0            0   3   377     4    -24ns[ -166ns] +/-   37ns
#* PHC0            0   3   377     6    +13ns[  +49ns] +/-   32ns
#* PHC0            0   3   377     8    +49ns[ +182ns] +/-   28ns
#* PHC0            0   3   377    11    -43ns[ -113ns] +/-   24ns
#* PHC0            0   3   377     4    +60ns[ +152ns] +/-   18ns
 

在Hyper-V(空闲主机,单访客)上的测试结果:


# for f in `seq 1 5`; do chronyc sources | grep PHC0 ; sleep 10s; done
#* PHC0            0   3   377     7   +287ns[+2659ns] +/-  131ns
#* PHC0            0   3   377     7   +119ns[-3852ns] +/-  130ns
#* PHC0            0   3   377     9  +1648ns[+2449ns] +/-  156ns
#* PHC0            0   3   377     5   +898ns[ +613ns] +/-  142ns
#* PHC0            0   3   377     7   +288ns[ -403ns] +/-   98ns
 

尽管Hyper-V PTP设备的准确性不如KVM,但与NTP相比仍然非常准确。 从上面可以看到,访客的系统时间通常与主机的时间保持在10us之内,这是一个很好的结果。

Vitaly Kuznetsov将于2017年6月20日在北京举行的 LinuxCon ContainerCon CloudOpen China上讨论Linux VM的计时问题

翻译自: https://opensource.com/article/17/6/timekeeping-linux-vms

vm中linux自动连网

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值