php一次请求redis会有哪些开销你没深入了解过吧

2020-11-30 08:31 PHP自学中心


精选文章正文

视频教程推荐:【TP5.1+redis实现大型电商网站订单消息推送功能

公众号里回复:897583   免费领取提取码!



问大家一个问题,下图中一个最简单的例子,会导致哪些CPU开销产生?你是否能够说清楚?

<?php
  ...
  $redis->get('test');
  ...


这个例子一下子就把大家在我的文章里学到的东西和你的实际工作结合起来了。怎么样,是不是足够简单?就是一句php代码从redis实例中获取一个key的value值而已,相信类似的代码你天天都在写。对这句redis get实际开销的理解水平,就代表了你的内功的深度。


如果你只是一个初级或者中级开发工程师,这些确实没有必要了解。但是如果你想成为一名高级、或者是资深开发工程师,那么你应该具备大致估算你手下写出的每一行代码开销的能力,要对自己代码在线上的运行开销负责!


1
测试准备

接下来,我们就来带大家从更深层次的方向认识到这句简单代码的开销。为了便于测试,我们对代码进行一些简单的改造,最终的实际测试文件如下

<?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里获取了一条数据而已。那么让我们看看它到底会产生哪些开销?


2
系统调用开销

我们使用strace命令来查看

# 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操作都需要执行多次系统调用才可完成。

3
进程上下文切换开销

每次次调用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密集型的应用里自愿上下文切换要比时间片到了被动切换要多的多!

4
软中断开销

每次在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请求收到数据返回的时候,内核必须要支出一次软中断的开销!

5
总结

看似一次非常简单的redis get操作就会把所有系统态的高开销操作都涉及到了。一次进程上下文切换、一次软中断、若干次系统调用。其实除了上面这些容易评估到的开销外,还有如L1、L2 cache miss,以及TLB cache miss这些在进程被切换掉都会造成cache命中率下降,也会导致额外开销。所以,你以为的简单,其实不一定简单!




以上是本文的全部内容,希望对大家的学习有帮助,也希望大家多多支持 php自学中心 ,学习与交流少不了一个圈子,点击加技术群:PHP自学中心交流②群



本文章转载自公众号:phpCenter

首页 - PHP 相关的更多文章: