分别测试在启用 istio前后 ,通过压测 nginx web 服务,观察对资源的消耗情况以及最大 QPS。
服务端: c8m16,centos7.7 装有 Kubesphere 平台(用 ks 官网提供的all-in-one 方式安装的 kubesphere)
客户端: c8m16,centos7.7
两台主机都位于青云的基础网络中,并能相互访问。
工具介绍:
客户端用 vegeta,这个工具能利用多核,并能控制并发数,最后会对测试结果进行分析。
wget https://github.com/tsenart/vegeta/releases/download/v8.0.0/vegeta-8.0.0-linux-amd64.tar.gz
下载后,解压将 vegeta
二进命令放进 /usr/local/bin
服务端配合 dstat 命令行工具查看实时资源情况,并配合虚机控制台观察资源实时情况。
dstat 能够直观地以具体数值的形式,实时观察到当前网络/cpu/内存等的性能状况。
yum install dstat -y
服务端(istio1.3.3)
平台部署 nginx deployment,并暴露service ,指定 service type 为 NodePort
用 dry-run 生成 deployment 的 yaml 文件
root@ks-allinone:/root # kubectl create deployment my-nginx --image=nginx --dry-run -o yaml > nginx-deploy.yaml
修改 nginx-deploy.yaml 的 ports为 80,deployment 的yaml 如下
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: my-nginx
name: my-nginx
spec:
replicas: 1
selector:
matchLabels:
app: my-nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: my-nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
ports:
- containerPort: 80
status: {}
创建 deployment
root@ks-allinone:/root # kubectl apply -f nginx-deploy.yaml
确认工作负载正常
root@ks-allinone:/root # kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
my-nginx 1/1 1 1 3h27m
root@ks-allinone:/root # kubectl get po
NAME READY STATUS RESTARTS AGE
my-nginx-6fbdd4465-g7cg6 1/1 Running 1 33m
此时是没有 sidecar 的,可以 describe pods 来确认。只有当 deployment 里面显式申明 annotations 为sidecar.istio.io/inject: “true” 时才会有 sidecar。因此,此时是直连的。
root@ks-allinone:/root # kubectl describe po/my-nginx-6fbdd4465-g7cg6 | grep Container
Containers:
Container ID: docker://7bc6cffd0bbc078ad6d245a64c890ea7bce45e3b72cddbb91980bba40d023d92
ContainersReady True
可以看到,并没有 istio-proxy 容器,因此未启用 istio-proxy,是直连的。
暴露服务端口并指定服务类型
kubectl expose deploy my-nginx --type=Nodeport
root@ks-allinone:/root # kubectl get ep/my-nginx
NAME ENDPOINTS AGE
my-nginx 10.233.100.94:80 12hq
root@ks-allinone:/root # kubectl get svc/my-nginx -o yaml
...
spec:
clusterIP: 10.233.30.222
externalTrafficPolicy: Cluster
ports:
- nodePort: 31415
port: 80
protocol: TCP
targetPort: 80
...
确认能正常访问服务
root@ks-allinone:/root # curl http://10.160.7.101:31415
...
<title>Welcome to nginx!</title>
<p>If you see this page, the nginx web server is successfully installed and
<style>
...
客户端
要用多个客户端进程或主机,直接压测到单台服务端的【HTTP】,确保一个服务端的CPU达到80%并且是一条平线。这时能得出一台服务端所能承载的数据。这里我的环境只用一台高配的 linux,经观察,能保证客户端资源足够,没有达到瓶颈。
客户端 Linux 内核调优
# sysctl
# * `/etc/sysctl.conf`
net.core.somaxconn = 65535
net.ipv4.ip_local_port_range = 1024 65023
net.ipv4.tcp_syncookies = 0
net.ipv4.tcp_syn_retries = 6
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_max_syn_backlog = 1048576
net.ipv4.tcp_max_tw_buckets = 1048576
net.ipv4.tcp_max_orphans=65535
net.ipv4.icmp_ratelimit = 10
kernel.pid_max = 65536
net.ipv4.neigh.default.gc_thresh1 = 512
net.ipv4.neigh.default.gc_thresh2 = 2048
net.ipv4.neigh.default.gc_thresh3 = 4096
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# net
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
net.core.netdev_max_backlog = 65535
# udp
net.ipv4.udp_rmem_min = 131072
net.ipv4.udp_wmem_min = 131072
# this is a must
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
### ulimit
# * `/etc/security/limits.conf`
root soft nofile 65536
root hard nofile 65536
* soft nofile 65536
* hard nofile 65536
[root@i-w92oin2z ~]# ulimit -n
65536
[root@i-w92oin2z ~]# ulimit -u
65536
测试
目前是未启用 istio 的情况
在测试的时候,启用 8cpu,持续压测 15s,尽量保证丢包率。
[root@i-w92oin2z ~]# echo "GET http://10.160.7.101:31415" | vegeta --cpus 8 attack -duration=15s -rate 9730 -keepalive 0| tee results.bin | vegeta report
^CRequests [total, rate] 22023, 9730.92
Duration [total, attack, wait] 2.263905878s, 2.263199186s, 706.692µs
Latencies [mean, 50, 95, 99, max] 6.551698ms, 4.682796ms, 17.103551ms, 25.095751ms, 1.005557864s
Bytes In [total, mean] 13478076, 612.00
Bytes Out [total, mean] 0, 0.00
Success [ratio] 100.00%
Status Codes [code:count] 200:22023
Error Set:
上述在测试的时候为什么直接用 9730 这个 qps 呢?
这是因为自已在测试时候,其实已经知道了在启用的 istio 时候的最大 iops 是这个值,这里为了做比较,预先用这个iops,来看下资源的消耗情况。

