现象同样TPS低、响应时间长,但这个接口走的路径不一样,你将看到在资源真不足时,只有增加相应节点的资源才能提升性能。
- 不要轻易给出资源不足的结论。因为但凡有优化空间,都要尝试优化,而不是直接告诉领导加资源。
- 给“增加资源”结论,须建立在有足够证据基础上
1 压力场景数据
对查询商品接口,第一次试执行性能场景的结果:
TPS只有250左右,且响应时间也明显随压力增加而增加,看起来瓶颈已出现?下一步看架构图。
2 看架构图
APM工具看接口的架构:
从压力机到Gateway服务、到Search服务、再到ES-Client,这个APM工具也只能帮到这。因为用的ES 7做搜索服务,而skywalking工具也没有对应Agent,所以后面没配skywalking。
现在的APM工具大多基于应用层做的,有些运维APM采集的数据会更多,但也是响应时间、吞吐量等信息。对性能分析,现在的APM工具有减少排查时间的能力,但在组件级的细化定位还有待提高。虽然AI OPS也被提到台面,但也没见过哪个公司上AIOPS后,就不让人看着。
总之,从细化分析的角度,定位问题根因时,手头有什么工具就用,即使工具都没,撸日志也照样能做到,不要迷信工具,要“迷信”思路。
3 拆分响应时间
RESAR性能分析逻辑中,拆分响应时间只是一个分析的起点。
根据架构图,拆分响应时间如下:
- Gateway服务上的响应时间:
- Search服务上的响应时间:
- ES Client的响应时间:
一层层看后,发现查询商品接口的响应时间消耗在ES client。而在这查询的路径,在gateway/search服务上,并没做复杂动作。
既然知道响应时间消耗在哪,就定位它,看能不能把TPS优化起来。
4 全局监控
还是从全局监控开始,看全局监控可让我们有的放矢。分析过程中,经常有人往下走几步后,就思维混乱。因为数据很多,分析时易从一个数据走到不重要分支。而这时,若你心有全局监控数据,思路会更清晰,不会在无关分支消耗时间。
回到例子,从下面k8s worker(即k8s的node,在我们的环境中我习惯叫worker)数据看,似乎没一个worker的资源使用率特别高:
在k8s看资源消耗,不要只看worker层,一个worker可能运行多pod。上图看,由于worker层没有资源消耗,但时间又明显消耗在ES client,所以,接下来要看每个pod的资源使用情况:
有红色!有两个与ES相关POD,它们CPU都红了。既然是与ES相关POD,就把ES所有的POD排个序看:
从上图数据看,有个ES Client 消耗67% CPU,有两个ES Data消耗99% CPU,ES本就是吃CPU大户。
从前面的worker资源使用率一步一步走到这里,在分析方向上是合情合理的,因为这些都是属于全局监控内容。
5 定向分析
现在我们就来扒一扒ES,看它在哪个worker节点。罗列Pod信息:
1[root@k8s-master-1 ~]# kubectl get pods -o wide | grep elasticsearch2elasticsearch-client-0 1/1 Running 0 6h43m 10.100.230.2 k8s-worker-1 <none> <none>3elasticsearch-client-1 1/1 Running 0 6h45m 10.100.140.8 k8s-worker-2 <none> <none>4elasticsearch-data-0 1/1 Running 0 7h8m 10.100.18.197 k8s-worker-5 <none> <none>5elasticsearch-data-1 1/1 Running 0 7h8m 10.100.5.5 k8s-worker-7 <none> <none>6elasticsearch-data-2 1/1 Running 0 7h8m 10.100.251.67 k8s-worker-9 <none> <none>7elasticsearch-master-0 1/1 Running 0 7h8m 10.100.230.0 k8s-worker-1 <none> <none>8elasticsearch-master-1 1/1 Running 0 7h8m 10.100.227.131 k8s-worker-6 <none> <none>9elasticsearch-master-2 1/1 Running 0 7h8m 10.100.69.206 k8s-worker-3 <none> <none>10[root@k8s-master-1 ~]#
可看到,整个namespace有两个ES client,三个ES data,三个ES master。
画个细点的架构图:
再结合全局分析的资源使用率图,现在判断至少有两个问题:
- ES client请求不均衡;
- ES data CPU 高。
下面我们一个一个来分析。
5.1 ES client请求不均衡
从上面架构图中可见,search服务连两个ES client,但是只有一个ES client的CPU使用率高。所以,要查链路,看ES的service:
1[root@k8s-master-1 ~]# kubectl get svc -o wide | grep search2elasticsearch-client NodePort 10.96.140.52 <none> 9200:30200/TCP,9300:31614/TCP 34d app=elasticsearch-client,chart=elasticsearch,heritage=Helm,release=elasticsearch-client3elasticsearch-client-headless ClusterIP None <none> 9200/TCP,9300/TCP 34d app=elasticsearch-client4elasticsearch-data ClusterIP 10.96.16.151 <none> 9200/TCP,9300/TCP 7h41m app=elasticsearch-data,chart=elasticsearch,heritage=Helm,release=elasticsearch-data5elasticsearch-data-headless ClusterIP None <none> 9200/TCP,9300/TCP 7h41m app=elasticsearch-data6elasticsearch-master ClusterIP 10.96.207.238 <none> 9200/TCP,9300/TCP 7h41m app=elasticsearch-master,chart=elasticsearch,heritage=Helm,release=elasticsearch-master7elasticsearch-master-headless ClusterIP None <none> 9200/TCP,9300/TCP 7h41m app=elasticsearch-master8svc-mall-search ClusterIP 10.96.27.150 <none> 8081/TCP 44d app=svc-mall-search9[root@k8s-master-1 ~]#
你看,整个namespace中有一个client service(解析出来的是VIP,访问此服务时不会绕过K8s的转发机制),还有一个client-headless service(解析出来的是POD IP,访问这个服务时会绕过K8s的转发机制)。
查为何出现访问不均衡。
查看search服务的ES配置,看到:
1 elasticsearch:2 rest:3 uris: elasticsearch-client:92004 username: elastic5 password: admin@123
看到这用的elasticsearch-client:9200,再看client service的配置:
1---2apiVersion: v13kind: Service4metadata:5 annotations:6 meta.helm.sh/release-name: elasticsearch-client7 meta.helm.sh/release-namespace: default8 creationTimestamp: '2020-12-10T17:34:19Z'9 labels:10 app: elasticsearch-client11 app.kubernetes.io/managed-by: Helm12 chart: elasticsearch13 heritage: Helm14 release: elasticsearch-client15 managedFields:16 - apiVersion: v117 fieldsType: FieldsV118 fieldsV1:19 'f:metadata': {}20 'f:spec':21 'f:ports': {}22 manager: Go-http-client23 operation: Update24 time: '2020-12-10T17:34:19Z'25 name: elasticsearch-client26 namespace: default27 resourceVersion: '4803428'28 selfLink: /api/v1/namespaces/default/services/elasticsearch-client29 uid: 457e962e-bee0-49b7-9ec4-ebfbef0fecdd30spec:31 clusterIP: 10.96.140.5232 externalTrafficPolicy: Cluster33 ports:34 - name: http35 nodePort: 3020036 port: 920037 protocol: TCP38 targetPort: 920039 - name: transport40 nodePort: 3161441 port: 930042 protocol: TCP43 targetPort: 930044 selector:45 app: elasticsearch-client46 chart: elasticsearch47 heritage: Helm48 release: elasticsearch-client49 sessionAffinity: None50 type: NodePort
从上面配置看,sessionAffinity也配置为None,即这个service不以客户端的IP来保持session。因为在这个环境配置中,Type为NodePort,而我们在k8s中配置的转发规则是iptables。所以说,service是依赖iptables的规则来做后端转发的。
接下来,我们检查一下iptables的转发规则。
先看iptables中关于ES client的规则:
1[root@k8s-master-1 ~]# iptables -S KUBE-SERVICES -t nat|grep elasticsearch-client|grep 92002-A KUBE-SERVICES ! -s 10.100.0.0/16 -d 10.96.140.52/32 -p tcp -m comment --comment "default/elasticsearch-client:http cluster IP" -m tcp --dport 9200 -j KUBE-MARK-MASQ3-A KUBE-SERVICES -d 10.96.140.52/32 -p tcp -m comment --comment "default/elasticsearch-client:http cluster IP" -m tcp --dport 9200 -j KUBE-SVC-XCX4XZ2WPAE7BUZ44[root@k8s-master-1 ~]#
service的规则名是KUBE-SVC-XCX4XZ2WPAE7BUZ4,再去查它对应iptables规则:
1[root@k8s-master-1 ~]# iptables -S KUBE-SVC-XCX4XZ2WPAE7BUZ4 -t nat2-N KUBE-SVC-XCX4XZ2WPAE7BUZ43-A KUBE-SVC-XCX4XZ2WPAE7BUZ4 -m comment --comment "default/elasticsearch-client:http" -j KUBE-SEP-LO263M5QW4XA6E3Q4[root@k8s-master-1 ~]#567[root@k8s-master-1 ~]# iptables -S KUBE-SEP-LO263M5QW4XA6E3Q -t nat8-N KUBE-SEP-LO263M5QW4XA6E3Q9-A KUBE-SEP-LO263M5QW4XA6E3Q -s 10.100.227.130/32 -m comment --comment "default/elasticsearch-client:http" -j KUBE-MARK-MASQ10-A KUBE-SEP-LO263M5QW4XA6E3Q -p tcp -m comment --comment "default/elasticsearch-client:http" -m tcp -j DNAT --to-destination 10.100.227.130:9200
好像没有负载均衡配置(probability参数),且根据iptables规则也只是转发到一个ES client。至此,其实我们也就能理解,为什么在全局监控的时候,我们只看到一个ES client有那么高的CPU使用率,而另一个ES client却没动静。
但这里的iptables规则并不是自己来配置的,而是在部署k8s的时候自动刷进去的规则。现在只有一条规则了,所以只能转发到一个POD上去。
再刷一遍ES POD,重装下ES POD,看k8s自己能不能刷出来负载均衡的iptables规则。重来一遍后,再看iptables规则:
1[root@k8s-master-1 ~]# iptables -S KUBE-SVC-XCX4XZ2WPAE7BUZ4 -t nat2-N KUBE-SVC-XCX4XZ2WPAE7BUZ43-A KUBE-SVC-XCX4XZ2WPAE7BUZ4 -m comment --comment "default/elasticsearch-client:http" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-IFM4L7YNSTSJP4YT4-A KUBE-SVC-XCX4XZ2WPAE7BUZ4 -m comment --comment "default/elasticsearch-client:http" -j KUBE-SEP-5RAP6F6FATXC4DFL5[root@k8s-master-1 ~]#
现在刷出来两条iptables规则了,看来之前不断折腾的部署过程中,ES client一直有问题。
在上面的iptables规则里,那两条iptables的上一条中有一个关键词“——probability 0.50000000000”。
iptables的匹配规则是从上到下,既然上一条的匹配是随机0.5,即只有50%的请求走第一条规则,那下一条自然也是随机0.5,因为总共只有两条规则。这样就均衡了。
接着做这个接口的压力场景:
看起来ES client均衡了,它对应TPS:
明显TPS提升60。
ES client请求不均衡的问题解决了,还要看下ES data单节点CPU高的问题。
5.2 ES Data CPU使用率高
一阶段:加个CPU
TPS提升后,再看全局监控数据:
比开始好多了。基于前面分析ES client经验,先查ES data的iptables规则:
1-- 查看下有哪些ES data的POD2[root@k8s-master-1 ~]# kubectl get pods -o wide | grep data3elasticsearch-data-0 1/1 Running 0 10h 10.100.18.197 k8s-worker-5 <none> <none>4elasticsearch-data-1 1/1 Running 0 10h 10.100.5.5 k8s-worker-7 <none> <none>5elasticsearch-data-2 1/1 Running 0 10h 10.100.251.67 k8s-worker-9 <none> <none>678-- 查看ES data对应的iptables规则9[root@k8s-master-1 ~]# iptables -S KUBE-SERVICES -t nat|grep elasticsearch-data10-A KUBE-SERVICES ! -s 10.100.0.0/16 -d 10.96.16.151/32 -p tcp -m comment --comment "default/elasticsearch-data:http cluster IP" -m tcp --dport 9200 -j KUBE-MARK-MASQ11-A KUBE-SERVICES -d 10.96.16.151/32 -p tcp -m comment --comment "default/elasticsearch-data:http cluster IP" -m tcp --dport 9200 -j KUBE-SVC-4LU6GV7CN63XJXEQ12-A KUBE-SERVICES ! -s 10.100.0.0/16 -d 10.96.16.151/32 -p tcp -m comment --comment "default/elasticsearch-data:transport cluster IP" -m tcp --dport 9300 -j KUBE-MARK-MASQ13-A KUBE-SERVICES -d 10.96.16.151/32 -p tcp -m comment --comment "default/elasticsearch-data:transport cluster IP" -m tcp --dport 9300 -j KUBE-SVC-W4QKPGOO4JGYQZDQ141516-- 查看9200(外部通信)对应的规则17[root@k8s-master-1 ~]# iptables -S KUBE-SVC-4LU6GV7CN63XJXEQ -t nat18-N KUBE-SVC-4LU6GV7CN63XJXEQ19-A KUBE-SVC-4LU6GV7CN63XJXEQ -m comment --comment "default/elasticsearch-data:http" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-ZHLKOYKJY5GV3ZVN20-A KUBE-SVC-4LU6GV7CN63XJXEQ -m comment --comment "default/elasticsearch-data:http" -m statistic --mode random --probability 1 -j KUBE-SEP-6ILKZEZS3TMCB4VJ21-A KUBE-SVC-4LU6GV7CN63XJXEQ -m comment --comment "default/elasticsearch-data:http" -j KUBE-SEP-JOYLBDPA3LNXKWUK222324-- 查看以上三条规则的转发目标25[root@k8s-master-1 ~]# iptables -S KUBE-SEP-ZHLKOYKJY5GV3ZVN -t nat26-N KUBE-SEP-ZHLKOYKJY5GV3ZVN27-A KUBE-SEP-ZHLKOYKJY5GV3ZVN -s 10.100.18.197/32 -m comment --comment "default/elasticsearch-data:http" -j KUBE-MARK-MASQ28-A KUBE-SEP-ZHLKOYKJY5GV3ZVN -p tcp -m comment --comment "default/elasticsearch-data:http" -m tcp -j DNAT --to-destination 10.100.18.197:920029[root@k8s-master-1 ~]# iptables -S KUBE-SEP-6ILKZEZS3TMCB4VJ -t nat30-N KUBE-SEP-6ILKZEZS3TMCB4VJ31-A KUBE-SEP-6ILKZEZS3TMCB4VJ -s 10.100.251.67/32 -m comment --comment "default/elasticsearch-data:http" -j KUBE-MARK-MASQ32-A KUBE-SEP-6ILKZEZS3TMCB4VJ -p tcp -m comment --comment "default/elasticsearch-data:http" -m tcp -j DNAT --to-destination 10.100.251.67:920033[root@k8s-master-1 ~]# iptables -S KUBE-SEP-JOYLBDPA3LNXKWUK -t nat34-N KUBE-SEP-JOYLBDPA3LNXKWUK35-A KUBE-SEP-JOYLBDPA3LNXKWUK -s 10.100.5.5/32 -m comment --comment "default/elasticsearch-data:http" -j KUBE-MARK-MASQ36-A KUBE-SEP-JOYLBDPA3LNXKWUK -p tcp -m comment --comment "default/elasticsearch-data:http" -m tcp -j DNAT --to-destination 10.100.5.5:920037[root@k8s-master-1 ~]
规则很合理。ES Data共三个pod,逻辑上看,各占三分之一。
在前面的ES client分析中,第一个POD 0.5,下一条自然也只剩0.5。现在,ES data部分有三条iptables规则。而这部分,主要是看nat表及其上的链。
从上面信息可见,这集群有三个ES data服务,对应三条转发规则
- 第一条规则的匹配比例是:0.33333333349
- 第二条比例:0.50000000000
- 第三条是1
这三条转发规则对应的POD IP和端口分别是:10.100.18.197:9200、10.100.251.67:9200、10.100.5.5:9200,即通过这三条iptables规则可实现负载均衡:
假设30个请求进来,那ES Data 0会有30x0.33333333349=10个请求;对于剩下的20个请求,在ES Data 1上就会有20x0.50000000000=10个请求;最后10个请求到ES Data 2。这是非常均衡的逻辑,只是在iptables规则中,我看这几个数据比例,觉得别扭。
既然明白这逻辑,下面还是把查询商品接口的场景压起来:
数据上看,经常出现ES data 某个节点消耗CPU高。可对应到我们前面看到的全局worker监控界面中,并没有哪个worker的CPU很高。所以,这里要查ES Data中的cgroup配置的限制。
即ES data的每个POD都是配置了一颗CPU,难怪CPU使用率动不动就红了。
前面查看data列表时发现,ES data 0 在worker-5上,ES data 1 在worker-7上,ES data 2 在worker-9上。而我们现在看到的却是,它们都各自分到了一个CPU。既然如此,再添加一个CPU,然后再回去看worker-5/7/9的反应。为什么只加一个CPU?因为从worker-7上来看,现在的CPU使用率已经在50%左右了,要是加多了,我怕它吃不消。
看压力场景执行效果:
似乎……不怎么样?TPS没增加。
二阶段:加副本
加CPU后的全局POD监控:
还是只有一个ES data的CPU使用率高,所以查ES中的数据分布。因为负载均衡解决了,且知道有三个ES data节点。现在就要知道是不是每个节点都被访问到了。
pms 0 p 10.100.18.199 _w 32 17690 18363 6.7mb 7820 true true 8.5.1 false
pms 0 p 10.100.18.199 _15 41 2110 0 465.7kb 5500 true true 8.5.1 true
pms 0 p 10.100.18.199 _16 42 21083 30255 9.5mb 5900 true true 8.5.1 false
pms 0 p 10.100.18.199 _17 43 2572 0 568kb 5500 true true 8.5.1 true
pms 0 p 10.100.18.199 _18 44 1403 0 322.9kb 5500 true true 8.5.1 true
pms 0 p 10.100.18.199 _19 45 1856 0 414.1kb 5500 true true 8.5.1 true
pms 0 p 10.100.18.199 _1a 46 1904 0 423kb 5500 true true 8.5.1 true
为啥数据都在一个节点上(都是10.100.18.199)?看起来只有一个数据副本的原因了。
green open pms A--6O32bQaSBrJPJltOLHQ 1 0 48618 48618 55.1mb 18.3mb
所以,我们先把副本数加上去,因为我们有三个data节点,所以这里加三个副本:
PUT /pms/_settings
{
"number_of_replicas": 3
}
我们再次查看ES中的数据分布,如下所示:
pms 0 r 10.100.18.200 _w 32 17690 18363 6.7mb 7820 true true 8.5.1 false
pms 0 r 10.100.18.200 _15 41 2110 0 465.7kb 5500 true true 8.5.1 true
pms 0 r 10.100.18.200 _16 42 21083 30255 9.5mb 5900 true true 8.5.1 false
pms 0 r 10.100.18.200 _17 43 2572 0 568kb 5500 true true 8.5.1 true
pms 0 r 10.100.18.200 _18 44 1403 0 322.9kb 5500 true true 8.5.1 true
pms 0 r 10.100.18.200 _19 45 1856 0 414.1kb 5500 true true 8.5.1 true
pms 0 r 10.100.18.200 _1a 46 1904 0 423kb 5500 true true 8.5.1 true
pms 0 p 10.100.251.69 _w 32 17690 18363 6.7mb 7820 true true 8.5.1 false
pms 0 p 10.100.251.69 _15 41 2110 0 465.7kb 5500 true true 8.5.1 true
pms 0 p 10.100.251.69 _16 42 21083 30255 9.5mb 5900 true true 8.5.1 false
pms 0 p 10.100.251.69 _17 43 2572 0 568kb 5500 true true 8.5.1 true
pms 0 p 10.100.251.69 _18 44 1403 0 322.9kb 5500 true true 8.5.1 true
pms 0 p 10.100.251.69 _19 45 1856 0 414.1kb 5500 true true 8.5.1 true
pms 0 p 10.100.251.69 _1a 46 1904 0 423kb 5500 true true 8.5.1 true
pms 0 r 10.100.140.10 _w 32 17690 18363 6.7mb 7820 true true 8.5.1 false
pms 0 r 10.100.140.10 _15 41 2110 0 465.7kb 5500 true true 8.5.1 true
pms 0 r 10.100.140.10 _16 42 21083 30255 9.5mb 5900 true true 8.5.1 false
pms 0 r 10.100.140.10 _17 43 2572 0 568kb 5500 true true 8.5.1 true
pms 0 r 10.100.140.10 _18 44 1403 0 322.9kb 5500 true true 8.5.1 true
pms 0 r 10.100.140.10 _19 45 1856 0 414.1kb 5500 true true 8.5.1 true
pms 0 r 10.100.140.10 _1a 46 1904 0 423kb 5500 true true 8.5.1 true
接着压,看POD资源:
data节点的CPU都用起来了。
再看worker的资源:
[root@k8s-master-1 ~]# kubectl get pods -o wide | grep data
elasticsearch-data-0 1/1 Running 0 16m 10.100.18.199 k8s-worker-5 <none> <none>
elasticsearch-data-1 1/1 Running 0 17m 10.100.251.68 k8s-worker-9 <none> <none>
elasticsearch-data-2 1/1 Running 0 18m 10.100.140.9 k8s-worker-2 <none> <none>
现在ES Data的POD分布到2、5、9三这个worker上去了,我们查看下全局监控:
嗯,不错,ES data的POD把资源用起来了。其实这里要想继续调,还可以把CPU加大,ES本来就是吃CPU、内存的大户。不过,我们前面在配置的时候,给ES data的CPU也确实太小了。这个问题,并不是我故意设计出来的,而是当时在部署的时候,没考虑到这些。
最后看优化后效果:
TPS很快涨到900左右了!优化很好。
现在回过头来看第一个阶段,我们加CPU没有效果,主要还是因为副本数量太少。ES优化中还有很多细节。只不过给你的是整体分析思路和逻辑,而不是纠结每个细节参数。
如果你想在ES做更多优化,可在分析完业务之后,确定一下ES的架构、数据索引、分片等信息,然后再来设计合理的ES部署。
6 总结
我们看到APM工具也有无能为力的地方。所以分析到具体组件后,要想再往下分析,就得靠自己的技术功底。
在出现请求不均衡的时候,我们一定要先去看负载均衡的逻辑有没有问题。当看到ES client不均衡时,我们去看了iptables的原理,在发现iptables只有一个转发规则的时候,接下来要做的当然就是重刷转发规则了。
在ES client转发均衡了之后,我们在ES data单节点上又看到CPU使用率过高。由于ES data在POD当中,我们自然就要想到去看cgroup的限制。
而在添加了CPU之后,我们发现TPS并没有提高,这时候就要去看ES的逻辑了。ES的强大之处就在于多副本多分片的查询能力,所以,我们增加了副本之后,CPU就用起来了,这是一个合理的优化结果,TPS也自然提高了。
经过一系列操作,终于把资源用起来。性能优化第一个阶段的目标,就是把资源给用起来,再考虑更细节优化。
性能调优要先将资源利用起来,这资源使用到达多少就算是合理了,比如CPU,有些系统是80%,有些可到100,怎么衡量?
要分析资源是用到哪里才能判断合理不合理。在性能测试中,可以用到100%,但生产上不可以。所以资源使用到多少要看场景和业务影响。
标签:10.100,data,性能,接口,elasticsearch,系统资源,KUBE,true,ES From: https://blog.51cto.com/u_11440114/6176583