在k8s部署业务服务pod时,如果将该Pod以k8s svc NodePort类型负载出来,这时压测应用的响应性能较高,可以达到10w多的QPS;将这个k8s svc再用Ingress代理,压测应用发现只有5w多的QPS了。这个性能开销非常大,差了大概一半的性能,所以需要对nginx-ingress-controller进行优化处理。
我们知道,nginx-ingress-controller的原理实际上是扫描Kubernetes集群中的Ingress资源,根据Ingress资源的定义自动为每个域名生成一段nginx虚拟主机及反向代理的配置,最后由nginx读取这些配置,完成实际的HTTP请求流量的处理,整个HTTP请求链路如下:
client ->nginx -> upstream(kubernetes service) -> pods
nginx的实现中必然要对接收的HTTP请求进行7层协议解析,并根据请求信息将HTTP请求转发给upstream。
而client直接请求kubernetes service有不错的QPS值,说明nginx这里存在问题。
1)使用ipvs代替iptables
[root@xianchaomaster1 ~]#yum install -y ipset ipvsadm [root@xianchaomaster1~]#cat << 'EOF' > /etc/sysconfig/modules/ipvs.modules #!/bin/bash ipvs_modules=(ip_vsip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_ship_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack_ipv4) forkernel_module in ${ipvs_modules[*]}; do /sbin/modinfo -Ffilename ${kernel_module} > /dev/null 2>&1 if [ $? -eq 0 ];then /sbin/modprobe${kernel_module} fi done EOF [root@xianchaomaster1~]#chmod +x /etc/sysconfig/modules/ipvs.modules [root@xianchaomaster1~]# /etc/sysconfig/modules/ipvs.modules [root@xianchaomaster1~]# kubectl -n kube-system edit cm kube-proxy ...... mode:"ipvs" ...... [root@xianchaonode1~]# yum install -y ipset ipvsadm [root@xianchaonode1~]#cat<< 'EOF' > /etc/sysconfig/modules/ipvs.modules #!/bin/bash ipvs_modules=(ip_vsip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_ship_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack_ipv4) forkernel_module in ${ipvs_modules[*]}; do /sbin/modinfo -Ffilename ${kernel_module} > /dev/null 2>&1 if [ $? -eq 0 ];then /sbin/modprobe${kernel_module} fi done EOF [root@ xianchaonode1~]# chmod +x /etc/sysconfig/modules/ipvs.modules [root@ xianchaonode1~]#/etc/sysconfig/modules/ipvs.modules [root@xianchaomaster1~]# kubectl -n kube-system get pod -l k8s-app=kube-proxy | grep -v 'NAME' | awk'{print $1}' | xargs kubectl -n kube-system delete pod [root@xianchaomaster1~]# iptables -t filter -F; iptables -t filter -X; iptables -t nat -F; iptables-t nat -X; [root@ xianchaonode1~]#iptables -t filter -F; iptables -t filter -X; iptables -t nat -F; iptables -tnat -X;
修改ipvs模式之后过5-10分钟测试在k8s创建pod是否可以正常访问网络
[root@xianchaomaster1~]# kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox-- sh / # pingwww.baidu.com PING www.baidu.com(39.156.66.18): 56 data bytes 64 bytes from110.242.68.4: seq=0 ttl=127 time=37.319 ms #通过上面可以看到能访问网络 /# exit
测试dns是否正常
[root@xianchaomaster1 ~]# kubectl run busybox--image busybox:1.28 --restart=Never --rm -it busybox -- sh / # nslookup kubernetes.default.svc.cluster.local Server: 10.96.0.10 Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local Name: kubernetes.default.svc.cluster.local Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
看到上面内容,说明k8s的dns解析正常
2)k8s集群节点修改内核参数
cat << EOF>> /etc/sysctl.conf net.core.somaxconn= 655350 net.ipv4.tcp_syncookies= 1 net.ipv4.tcp_timestamps= 1 net.ipv4.tcp_tw_reuse= 1 net.ipv4.tcp_fin_timeout= 30 net.ipv4.tcp_max_tw_buckets= 5000 net.nf_conntrack_max= 2097152 net.netfilter.nf_conntrack_max= 2097152 net.netfilter.nf_conntrack_tcp_timeout_close_wait= 15 net.netfilter.nf_conntrack_tcp_timeout_fin_wait= 30 net.netfilter.nf_conntrack_tcp_timeout_time_wait= 30 net.netfilter.nf_conntrack_tcp_timeout_established= 1200 EOF $ sysctl -p –system
3)k8s集群节点修改最大打开文件数
ulimit -n 655350 cat /etc/sysctl.conf ... fs.file-max=655350 ... sysctl -p--system cat/etc/security/limits.conf ... * hard nofile655350 * soft nofile655350 * hard nproc6553 * soft nproc655350 root hard nofile655350 root soft nofile655350 root hard nproc655350 root soft nproc655350 ... echo 'sessionrequired pam_limits.so' >> /etc/pam.d/common-session
4)优化nginx-ingress-controller
参考nginx-ingress-controller的配置方法,这里优化部分如下:
$ kubectl -nkube-system edit configmap nginx-configuration ... apiVersion: v1 data: keep-alive:"60" keep-alive-requests:"100" upstream-keepalive-connections:"10000" upstream-keepalive-requests:"100" upstream-keepalive-timeout:"60" kind: ConfigMap ...
此时发现性能好多了
么是Keep-Alive模式?
HTTP协议采用请求-应答模式,有普通的非KeepAlive模式,也有KeepAlive模式。
非KeepAlive模式时,每个请求/应答客户和服务器都要新建一个连接,完成 之后立即断开连接(HTTP协议为无连接的协议);当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。
启用Keep-Alive的优点
启用Keep-Alive模式肯定更高效,性能更高。因为避免了建立/释放连接的开销。下面是RFC 2616 上的总结:
TCP连接更少,这样就会节约TCP连接在建立、释放过程中,主机和路由器上的CPU和内存开销。
网络拥塞也减少了,拿到响应的延时也减少了
错误处理更优雅:不会粗暴地直接关闭连接,而是report,retry
性能大提升的原因
压测命令ab并没有添加-k参数,因此client->nginx的HTTP处理并没有启用Keep-Alive。
但由于nginx-ingress-controller配置了upstream-keepalive-connections、upstream-keepalive-requests、upstream-keepalive-timeout参数,这样nginx->upstream的HTTP处理是启用了Keep-Alive的,这样到Kuberentes Service的TCP连接可以高效地复用,避免了重建连接的开销。