# 15 | 查询商品:资源不足有哪些性能表现? 你好,我是高楼。 这节课,我们来收拾“查询商品”这个接口。虽然这次的现象同样是TPS低、响应时间长,但是,这个接口走的路径和之前的不一样,所以在分析过程中会有些新鲜的东西,你将看到在资源真的不足的情况下,我们只有增加相应节点的资源才能提升性能。 在我的项目中,我一直都在讲,**不要轻易给出资源不足的结论。因为但凡有优化的空间,我们都要尝试做优化,而不是直接告诉客户加资源。而给出“增加资源”这个结论,也必须建立在有足够证据的基础上**。在这节课中,你也将看到这一点。 话不多说,我们直接开始今天的内容。 ## 压力场景数据 对于查询商品接口,我们第一次试执行性能场景的结果如下: ![](https://static001.geekbang.org/resource/image/75/a2/75ef8d040cdbcef4556bbfa7fd7098a2.png) 你看,TPS只有250左右,并且响应时间也明显随着压力的增加而增加了,看起来瓶颈已经出现了,对吧?根据哥的逻辑,下一步就是看架构图啦。 ## 先看架构图 我们用APM工具来看看这个接口的架构。 ![](https://static001.geekbang.org/resource/image/6b/70/6bcbe3236d91fd7628fa5a6186243870.png) 你看,从压力机到Gateway服务、到Search服务、再到ES-Client,这个APM工具也只能帮我们到这里了。因为我们用的是ElasticSearch 7来做的搜索服务的支撑,而这个skywalking工具也没有对应的Agent,所以后面并没有配置skywalking。 在这里,我要多啰嗦几句。现在的APM工具大多是基于应用层来做的,有些运维APM采集的数据会更多一些,但也是响应时间、吞吐量等这样的信息。对于性能分析而言,现在的APM工具有减少排查时间的能力,但是在组件级的细化定位上还有待提高。虽然AI OPS也被提到了台面,但是也没见过哪个公司上了AIOPS产品后,就敢不让人看着。 总之,从细化分析的角度,我们在定位问题的根本原因时,手头有什么工具就可以用什么工具,即使什么工具都没有,撸日志也是照样能做到的,所以我建议你不要迷信工具,要“迷信”思路。 下面我们来拆分下这个接口的响应时间,看看这个案例的问题点在哪里。 ## 拆分响应时间 **“在RESAR性能分析逻辑中,拆分响应时间只是一个分析的起点**。”这是我一直在强调的一句话。如果性能工程师连这个都不会做,就只能好好学习天天向上了。 根据架构图,我们拆分响应时间如下。 * Gateway服务上的响应时间: ![](https://static001.geekbang.org/resource/image/dc/0d/dc64c9e8ace689c86d6584b64f9f230d.png) * Search服务上的响应时间: ![](https://static001.geekbang.org/resource/image/a6/c9/a6dc83d1b51445464d3db3e5421798c9.png) * ES Client的响应时间: ![](https://static001.geekbang.org/resource/image/0b/81/0b168cdd73f30b5565c52a6d97b45081.png) 一层层看过之后,我们发现查询商品这个接口的响应时间消耗在了ES client上面。而在我们这个查询的路径上,在gateway/search服务上,我们并没有做什么复杂的动作。 既然知道了响应时间消耗在哪里,下面我们就来定位它,看能不能把TPS优化起来。 ## 全局监控 根据高老师的经验,我们还是从全局监控开始,看全局监控可以让我们更加有的放矢。在分析的过程中,经常有人往下走了几步之后,就开始思维混乱、步伐飘逸。因为数据有很多,所以分析时很容易从一个数据走到不重要的分支上去了。而这时候,如果你心里有全局监控数据,思路就会更清晰,不会在无关的分支上消耗时间。 回到我们这个例子中,从下面的k8s worker(也就是k8s中的node,在我们的环境中我习惯叫成worker,就是为了体现:在我的地盘,我爱叫啥就叫啥)的数据上来看,似乎没有一个worker的资源使用率是特别高的。 ![](https://static001.geekbang.org/resource/image/25/e5/25bb0386561be19b9615a4b0130fe4e5.png) 请你注意,在k8s中看资源消耗,一定不要只看worker这个层面,因为这个层面还不够,一个worker上可能会运行多个pod。从上图来看,由于worker层面没有资源消耗,但是时间又明显是消耗在ES client上的,所以,接下来我们要看一下每一个pod的资源使用情况。 ![](https://static001.geekbang.org/resource/image/13/f3/13f919d42a29f2d37f699036658006f3.png) 咦,有红色。你看,有两个与ES相关的POD,它们的CPU都飘红了,这下可有得玩了。既然是与ES相关的POD,那我们就把ES所有的POD排个序看看。 ![](https://static001.geekbang.org/resource/image/62/bd/624d7bc2fe25f731aa42037d8d9f29bd.png) 从上图的数据来看,有一个ES Client 消耗了67%的CPU,有两个ES Data消耗了99%的CPU,ES本来就是吃CPU的大户,所以我们接下来要着重分析它。 这里我再说明一点,我们从前面的worker资源使用率一步一步走到这里,在分析方向上是合情合理的,因为这些都是属于我提到的全局监控的内容。 ## 定向分析 现在我们就来扒一扒ES,看看它在哪个worker节点上。罗列Pod信息如下: ``` [root@k8s-master-1 ~]# kubectl get pods -o wide | grep elasticsearch elasticsearch-client-0 1/1 Running 0 6h43m 10.100.230.2 k8s-worker-1 elasticsearch-client-1 1/1 Running 0 6h45m 10.100.140.8 k8s-worker-2 elasticsearch-data-0 1/1 Running 0 7h8m 10.100.18.197 k8s-worker-5 elasticsearch-data-1 1/1 Running 0 7h8m 10.100.5.5 k8s-worker-7 elasticsearch-data-2 1/1 Running 0 7h8m 10.100.251.67 k8s-worker-9 elasticsearch-master-0 1/1 Running 0 7h8m 10.100.230.0 k8s-worker-1 elasticsearch-master-1 1/1 Running 0 7h8m 10.100.227.131 k8s-worker-6 elasticsearch-master-2 1/1 Running 0 7h8m 10.100.69.206 k8s-worker-3 [root@k8s-master-1 ~]# ``` 现在就比较清晰了,可以看到,在整个namespace中有两个ES client,三个ES data,三个ES master。 我们来画一个细一点的架构图,以便在脑子里记下这个逻辑: ![](https://static001.geekbang.org/resource/image/2e/0f/2e8a4fe8b5e214a8463d918dea8cyy0f.jpg) 再结合我们在全局分析中看到的资源使用率图,现在判断至少有两个问题: 1. ES client请求不均衡; 2. ES data CPU 高。 下面我们一个一个来分析。 ### ES client请求不均衡 从上面的架构图中可以看到,search服务连两个ES client,但是只有一个ES client的CPU使用率高。所以,我们需要查一下链路,看看ES的service: ``` [root@k8s-master-1 ~]# kubectl get svc -o wide | grep search elasticsearch-client NodePort 10.96.140.52 9200:30200/TCP,9300:31614/TCP 34d app=elasticsearch-client,chart=elasticsearch,heritage=Helm,release=elasticsearch-client elasticsearch-client-headless ClusterIP None 9200/TCP,9300/TCP 34d app=elasticsearch-client elasticsearch-data ClusterIP 10.96.16.151 9200/TCP,9300/TCP 7h41m app=elasticsearch-data,chart=elasticsearch,heritage=Helm,release=elasticsearch-data elasticsearch-data-headless ClusterIP None 9200/TCP,9300/TCP 7h41m app=elasticsearch-data elasticsearch-master ClusterIP 10.96.207.238 9200/TCP,9300/TCP 7h41m app=elasticsearch-master,chart=elasticsearch,heritage=Helm,release=elasticsearch-master elasticsearch-master-headless ClusterIP None 9200/TCP,9300/TCP 7h41m app=elasticsearch-master svc-mall-search ClusterIP 10.96.27.150 8081/TCP 44d app=svc-mall-search [root@k8s-master-1 ~]# ``` 你看,整个namespace中有一个client service(解析出来的是VIP,访问此服务时不会绕过K8s的转发机制),还有一个client-headless service(解析出来的是POD IP,访问这个服务时会绕过K8s的转发机制)。 接下来,我们查一下为什么会出现访问不均衡的情况。 通过查看search服务的ES配置,我们看到如下信息: ``` elasticsearch: rest: uris: elasticsearch-client:9200 username: elastic password: admin@123 ``` 看到我们这里是用的elasticsearch-client:9200,我们再来看一下client service的配置: ``` --- apiVersion: v1 kind: Service metadata: annotations: meta.helm.sh/release-name: elasticsearch-client meta.helm.sh/release-namespace: default creationTimestamp: '2020-12-10T17:34:19Z' labels: app: elasticsearch-client app.kubernetes.io/managed-by: Helm chart: elasticsearch heritage: Helm release: elasticsearch-client managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: 'f:metadata': {} 'f:spec': 'f:ports': {} manager: Go-http-client operation: Update time: '2020-12-10T17:34:19Z' name: elasticsearch-client namespace: default resourceVersion: '4803428' selfLink: /api/v1/namespaces/default/services/elasticsearch-client uid: 457e962e-bee0-49b7-9ec4-ebfbef0fecdd spec: clusterIP: 10.96.140.52 externalTrafficPolicy: Cluster ports: - name: http nodePort: 30200 port: 9200 protocol: TCP targetPort: 9200 - name: transport nodePort: 31614 port: 9300 protocol: TCP targetPort: 9300 selector: app: elasticsearch-client chart: elasticsearch heritage: Helm release: elasticsearch-client sessionAffinity: None type: NodePort ``` 从上面的配置来看,sessionAffinity也配置为None了,也就是说这个service不以客户端的IP来保持session。因为在这个环境配置中,Type为NodePort,而我们在k8s中配置的转发规则是iptables。所以说,service是依赖iptables的规则来做后端转发的。 接下来,我们检查一下iptables的转发规则。 我们先来看iptables中关于ES client的规则: ``` [root@k8s-master-1 ~]# iptables -S KUBE-SERVICES -t nat|grep elasticsearch-client|grep 9200 -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-MASQ -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-XCX4XZ2WPAE7BUZ4 [root@k8s-master-1 ~]# ``` 可以看到,service的规则名是KUBE-SVC-XCX4XZ2WPAE7BUZ4,那我们再去查它对应的iptables规则: ``` [root@k8s-master-1 ~]# iptables -S KUBE-SVC-XCX4XZ2WPAE7BUZ4 -t nat -N KUBE-SVC-XCX4XZ2WPAE7BUZ4 -A KUBE-SVC-XCX4XZ2WPAE7BUZ4 -m comment --comment "default/elasticsearch-client:http" -j KUBE-SEP-LO263M5QW4XA6E3Q [root@k8s-master-1 ~]# [root@k8s-master-1 ~]# iptables -S KUBE-SEP-LO263M5QW4XA6E3Q -t nat -N KUBE-SEP-LO263M5QW4XA6E3Q -A KUBE-SEP-LO263M5QW4XA6E3Q -s 10.100.227.130/32 -m comment --comment "default/elasticsearch-client:http" -j KUBE-MARK-MASQ -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规则: ``` [root@k8s-master-1 ~]# iptables -S KUBE-SVC-XCX4XZ2WPAE7BUZ4 -t nat -N KUBE-SVC-XCX4XZ2WPAE7BUZ4 -A KUBE-SVC-XCX4XZ2WPAE7BUZ4 -m comment --comment "default/elasticsearch-client:http" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-IFM4L7YNSTSJP4YT -A KUBE-SVC-XCX4XZ2WPAE7BUZ4 -m comment --comment "default/elasticsearch-client:http" -j KUBE-SEP-5RAP6F6FATXC4DFL [root@k8s-master-1 ~]# ``` 哟,现在刷出来两条iptables规则了,看来之前在我们不断折腾的部署过程中,ES client一直是有问题的。 在上面的iptables规则里,那两条iptables的上一条中有一个关键词“——probability 0.50000000000”。我们知道,iptables的匹配规则是从上到下的,既然上一条的匹配是随机0.5,也就是说只有50%的请求会走第一条规则,那下一条自然也是随机0.5了,因为总共只有两条规则嘛。这样一来就均衡了。 我们再接着做这个接口的压力场景,看到如下信息: ![](https://static001.geekbang.org/resource/image/40/67/408592f11401e1yyb1c06ef48f3f8167.png) 看起来ES client均衡了,对不对? 它对应的TPS,如下: ![](https://static001.geekbang.org/resource/image/61/99/614e849f975cf983747e080329c0d699.png) 明显TPS提升了60左右。 ES client请求不均衡的问题解决了,现在,我们还要来看一下ES data单节点CPU高的问题。 ### ES Data CPU使用率高 * **第一阶段:加一个CPU** 在TPS提升之后,我们再来看一下全局监控数据。 ![](https://static001.geekbang.org/resource/image/2e/79/2ec7cce680e81f57717c642cf7834279.png) 看起来比一开始好多了。基于前面分析ES client的经验,我们就先来查一下ES data的iptables规则: ``` -- 查看下有哪些ES data的POD [root@k8s-master-1 ~]# kubectl get pods -o wide | grep data elasticsearch-data-0 1/1 Running 0 10h 10.100.18.197 k8s-worker-5 elasticsearch-data-1 1/1 Running 0 10h 10.100.5.5 k8s-worker-7 elasticsearch-data-2 1/1 Running 0 10h 10.100.251.67 k8s-worker-9 -- 查看ES data对应的iptables规则 [root@k8s-master-1 ~]# iptables -S KUBE-SERVICES -t nat|grep elasticsearch-data -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-MASQ -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-4LU6GV7CN63XJXEQ -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-MASQ -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-W4QKPGOO4JGYQZDQ -- 查看9200(外部通信)对应的规则 [root@k8s-master-1 ~]# iptables -S KUBE-SVC-4LU6GV7CN63XJXEQ -t nat -N KUBE-SVC-4LU6GV7CN63XJXEQ -A KUBE-SVC-4LU6GV7CN63XJXEQ -m comment --comment "default/elasticsearch-data:http" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-ZHLKOYKJY5GV3ZVN -A KUBE-SVC-4LU6GV7CN63XJXEQ -m comment --comment "default/elasticsearch-data:http" -m statistic --mode random --probability 1 -j KUBE-SEP-6ILKZEZS3TMCB4VJ -A KUBE-SVC-4LU6GV7CN63XJXEQ -m comment --comment "default/elasticsearch-data:http" -j KUBE-SEP-JOYLBDPA3LNXKWUK -- 查看以上三条规则的转发目标 [root@k8s-master-1 ~]# iptables -S KUBE-SEP-ZHLKOYKJY5GV3ZVN -t nat -N KUBE-SEP-ZHLKOYKJY5GV3ZVN -A KUBE-SEP-ZHLKOYKJY5GV3ZVN -s 10.100.18.197/32 -m comment --comment "default/elasticsearch-data:http" -j KUBE-MARK-MASQ -A KUBE-SEP-ZHLKOYKJY5GV3ZVN -p tcp -m comment --comment "default/elasticsearch-data:http" -m tcp -j DNAT --to-destination 10.100.18.197:9200 [root@k8s-master-1 ~]# iptables -S KUBE-SEP-6ILKZEZS3TMCB4VJ -t nat -N KUBE-SEP-6ILKZEZS3TMCB4VJ -A KUBE-SEP-6ILKZEZS3TMCB4VJ -s 10.100.251.67/32 -m comment --comment "default/elasticsearch-data:http" -j KUBE-MARK-MASQ -A KUBE-SEP-6ILKZEZS3TMCB4VJ -p tcp -m comment --comment "default/elasticsearch-data:http" -m tcp -j DNAT --to-destination 10.100.251.67:9200 [root@k8s-master-1 ~]# iptables -S KUBE-SEP-JOYLBDPA3LNXKWUK -t nat -N KUBE-SEP-JOYLBDPA3LNXKWUK -A KUBE-SEP-JOYLBDPA3LNXKWUK -s 10.100.5.5/32 -m comment --comment "default/elasticsearch-data:http" -j KUBE-MARK-MASQ -A KUBE-SEP-JOYLBDPA3LNXKWUK -p tcp -m comment --comment "default/elasticsearch-data:http" -m tcp -j DNAT --to-destination 10.100.5.5:9200 [root@k8s-master-1 ~] ``` Everything is perfect!!规则很合理。ES Data总共有三个pod,从逻辑上来看,它们各占了三分之一。 在前面的ES client分析中,我们讲到,第一个POD是0.5,下一条自然也只剩下0.5,这很容易理解。现在,ES data的部分有三条iptables规则,我们来简单说明一下。 > 通常我们理解的iptables就是一个防火墙。不过,要是从根本上来讲,它不算是一个防火墙,只是一堆规则列表,而通过iptables设计的规则列表,请求会对应到netfilter框架中去,而这个netfilter框架,才是真正的防火墙。其中,netfilter是处于内核中的,iptables就只是一个用户空间上的配置工具而已。 > 我们知道iptables有四表五链。四表是:fileter表(负责过滤)、nat表(负责地址转换)、mangle表(负责解析)、raw表(关闭nat表上启用的连接追踪);五链是:prerouting链(路由前)、input链(输入规则)、forward链(转发规则)、output链(输出规则)、postrouting链(路由后)。 > 而在这一部分,我们主要是看nat表以及其上的链。对于其他的部分,如果你想学习,可自行查阅iptables相关知识。毕竟,我还时刻记得自己写的是一个性能专栏,而不是计算机基础知识专栏,哈哈。 从上面的信息可以看到,我们的这个集群中有三个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规则可以实现负载均衡,画图理解如下: ![](https://static001.geekbang.org/resource/image/5e/88/5e9c08e967c62d9e9a84084d8c2de888.jpg) 我们假设有30个请求进来,那ES Data 0上就会有30x0.33333333349=10个请求;对于剩下的20个请求,在ES Data 1上就会有20x0.50000000000=10个请求;而最后剩下的10个请求,自然就到了ES Data 2上。这是一个非常均衡的逻辑,只是在iptables规则中,我看着这几个数据比例,实在是觉得别扭。 既然明白了这个逻辑,下面我们还是把查询商品接口的场景压起来看一下: ![](https://static001.geekbang.org/resource/image/06/49/06eb3b24a57226cd9a6717cd1e3f6049.png) 从数据上来看,经常会出现ES data 某个节点消耗CPU高的情况。可是,对应到我们前面看到的全局worker监控界面中,并没有哪个worker的CPU很高。所以,在这里,我们要查一下ES Data中的cgroup配置,看它的限制是多少。 ![](https://static001.geekbang.org/resource/image/8y/3c/8yyd469d83c9a346aff8c659f6c4ae3c.png) 也就是说,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%左右了,要是加多了,我怕它吃不消。 ![](https://static001.geekbang.org/resource/image/f5/01/f57acfca05yy43bd882a57404ea50d01.png) 看一下压力场景执行的效果: ![](https://static001.geekbang.org/resource/image/29/9c/299bbd39759ca90bdc4953334bc0c39c.png) 似乎……不怎么样?TPS并没有增加。 * **第二阶段:加副本** 我们再看加了CPU之后的全局POD监控: ![](https://static001.geekbang.org/resource/image/92/94/925d14923a3bfac75ef84b9b21622294.png) 还是只有一个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的资源: ![](https://static001.geekbang.org/resource/image/11/cc/11ayy743164f36a8d0b04bc76af52ccc.png) 现在看着是不是开心多了?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 elasticsearch-data-1 1/1 Running 0 17m 10.100.251.68 k8s-worker-9 elasticsearch-data-2 1/1 Running 0 18m 10.100.140.9 k8s-worker-2 ``` 现在ES Data的POD分布到2、5、9三这个worker上去了,我们查看下全局监控: ![](https://static001.geekbang.org/resource/image/53/b1/53a522a2754d7fcea550fde05cd791b1.png) 嗯,不错,ES data的POD把资源用起来了。其实这里要想继续调,还可以把CPU加大,ES本来就是吃CPU、内存的大户。不过,我们前面在配置的时候,给ES data的CPU也确实太小了。这个问题,并不是我故意设计出来的,而是当时在部署的时候,没考虑到这些。 最后,我们来看优化后的效果: ![](https://static001.geekbang.org/resource/image/1f/24/1fb93ff5yycfc2bb6049244820e73b24.png) 呀呀呀,你看TPS压都压不住呀,很快涨到900左右了!这个优化结果很好。 现在回过头来看第一个阶段,我们加CPU没有效果,主要还是因为副本数量太少。其实,在ES的优化中,还有很多细节可以玩。只不过,在我们这个课程中,我希望给你的是一个整体的分析思路和逻辑,而不是纠结于每个细节上的参数。所以,在这里,我们就不再说具体参数的调整了。 如果你想在ES上做更多的优化,可以在分析完业务之后,确定一下ES的架构、数据索引、分片等信息,然后再来设计一个合理的ES部署。 ## 总结 在这节课中,我们看到APM工具也有无能为力的地方。所以说,当我们分析到一个具体组件之后,要想再往下分析,就得靠自己的技术功底了。 在出现请求不均衡的时候,我们一定要先去看负载均衡的逻辑有没有问题。当看到ES client不均衡时,我们去看了iptables的原理,在发现iptables只有一个转发规则的时候,接下来要做的当然就是重刷转发规则了。 在ES client转发均衡了之后,我们在ES data单节点上又看到CPU使用率过高。由于ES data在POD当中,我们自然就要想到去看cgroup的限制。 而在添加了CPU之后,我们发现TPS并没有提高,这时候就要去看ES的逻辑了。ES的强大之处就在于多副本多分片的查询能力,所以,我们增加了副本之后,CPU就用起来了,这是一个合理的优化结果,TPS也自然提高了。 经过一系列的动作,我们终于把资源给用起来了。这也是我一直在强调的,**性能优化第一个阶段的目标,就是把资源给用起来,然后再考虑更细节的优化**。 ## 课后作业 最后,我给你留两道题,请你思考一下: 1. 当负载出现不均衡时,主要的分析方向是什么? 2. 什么时候才需要去看组件内部的实现逻辑? 记得在留言区和我讨论、交流你的想法,每一次思考都会让你更进一步。 如果你读完这篇文章有所收获,也欢迎你分享给你的朋友,共同学习进步。我们下一讲再见!