断路器是创建弹性微服务应用程序的重要模式。断路器使应用程序可以适应网络故障和延迟等网络不良影响。
测试断路器:
1、在 k8s 集群创建后端服务
[root@k8smaster ~]# cd istio-1.10.1
[root@k8smaster istio-1.10.1]# cat samples/httpbin/httpbin.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
#把 httpbin.tar.gz 上传到node1,手动解压:
[root@k8snode1 ~]# cd istio/
[root@k8snode1 istio]# docker load -i httpbin.tar.gz
[root@k8smaster istio-1.10.1]# kubectl apply -f samples/httpbin/httpbin.yaml
#该 httpbin 应用程序充当后端服务。
2、配置断路器
创建一个目标规则,在调用 httpbin 服务时应用断路器设置:
[root@k8smaster istio-1.10.1]# vim destination.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1
http:
http1MaxPendingRequests: 1
maxRequestsPerConnection: 1
outlierDetection:
consecutiveGatewayErrors: 1
interval: 1s
baseEjectionTime: 3m
maxEjectionPercent: 100
连接池(TCP | HTTP)配置,例如:连接数、并发请求等
tcp:
maxConnections: 1
TCP 连接池中的最大连接请求数,当超过这个值,会返回 503 代码。如两个请求过来,就会有一个请求返回 503。
http:
http1MaxPendingRequests: 1
连接到目标主机的最大挂起请求数,也就是待处理请求数。这里的目标指的是 virtualservice 路由规则中配置的 destination。
maxRequestsPerConnection: 1
连接池中每个连接最多处理 1 个请求后就关闭,并根据需要重新创建连接池中的连接
outlierDetection:
异常检测配置,传统意义上的熔断配置,即对规定时间内服务错误数的监测
consecutiveGatewayErrors: 1
#连续错误数 1,即连续返回 502-504 状态码的 Http 请求错误数
interval: 1s
错误异常的扫描间隔 1s,即在 interval(1s)内连续发生 consecutiveGatewayErrors(1)个错误,则触发服务熔断
baseEjectionTime: 3m
基本驱逐时间 3 分钟,实际驱逐时间为 baseEjectionTime*驱逐次数
maxEjectionPercent: 100
最大驱逐百分比 100%
[root@k8smaster istio-1.10.1]# kubectl apply -f destination.yaml
3、添加客户端访问 httpbin 服务
创建一个客户端以将流量发送给 httpbin 服务。该客户端是一个简单的负载测试客户端,Fortio 可以控制连接数,并发数和 HTTP 调用延迟。使用此客户端来“跳闸”在 DestinationRule 中设置的断路器策略。看看熔断能不能启动。
#通过执行下面的命令部署 fortio 客户端:
#把 fortio.tar.gz 上传到 node1 节点,手动解压:
[root@k8snode1 istio]# docker load -i fortio.tar.gz
[root@k8smaster istio-1.10.1]# kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml
#通过 kubectl 执行下面的命令,使用 fortio 客户端工具调用 httpbin:
[root@k8smaster istio-1.10.1]# kubectl get pods
NAME READY STATUS RESTARTS AGE
appv1-6f7b58fd99-xb4br 2/2 Running 0 3h55m
appv2-f78cb577-s6d4z 2/2 Running 0 3h55m
details-v1-65bbfd4f58-7w985 2/2 Running 2 5h4m
fortio-deploy-576dbdfbc4-hgfqj 2/2 Running 0 2m29s
httpbin-74fb669cc6-b25f8 2/2 Running 0 15m
productpage-v1-6b746f74dc-hxn89 2/2 Running 2 5h4m
ratings-v1-b45758b-kz668 2/2 Running 2 5h4m
reviews-v1-74894b48c8-g8nv8 2/2 Running 2 5h4m
reviews-v2-f649764d-2lc54 2/2 Running 2 5h4m
reviews-v3-6c675c6774-smbvr 2/2 Running 2 5h4m
#进入fortio然后使用curl请求httpdbin
[root@k8smaster istio-1.10.1]# kubectl exec fortio-deploy-5789d79849-4grn4 -c fortio -- /usr/bin/fortio curl http://httpbin:8000/get
#显示如下:
HTTP/1.1 200 OK
server: envoy
date: Mon, 08 Aug 2022 12:34:48 GMT
content-type: application/json
content-length: 622
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 2
4、触发断路器
在 DestinationRule 设置中,指定了 maxConnections: 1 和 http1MaxPendingRequests: 1。这些规则表明,如果超过一个以上的连接并发请求,则 istio-proxy 在为进一步的请求和连接打开路由时,应该会看到下面的情况。
模拟多个客户端发送请求,以两个并发连接(-c 2)和发送 20 个请求(-n 20)调用服务:
[root@k8smaster istio-1.10.1]# kubectl exec -it fortio-deploy-576dbdfbc4-z28m7 -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
#显示如下:
一大堆503
Jitter: false
Code 200 : 4 (20.0 %)
Code 503 : 16 (80.0 %)
#只有20%成功了,其余的都断开了,每次请求都不一样,断路器触发了。
在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性,Istio 使用虚拟服务来优雅实现超时处理。
下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。nginx 服务设置了超时时间为 2 秒,如果超出这个时间就不在等待,返回超时错误。tomcat 服务设置了响应时间延迟 10 秒,任何请求都需要等待 10 秒后才能返回。client 通过访问 nginx 服务去反向代理 tomcat 服务,由于 tomcat 服务需要 10 秒后才能返回,但 nginx 服务只等待 2 秒,所以客户端会提示超时错误。
node1解压tomcat,nginx,busybox
[root@k8snode1 ~]# docker load -i nginx
[root@k8snode1 ~]# docker load -i busybox:1.2.8
[root@k8snode1 ~]# docker load -i tomcat
[root@k8smaster ~]# mkdir /root/timeout
[root@k8smaster ~]# cd /root/timeout/
[root@k8smaster timeout~]# vim nginx-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-tomcat
labels:
server: nginx
app: web
spec:
replicas: 1
selector:
matchLabels:
server: nginx
app: web
template:
metadata:
name: nginx
labels:
server: nginx
app: web
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
replicas: 1
selector:
matchLabels:
server: tomcat
app: web
template:
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
containers:
- name: tomcat
image: docker.io/kubeguide/tomcat-app:v1
imagePullPolicy: IfNotPresent
[root@k8smaster timeout]# vim nginx-tomcat-svc.yaml
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
server: nginx
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
server: tomcat
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP
[root@k8smaster timeout]# vim virtual-tomcat.yaml
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
timeout: 2s
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault:
delay:
percentage:
value: 100
fixedDelay: 10s
route:
- destination:
host: tomcat-svc
#virtual-tomcat.yaml 资源清单重点知识讲解
第一:故障注入
http:
- fault:
delay:
percentage:
value: 100
fixedDelay: 10s
该设置说明每次调用 tomcat-svc 的 k8s service,都会延迟 10s 才会调用。
第二:调用超时
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
timeout: 2s
该设置说明调用 nginx-svc 的 k8s service,请求超时时间是 2s。
#部署 tomcat、nginx 服务
需要对 nginx-deployment.yaml 资源文件进行 Istio 注入,将 nginx、tomcat 都放入到网格中,可以采用手工注入 Istio 方式。
[root@k8smaster timeout]# kubectl apply -f nginx-deployment.yaml
执行成功后,通过 kubectl get pods 查看 Istio 注入情况:
[root@k8smaster timeout]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-tomcat-7dd6f74846-48g9f 2/2 Running 0 5h15m
tomcat-86ddb8f5c9-h6jdl 2/2 Running 0 5h15m
#部署 nginx 和 tomcat 的 service
[root@k8smaster timeout]# kubectl apply -f nginx-tomcat-svc.yaml
#部署虚拟服务
[root@k8smaster timeout]# kubectl apply -f virtual-tomcat.yaml
#设置超时时间
[root@k8smaster timeout]# kubectl exec -it nginx-tomcat-7dd6f74846-48g9f -- sh
# apt-get update
# apt-get install vim -y
# vim /etc/nginx/conf.d/default.conf
在location里把root和index注释掉,然后加下面两行反向代理的
proxy_pass http://tomcat-svc:8080;
proxy_http_version 1.1;
编辑完后,再执行如下语句验证配置和让配置生效:
/ # nginx -t
/ # nginx -s reload
这样,整个样例配置和部署都完成了。
#验证超时
登录 client,执行如下语句:
[root@k8smaster timeout]# kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh
/ # time wget -q -O - http://nginx-svc
#网关超时了
wget: server returned error: HTTP/1.1 408 Request Timeout
Command exited with non-zero status 1
real 0m 2.02s
user 0m 0.00s
sys 0m 0.00s
/ # while true; do wget -q -O - http://nginx-svc; done
wget: server returned error: HTTP/1.1 504 Gateway Timeout
wget: server returned error: HTTP/1.1 504 Gateway Timeout
wget: server returned error: HTTP/1.1 504 Gateway Timeout
wget: server returned error: HTTP/1.1 504 Gateway Timeout
wget: server returned error: HTTP/1.1 408 Request Timeout
每隔 2 秒,由于 nginx 服务的超时时间到了而 tomcat 未有响应,则提示返回超时错误。
验证故障注入效果,执行如下语句:
/ # time wget -q -O - http://tomcat-svc
wget: server returned error: HTTP/1.1 503 Service Unavailable
Command exited with non-zero status 1
real 0m 10.02s
user 0m 0.00s
sys 0m 0.01s
执行之后 10s 才会有结果
Istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务,除非我们启动 Istio 重试机制。
下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。tomcat 通过故障注入而中止对外服务,nginx 设置如果访问 tomcat 失败则会重试 3 次。
[root@k8smaster timeout]# kubectl delete -f .
[root@k8smaster timeout]# kubectl apply -f nginx-deployment.yaml
[root@k8smaster timeout]# kubectl apply -f nginx-tomcat-svc.yaml
[root@k8smaster timeout]# vim virtual-attempt.yaml
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
retries:
attempts: 3
perTryTimeout: 2s
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault:
abort:
percentage:
value: 100
httpStatus: 503
route:
- destination:
host: tomcat-svc
[root@k8smaster timeout]# kubectl apply -f virtual-attempt.yaml
虚拟服务资源清单解读:
第一:故障注入。该虚拟服务的作用对象就是 tomcat-svc。使用此故障注入后,在网格中该 tomcat 就是不可用的。
abort:
percentage:
value: 100
httpStatus: 503
abort 是模拟 tomcat 服务始终不可用,该设置说明每次调用 tomcat-svc 的 k8s service,100%都会返回错误状态码 503。
第二:调用超时:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
reties:
attempts: 3
perTryTimeout: 2s
该设置说明调用 nginx-svc 的 k8s service,在初始调用失败后最多重试 3 次来连接到服务子集,每个重试都有 2 秒的超时。
[root@k8smaster timeout]# kubectl exec -it nginx-tomcat-3da6f82051-rdqqf -- /bin/sh
# apt-get update
# apt-get install vim -y
/ # vim /etc/nginx/conf.d/default.conf
在location里把root和index注释掉,然后加下面两行反向代理的
proxy_pass http://tomcat-svc:8080;
proxy_http_version 1.1;
/ # nginx -t
/ # nginx -s reload
#验证重试是否生效
[root@k8smaster timeout]# kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh
/ # wget -q -O - http://nginx-svc
[root@xianchaomaster1 timeout]# kubectl logs -f nginx-tomcat-3da6f82051-rdqqf -c istio-proxy
可以看到重试三次
分布式追踪最早由谷歌的 Dapper 普及开来,它本质上是具有在微服务的整个生命周期中追踪请求的能力。分布式追踪(Distributed Tracing)主要用于记录整个请求链的信息。
当业务微服务化后,一次业务请求,可能会涉及到多个微服务,分布式跟踪可以对跨多个分布式服务网格的 1 个请求进行追踪分析,并通过可视化的方式深入地了解请求的延迟,序列化和并发,充分地了解服务流量实况,从而快速地排查和定位问题。在微服务应用中,一个完整的业务往往需要调用多个服务才能完成,服务之间就产生了交互。当出现故障时,如何找到问题的根源非常重要。追踪系统可以清晰地展示出请求的整个调用链以及每一步的耗时,方便查找问题所在。
Jaeger 是一个开源的分布式追踪系统,它可以在复杂的分布式系统中进行监控和故障排查。Jaeger的主要功能包括分布式请求监控、性能调优、故障分析和服务依赖分析等。
Jaeger 组件介绍:
jaeger-agent:
负责发送的进程,对 spans 进行处理并发送给 collector,监听 spans 的 UDP 发送。这层作为基础组件部署在主机上,Agent 将 Client Library 和 Collector 解耦,为 ClientLibrary 屏蔽了路由和发现 Collector 的细节。
jaeger-collector:
收集追踪 spans,并通过管道对追踪数据进行处理。当前的管道支持追踪的验证、索引、转换,最后存储数据。
jaeger-query:
从存储中检索追踪信息并通过 UI 展示
data store:
追踪信息的存储
kubectl get svc -n istio-system | grep jaeger
显示如下:
jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP 55d
jaeger-collector ClusterIP 10.99.194.57 <none> 14267/TCP,14268/TCP,14250/TCP 55d
jaeger-collector-headless ClusterIP None <none> 14250/TCP 55d
jaeger-query ClusterIP 10.107.192.115 <none> 16686/TCP
修改 jaeger-query 的 type 类型为 nodePort
kubectl edit svc jaeger-query -n istio-system
把 type: ClusterIP 变成 type: NodePort
kubectl get svc -n istio-system | grep jaeger-query
显示如下:
jaeger-query NodePort 10.107.192.115 <none> 16686:31450/TCP
在浏览器访问:
192.168.11.129:31450
Istio 利用 Envoy 的分布式追踪功能提供了开箱即用的追踪集成。确切地说,Istio 提供了安装各种追踪后端服务的选项,并且通过配置代理来自动发送追踪 span 到追踪后端服务。尽管 Istio 代理能够自动发送 span,但是他们需要一些附加线索才能将整个追踪链路关联到一起。所以当代理发送 span 信息的时候,应用需要附加适当的 HTTP 请求头信息,这样才能够把多个 span 正确的关联到同一个追踪上。
要做到这一点,应用程序从传入请求到任何传出的请求中需要包含以下请求头参数:
x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context
创作不易,如果觉得内容对你有帮助,麻烦给个三连关注支持一下我!如果有错误,请在评论区指出,我会及时更改!istio系列也算完结了,后面会补充一些k8s篇的遗漏知识点。
感谢各位的观看,文章掺杂个人理解,如有错误请联系我指出~