本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2024-11(1)

一次简单的redis网络请求会有哪些CPU开销?

发布于2021-03-14 05:42     阅读(822)     评论(0)     点赞(30)     收藏(5)


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

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

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

在前面的文章中介绍了一些和CPU相关的硬件、内核知识,把开销大户进程上下文切换、系统调用、软中断的具体开销都挨个分析了一遍。没有看过的同学请关注并翻看我以前的文章。不过,这时候我觉得有很多开发同学都有一个疑惑,仍然是觉得:“我是应用层的开发,这么底层的开销和我有什么关系?” 或者是说:“线上服务器的运维不都应该是运维的工作吗?和开发又没关系”

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

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

<?php  
	$redis = new Redis();  
	$redis->connect({某Redis server的IP}, 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命中率下降,也会导致额外开销。

所以,你以为的简单,其实不一定简单!


file


开发内功修炼之CPU篇专辑:


我的公众号是「开发内功修炼」,在这里我不是单纯介绍技术理论,也不只介绍实践经验。而是把理论与实践结合起来,用实践加深对理论的理解、用理论提高你的技术实践能力。欢迎你来关注我的公众号,也请分享给你的好友~~~

原文链接:https://www.cnblogs.com/kfngxl/p/13910801.html



所属网站分类: 技术文章 > 博客

作者:肚子里的大哥

链接:http://www.phpheidong.com/blog/article/3039/a82a3962be6de4e102c6/

来源:php黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

30 0
收藏该文
已收藏

评论内容:(最多支持255个字符)