专栏名称: Linux就该这么学
专注于Linux运维技术培训,让您学习的每节课都有所收获,订阅本号后可每天获得最新Linux运维行业资讯、最实用的Linux免费教程以及独家Linux考证资料,三十多万技术小伙伴的选择,Linux就该这么学!
目录
相关文章推荐
Linux就该这么学  ·  小米全球总部 “15元员工餐” ... ·  8 小时前  
Linux就该这么学  ·  耗时6个月,高中生 “自制” ... ·  昨天  
Linux就该这么学  ·  利用 Function 接口告别冗余(屎山)代码 ·  2 天前  
Linux就该这么学  ·  “十分”给力:Wine 10.0 ... ·  4 天前  
Linux就该这么学  ·  DeepSeek ... ·  5 天前  
51好读  ›  专栏  ›  Linux就该这么学

惊呆了!应用程序容器化后,性能真会下降这么多,如何破局?

Linux就该这么学  · 公众号  · linux  · 2025-02-02 08:02

正文

链接:https://juejin.cn/post/7268663683881828413

1.背景

随着越来越多的公司拥抱云原生,从原先的单体应用演变为微服务,应用的部署方式也从虚机变为容器化,容器编排组件 K8s 也成为大多数公司的标配。然而在容器化以后,我们发现应用的性能比原先在虚拟机上表现更差,这是为什么呢?

2. 压测结果

2.1 容器化之前的表现

应用部署在虚拟机下,我们使用 wrk 工具进行压测,压测结果如下:
从压测结果看,平均 RT 为 1.68 ms,qps 为 716/s,我们再来看下机器的资源使用情况,CPU 基本已经被打满。

2.2 容器化后的表现

使用 wrk 工具进行压测,结果如下:
从压测结果看,平均 RT 为 2.11 ms,qps 为 554/s,我们再来看下机器的资源使用情况,CPU 基本已经被打满。

2.3 性能对比结果

总体性能下降:RT(25%)、QPS(29%)。

3. 原因分析

3.1 架构差异

由于应用在容器化后整体架构的不同、访问路径的不同,将可能导致应用容器化后性能的下降,于是我们先来分析下两者架构的区别。我们使用 K8s 作为容器编排基础设施,网络插件使用 calico 的 ipip 模式,整体架构如下所示。
这里需要说明,虽然使用 calico 的 ipip 模式,由于 pod 的访问为 service 的 nodePort 模式,所以不会走 tunl0 网卡,而是从 eth0 经过 iptables 后,通过路由到 calico 的 calixxx 接口,最后到 pod。

3.2 性能分析

在上面压测结果的图中,我们容器化后,CPU 的软中断si使用率明显高于原先虚拟机的si使用率,所以我们使用 perf 继续分析下热点函数。
为了进一步验证是否是软中断的影响,我们使用perf进一步统计软中断的次数。
我们发现容器化后比原先软中断多了14%,到这里,我们能基本得出结论,应用容器化以后,需要更多的软中断的网络通信导致了性能的下降。

3.3 软中断原因

由于容器化后,容器和宿主机在不同的网络 namespace,数据需要在容器的 namespace 和 host namespace 之间相互通信,使得不同 namespace 的两个虚拟设备相互通信的一对设备为veth pair,可以使用ip link命令创建,对应上面架构图中红色框内的两个设备,也就是calico创建的calixxx和容器内的eth0。我们再来看下veth设备发送数据的过程:
static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev){... if (likely(veth_forward_skb(rcv, skb, rq, rcv_xdp)...}
static int veth_forward_skb(struct net_device *dev, struct sk_buff *skb, struct veth_rq *rq, bool xdp){ return __dev_forward_skb(dev, skb) ?: xdp ? veth_xdp_rx(rq, skb) : netif_rx(skb);//中断处理}
/* Called with irq disabled */static inline void ____napi_schedule(struct softnet_data *sd, struct napi_struct *napi){ list_add_tail(&napi->poll_list, &sd->poll_list); //发起软中断 __raise_softirq_irqoff(NET_RX_SOFTIRQ);}
通过虚拟的 veth 发送数据和真实的物理接口没有区别,都需要完整的走一遍内核协议栈,从代码分析调用链路为veth_xmit -> veth_forward_skb -> netif_rx -> __raise_softirq_irqoff,veth的数据发送接收最后会使用软中断的方式,这也刚好解释了容器化以后为什么会有更多的软中断,也找到了性能下降的原因。

4. 优化策略

原来我们使用 calico 的 ipip 模式,它是一种 overlay 的网络方案,容器和宿主机之间通过 veth pair 进行通信存在性能损耗,虽然 calico 可以通过 BGP,在三层通过路由的方式实现 underlay 的网络通信,但还是不能避免 veth pari 带来的性能损耗,针对性能敏感的应用,那么有没有其他 underly 的网络方案来保障网络性能呢?那就是 macvlan/ipvlan 模式,我们以 ipvlan 为例稍微展开讲讲。

4.1 ipvlan L2 模式

IPvlan 和传统 Linux 网桥隔离的技术方案有些区别,它直接使用 Linux 以太网的接口或子接口相关联,这样使得整个发送路径变短,并且没有软中断的影响,从而性能更优。如下图所示:
上图是ipvlan L2模式的通信模型,可以看出container直接使用host eth0发送数据,可以有效减小发送路径,提升发送性能。

4.2 ipvlan L3 模式

ipvlan L3模式,宿主机充当路由器的角色,实现容器跨网段的访问,如下图所示:

4.3 Cilium

除了使用  macvlan/ipvlan提升网络性能外,我们还可以使用 Cilium 来提升性能,Cilium 为云原生提供了网络、可观测性、网络安全等解决方案,同时它是一个高性能的网络CNI插件,高性能的原因是优化了数据发送的路径,减少了 iptables 开销。
虽然 calico 也支持 ebpf,但是通过 benchmark 的对比,Cilium性能更好,高性能名副其实,接下来我们来看看官网公布的一些 benchmark 的数据,我们只取其中一部分来分析,如下图:
无论从 QPS 和 CPU 使用率上 Cilium 都拥有更强的性能。

5. 总结

容器化带来了敏捷、效率、资源利用率的提升、环境的一致性等等优点的同时,也使得整体的系统复杂度提升一个等级,特别是网络问题,容器化使得整个数据发送路径变长,排查难度增大。不过现在很多网络插件也提供了很多可观测性的能力,帮助我们定位问题。
我们还是需要从实际业务场景出发,针对容器化后性能、安全、问题排查难度增大等问题,通过优化架构,增强基础设施建设才能让我们在云原生的路上越走越远。
最后,感谢大家观看,也希望和我讨论云原生过程中遇到的问题。

END

官方站点:www.linuxprobe.com

Linux命令大全:www.linuxcool.com

刘遄老师QQ:5604215

Linux技术交流群:2636170

(新群,火热加群中……)

想要学习Linux系统的读者可以点击"阅读原文"按钮来了解书籍《Linux就该这么学》,同时也非常适合专业的运维人员阅读,成为辅助您工作的高价值工具书!