是的,我的旧笔记本电脑的功能是生产服务器的几倍

这些是我从开发人员那里听到的主张。最有趣的是,事实证明这是事实,这导致了冗长的调查。这将与在我们的VMware上旋转的SQL服务器有关。



实际上,确保生产服务器毫无希望地落后于笔记本电脑很容易。运行代码(不是在tempdb上,也不在启用了Delayed Durability的基础上)运行代码:

set nocount on
create table _t (v varchar(100))
declare @n int=300000
while @n>0 begin 
  insert into _t select 'What a slowpoke!'
  delete from _t
  set @n=@n-1
  end
GO
drop table _t

在我的桌面上,它运行5秒钟,在生产服务器上-28秒。因为SQL必须等待事务日志条目的物理结束,所以在这里我们正在做非常短的事务。粗略地讲,我们将一辆强大的大卡车驶入城市交通,我们看到踏板车上的披萨送货员如何超越了卡车-吞吐量在这里并不重要,只有延迟很重要。而且,无论价格是多少零,都没有一个网络存储能够赢得本地SSD的延迟。

(在评论中,我撒谎了-我在两个地方都延迟了耐久性。事实证明,如果没有延迟耐久性,则是:
台式机-39秒,15K tr /秒,0.065ms / io往返
PROD-360秒,1600 tr /秒,0.6ms
我应该早点注意了)


但是,在这种情况下,我们用一个平凡的例子来处理zeta Riemann函数平凡零。在开发人员带给我的示例中,还有另一个。我确信它们是正确的,并从示例中清除了所有与业务逻辑有关的细节。在某个时候,我意识到我可以完全扔掉他们的代码,并编写自己的代码-证明了同样的问题-它在生产上的运行速度慢了3-4倍:

create function dbo.isPrime (@n bigint)
returns int
as
  begin
  if @n = 1 return 0
  if @n = 2 return 1
  if @n = 3 return 1
  if @n % 2 = 0 return 0
  declare @sq int
  set @sq = sqrt(@n)+1 -- check odds up to sqrt
  declare @dv int = 1
  while @dv < @sq 
    begin
	set @dv=@dv+2
	if @n % @dv = 0 return 0
	end
  return 1
  end
GO
declare @dt datetime set @dt=getdate()
select dbo.isPrime(1000000000000037)
select datediff(ms,@dt,getdate()) as ms
GO

如果一切正常,那么将在6-7-8秒内进行数字简单性的验证。因此它在许多服务器上。但是在某些情况下,检查需要25-40秒。有趣的是,没有服务器执行需要花费14秒的时间-代码运行得非常快或非常慢,也就是说,问题是黑白的。

我做了什么?在VMware指标中有用。那里一切都很好-资源充足,就绪时间= 0,在一个vCPU上快速和慢速服务器上的CPU = 100的测试期间,一切都足够。我进行了一次测试以计算Pi的数量-该测试在任何服务器上都显示了相同的结果。越来越闻到黑魔法了。

走出DEV农场后,我开始扮演服务器的角色。事实证明,主机之间的vMotion可以“治愈”服务器,但反之亦然,可以将“快速”服务器转变为“慢速”服务器。看起来像这样-一些主机有问题...但是...不。某个虚拟机在主机上运行缓慢,例如A,但是在主机B上运行很快。相反,另一台虚拟机在A上运行很快,在B上运行慢! “快”和“慢”的汽车经常在主人身上旋转!

从那一刻起,空气中明显散发出硫磺味。毕竟,该问题不能归因于任何虚拟机(例如Windows补丁程序)-因为通过vMotion它变成了“快速”虚拟机。但是问题也不能归因于主机-因为它可能同时具有“快速”和“慢速”计算机。它也没有与负载连接-我设法在主机上获得一台“慢速”计算机,除此之外,它什么也没有。

绝望的是,我从Sysinternals启动了Process Explorer,并查看了SQL堆栈。在速度较慢的计算机上,这条线立即引起了我的注意:

ntoskrnl.exe!KeSynchronizeExecution + 0x5bf6
ntoskrnl.exe!KeWaitForMultipleObjects + 0x109d
ntoskrnl.exe!KeWaitForMultipleObjects + 0xb3f
ntosKrnx3 0!
ntoskrnl.exe!KeQuerySystemTimePrecise + 0x881 <-!!!
ntoskrnl.exe中!ObDereferenceObjectDeferDelete + 0x28a
ntoskrnl.exe中!KeSynchronizeExecution函数+ 0x2de2
sqllang.dll!CDiagThreadSafe :: PxlvlReplace + 0x1a20
...跳过
sqldk.dll!SystemThread :: MakeMiniSOSThread + 0xa54
KERNEL32.DLL!BaseThreadInitThunk + 0×14
ntdll.dll中!RtlUserThreadStart + 0×21


