查看原文
其他

访问本机 Server,使用 127.0.0.1 能比 192.168.x 更快吗?

IT服务圈儿 2022-09-11

The following article is from 架构技术漫谈 Author 张彦飞allen


来源丨经授权转自 架构技术漫谈(ID:gh_f115c9e21b4c)

作者 | 张彦飞allen

思考题:访问本机 Server 时,使用 127.0.0.1 能比使用本机 ip(例如192.168.x.x) 更快吗?

飞哥的结论是,这两种使用方法在性能上没有啥差别。

一、相关源码分析

第一: 所有 local 路由表项内核都会标识为 RTN_LOCAL。

前面文章里可以看到选用哪个设备是在网络层里路由选择的时候决定的,函数是 __ip_route_output_key。

//file: net/ipv4/route.c
struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
{

 if (fib_lookup(net, fl4, &res)) {
 }
 if (res.type == RTN_LOCAL) {
  dev_out = net->loopback_dev;
  ...
 }

 rth = __mkroute_output(&res, fl4, orig_oif, dev_out, flags);
 return rth;
}

这里会查询到 local 路由表。

# ip route list table local
local 10.162.*.* dev eth0  proto kernel  scope host  src 10.162.*.*
local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1

很多人在看到这个路由表的时候就被它给迷惑了,以为上面 10.162.. 真的会被路由到 eth0。而其实内核在初始化 local 路由表的时候,把 local 路由表里所有的路由项都设置成了 RTN_LOCAL。这个过程是在设置本机 ip 的时候,调用 fib_inetaddr_event 函数完成设置的。

static int fib_inetaddr_event(struct notifier_block *this, 
 unsigned long event, void *ptr)
{
 switch (event) {
 case NETDEV_UP:
  fib_add_ifaddr(ifa);
  break;
 case NETDEV_DOWN:
  fib_del_ifaddr(ifa, NULL);
//file:ipv4/fib_frontend.c
void fib_add_ifaddr(struct in_ifaddr *ifa)
{
 fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
}

第二: 所有 RTN_LOCAL 类型的路由表都会选择到 loopback 虚拟设备。

来看网络层的这段源码。

//file: net/ipv4/route.c
struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
{

 if (fib_lookup(net, fl4, &res)) {
 }
 if (res.type == RTN_LOCAL) {
  dev_out = net->loopback_dev;
  ...
 }

 rth = __mkroute_output(&res, fl4, orig_oif, dev_out, flags);
 return rth;
}

所以即使本机 IP,不用 127.0.0.1,内核在路由项查找的时候仍然会使用 net->loopback_dev。也就是 lo 虚拟网卡。

二、实践验证

为了稳妥起见,飞哥再抓包确认一下。开启两个控制台窗口,一个对 lo 设备进行抓包。因为局域网内会有大量的网络请求,为了方便过滤,这里使用一个特殊的端口号 8888。如果这个端口号在你的机器上占用了,那需要再换一个。

#tcpdump -i eth0 port 8888

另外一个窗口使用 telnet 对本机 IP 端口发出几条网络请求。

#telnet 10.162.*.* 8888
Trying 10.162.*.*...
telnet: connect to address 10.162.*.*: Connection refused

这时候切回第一个控制台,发现啥反应都没有。说明包根本就没有过 eth0 这个设备。

再把设备换成 lo 再抓。当 telnet 发出网络请求以后,在 tcpdump 所在的窗口下看到了抓包结果。

# tcpdump -i lo port 8888
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
08:22:31.956702 IP 10.162.*.*.62705 > 10.162.*.*.ddi-tcp-1: Flags [S], seq 678725385, win 43690, options [mss 65495,nop,wscale 8], length 0
08:22:31.956720 IP 10.162.*.*.ddi-tcp-1 > 10.162.*.*.62705: Flags [R.], seq 0, ack 678725386, win 0, length 0

总结

我觉得有相当大一部分人都会认为访问本机 Server 的话,用 127.0.0.1 更快。原因是直觉上认为访问 IP 就会经过网卡。

其实内核知道本机上所有的 IP,只要发现目的地址是本机 IP 就可以全走 loopback 回环设备了。本机其它 IP 和 127.0.0.1 一样,也是不用过物理网卡的,所以访问它们性能开销基本一样!


1、数据中台与传统大数据平台有什么区别?终于有人讲明白了

2、Python对比VBA实现excel表格合并与拆分

3、年轻人开始“反算法”

4、萌新第一次用鸿蒙跑hello world

识别关注我们

了解更多精彩内容

点分享

点点赞

点在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存