启用 istio
修改 deployment 的 yaml,加上annotations sidecar.istio.io/inject: "true"
,然后 restart deployment,让 sidecar 注入
root@ks-allinone:/root # kubectl edit deploy/my-nginx

滚动更新
root@ks-allinone:/root # kubectl rollout restart deploy/my-nginx
查看 sidecar 是否已经正常注入
root@ks-allinone:/root # kubectl describe po/my-nginx-758549d5f5-s6rx7|grep Container
...
Init Containers:
istio-init:
Container ID: docker://8a40741fa51555786f7cb8bc41a207892d3eeec277d51a015d9841e6cb46e5b1
Image: istio/proxy_init:1.3.3
--
/var/run/secrets/kubernetes.io/serviceaccount from default-token-qtpzv (ro)
Containers:
nginx:
Container ID: docker://06a4f4137853928779305fa7b08f375d979a4c108ca28ca7d811d34a7fc180b8
Image: nginx
--
istio-proxy:
Container ID: docker://3967a930c02fe9bcc891868c1e13d206967488b0864c0ef929b5dd0a6065698b
Image: istio/proxyv2:1.3.3
--
...
客户端启动压测

观察测试结果

对比下压力一定的情况下,前后资源的使用情况:

内存并未有太在的变化,主要资源消耗情况提现在 cpu上。
上述是对比压力一定的情况下,资源消耗情况的一个对比。现在调整 deployment annotation ,
不启用 istio,看下最大 qps 能达到多少。
[root@i-w92oin2z ~]# echo "GET http://10.160.7.101:31415" | vegeta --cpus 8 attack -duration=15s -rate 11100| tee results.bin | vegeta report
Requests [total, rate] 166500, 11071.28
Duration [total, attack, wait] 18.468855476s, 15.038907309s, 3.429948167s
Latencies [mean, 50, 95, 99, max] 79.342712ms, 17.243526ms, 313.747387ms, 1.077144782s, 8.148469651s
Bytes In [total, mean] 101832516, 611.61
Bytes Out [total, mean] 0, 0.00
Success [ratio] 99.94%
Status Codes [code:count] 0:107 200:166393
Error Set:
Get http://10.160.7.101:31415: EOF
可以看到 QPS 基本上能达到最大的值是 11100 了,再调大,丢包率会增加,因此基本上这个就是最大值了。
看下服务端资源消耗情况:


总结
使用 istio最大的 QPS 约为 9730,不使用 istio 最大 QPS 约为 11100。
使用 istio/不使用 istio ≈ 88%
因为本次实验环境是 all-in-one 模式,只是简单的做了下对比,与生产环境相比存在一定的误差。如果生产环境上有压测经验的,欢迎补充。