已经是东西了。该程序是这样写的:

    class Program
    {
        [DllImport("kernel32.dll")]
        static extern void GetSystemTimePreciseAsFileTime(out FILE_TIME lpSystemTimeAsFileTime);

        [StructLayout(LayoutKind.Sequential)]
        struct FILE_TIME
        {
            public int ftTimeLow;
            public int ftTimeHigh;
        }

        static void Main(string[] args)
        {
            for (int i = 0; i < 16; i++)
            {
                int counter = 0;

                var stopwatch = Stopwatch.StartNew();

                while (stopwatch.ElapsedMilliseconds < 1000)
                {
                    GetSystemTimePreciseAsFileTime(out var fileTime);
                    counter++;
                }

                if (i > 0)
                {
                    Console.WriteLine("{0}", counter);
                }
            }
        }
    }

该程序显示出更快的减速效果-在“快速”机器上,每秒显示16-18百万个周期,而在慢速机器上,每秒显示50万个,甚至70万个。也就是说,相差是10到20倍(!!!)。这已经是一个小小的胜利:在任何情况下,Microsoft和VMware支持之间都不会卡住,这样他们就可以相互转移箭头。

此外,进展停止了-休假,重要事项,病毒性歇斯底里和工作量急剧增加。我经常向同事提一个魔术问题,但有时似乎他们并不总是信任我-VMware将代码速度降低10到20倍的说法太可怕了。

我试图发掘出正在减速的东西。在我看来,有时我发现了一个解决方案-打开和关闭热插拔,更改内存大小或处理器数量通常使计算机成为“快速”处理器。但不是永远。但是事实证明是正确的,那就是外出敲门,就是改变虚拟机的任何参数,

最后,我的美国同事突然发现了根本原因。



主持人的频率有所不同!
  • 这通常并不可怕。但是:从“本地”主机迁移到“不同”频率的主机时,VMware应该调整GetTimePrecise的结果。
  • 通常,这并不可怕,除非有像SQL Server这样的应用程序每秒请求确切的时间数百万次。
  • 但这并不可怕,因为SQL Server并不总是这样做(请参见结论)。

但是在某些情况下,这种耙子很难击中。但是,是的,通过轻按方向键(在VM设置中进行了更改),我迫使VMware“重新计算”配置,当前主机的频率变为计算机的“本机”频率。

决断


www.vmware.com/files/pdf/techpaper/Timekeeping-In-VirtualMachines.pdf

When you disable virtualization of the TSC, reading the TSC from within the virtual machine returns the physical machine’s TSC value, and writing the TSC from within the virtual machine has no effect. Migrating the virtual machine to another host, resuming it from suspended state, or reverting to a snapshot causes the TSC to jump discontinuously. Some guest operating systems fail to boot, or exhibit other timekeeping problems, when TSC virtualization is disabled. In the past, this feature has sometimes been recommended to improve performance of applications that read the TSC frequently, but performance of the virtual TSC has been improved substantially in current products. The feature has also been recommended for use when performing measurements that require a precise source of real time in the virtual machine.

简而言之,添加参数

monitor_control.virtual_rdtsc = FALSE

结论


您可能有一个问题:SQL经常调用GetTimePrecise吗?

我没有SQL Server源,但是逻辑如此。 SQL几乎是具有协同并发性的OS,每个线程都必须不时地让位。在哪里更好呢?自然而然的期望-锁定或IO。好吧,如果我们旋转计算周期该怎么办?然后,执行下一个运算符之后,显而易见的几乎是唯一的位置是解释器(这不是完全的解释器)。

作为一项规则,SQL服务器不用于打钉干净的计算,这是没有问题的。但是,使用各种临时平板电脑(立即被缓存)的循环会将代码转换成一系列非常快速执行的语句。

顺便说一句,如果将函数包装为NATIVELY COMPILED,则它不再要求时间,并且其速度增加了10倍。但是,协作多任务处理又如何呢?但是对于本地编译的代码,我不得不在SQL中进行PREEMPTIVE MULTITASKING。

All Articles