<?php ... $redis->get('test'); ...
这个例子一下子就把大家在我的文章里学到的东西和你的实际事情结合起来了。怎么样,是不是足够大略?便是一句php代码从redis实例中获取一个key的value值而已,相信类似的代码你每天都在写。对这句redis get实际开销的理解水平,就代表了你的内功的深度。
在前面的文章中先容了一些和CPU干系的硬件、内核知识,把开销大户进程高下文切换、系统调用、软中断的详细开销都挨个剖析了一遍。没有看过的同学请关注并翻看我以前的文章。不过,这时候我以为有很多开拓同学都有一个迷惑,仍旧是以为:“我是运用层的开拓,这么底层的开销和我有什么关系?” 或者是说:“线上做事器的运维不都该当是运维的事情吗?和开拓又没紧要”
我想说的是,如果你只是一个低级或者中级开拓工程师,这些确实没有必要理解。但是如果你想成为一名高等、或者是资深开拓工程师,那么你该当具备大致估算你部下写出的每一行代码开销的能力,要对自己代码在线上的运行开销卖力!
接下来,我们就来带大家从更深层次的方向认识到这句大略代码的开销。为了便于测试,我们对代码进行一些大略的改造,终极的实际测试文件如下。测试代码见test07
<?php $redis = new Redis(); $redis->connect('10.153.55.119', 6339); sleep(60); echo \"大众Test begin\n\公众; for($i=0; $i<10000; $i++){ $redis->get('test'); } echo \公众Test end!\n \"大众; sleep(60);
例子非常的大略,便是一句后端同学代码里常常涌现的从Redis里获取了一条数据而已。那么让我们看看它到底会产生哪些开销?
1.系统调用
# strace -c php main.php % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 97.24 0.039698 1 30003 poll 2.20 0.000899 0 10003 sendto 0.30 0.000122 0 10000 recvfrom 0.13 0.000053 0 10069 gettimeofday 0.03 0.000013 2 6 socket 0.03 0.000012 0 408 munmap 0.02 0.000008 0 657 read
我们代码所调用的get函数,实在是php的一个redis扩展供应的。该扩展又会去调用Linux系统的网络库函数,库函数再去调用内核供应的系统调用。这个调用层次模型如下:
从实际测试结果可见,每次get操作都须要实行多次系统调用才可完成。
2、进程高下文切换
每次调用get后,如果数据没有返回。进程都是壅塞掉的,因此还会导致进程进入主动高下文切换。 我们用实验的办法来查看一下:
# php main.php
然后再另起一个掌握台,分别赶在实验开始前和实验开始后实行如下两行命令:
# grep ctxt /proc/14862/status voluntary_ctxt_switches: 4 nonvoluntary_ctxt_switches: 43 # grep ctxt /proc/14862/status voluntary_ctxt_switches: 10005 nonvoluntary_ctxt_switches: 49
每次get都会导致进程进入志愿高下文切换,在网络IO密集型的运用里志愿高下文切换要比韶光片到了被动切换要多的多!
3、软中断
每次在redis做事器返回数据的时候,网卡都会通过软中断的办法来让内核处理数据包。因此
# cat /proc/softirqs CPU0 CPU1 CPU2 CPU3 HI: 0 0 0 0 TIMER: 196173081 145428444 154228333 163317242 NET_TX: 0 0 0 0 NET_RX: 178159928 116073 10108 160712 # cat /proc/softirqs CPU0 CPU1 CPU2 CPU3 HI: 0 0 0 0 TIMER: 196173688 145428634 154228610 163317624 NET_TX: 0 0 0 0 NET_RX: 178170212 116073 10108 160712
该虚机的软中断亲和性在CPU0上,178170212-178159928 = 10284(多出来的284是机器上其它的小做事)。 每次get要求收到数据返回的时候,内核必须要支出一次软中断的开销!
总结
看似一次非常大略的redis get操作就会把所有系统态的高开销操作都涉及到了。一次进程高下文切换、一次软中断、多少次系统调用。在经由了前面多篇文章的历练,相信大家对它们的开销有了一个量化的拿捏。实在除了上面这些随意马虎评估到的开销外,还有如L1、L2 cache miss,以及TLB cache miss这些在进程被切换掉都会造成cache命中率低落,也会导致额外开销。
以是,你以为的大略,实在不一定大略!
欢迎关注个人"大众年夜众号“开拓内功修炼”,打通理论与实践的任督二脉!