流量镜像,也称为影子流量,流量镜像提供一种尽量低的风险为生产带来变化的强大功能。镜像会将实时流量的副本发送到镜像服务。镜像流量发生在主服务的关键请求路径以外。nginx
在非生产或者测试环境中,尝试访问一个服务全部可能的测试用例组合是个很是不现实的任务。 在某些状况下,编写这些用例的全部工做也可能与实际生产所需的用例不匹配。在理想状况下,可使用实时的生产用例和流量来帮助完善在测试环境中错过的功能区域。git
一旦咱们可以可靠地镜像流量,就能够开始作一些有价值的事情,例如经过请求流量对比工具Diffy,能够将引入测试集群的流量与生产集群中的预期行为进行比较。例如,咱们可能想比较请求结果与预期结果间的误差,或是API协议中的数据损坏状况,以便更好地兼容。
除此以外,须要注意:github
此处,插入一个代理就能够负责此类流量的协调,并对其进行有趣的比较。Diffy就是一款这样的代理工具。Diffy启动一个代理服务(例如监听端口8880),再根据用户设置的primary、secondary两个旧服务地址(primary和secondary代码彻底相同,目的是为了减小噪音干扰)、candidate新服务地址。docker
它还可以检测结果中的噪音,并经过先调用两个实时服务的实例来忽略它们(例如时间戳,单调递增计数器等提示),总结来讲就是检测,而后在测试服务中忽略掉这部分。api
Diffy还提供了一个不错的页面能够用来查看调用结果、对比状况、和基于某些特征的过滤。它还有一个很好的管理控制台,能够查看有关调用比较结果的功能指标(metrics)和统计数据(statistics)。微信
在此任务中,将首先强制全部流量到 v1 版本的服务。而后,将使用规则将一部分流量镜像到 v2版本。并发
首先部署两个版本的示例服务。app
版本1的部署使用了Docker镜像httpbin,提供常见的http请求访问:负载均衡
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: mirrorservice-sample-v1 spec: replicas: 1 template: metadata: labels: app: mirrorservice-sample version: v1 spec: containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: mirrorservice-sample command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:44134", "httpbin:app"] ports: - containerPort: 44134
版本2的部署使用了自定义的Docker镜像,对应的Dockerfile以下:curl
FROM nginx:latest COPY default.conf /etc/nginx/conf.d/ EXPOSE 80
所需的nginx 配置文件:
server { listen 44134; server_name localhost; location / { proxy_pass http://httpbin-diffy.diffy:8880/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }
版本2的部署做为Istio的流量镜像目标,在接收到流量以后会转发到Diffy的代理中。当前没有直接将Diffy代理做为Isito流量镜像目标,缘由是Diffy代理与Envoy代理目前自己有冲突,没法正常流量转发,所以须要此部署中转一下。
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: mirrorservice-sample-v2 spec: replicas: 1 template: metadata: labels: app: mirrorservice-sample version: v2 spec: containers: - name: mirrorservice-sample image: registry.cn-beijing.aliyuncs.com/wangxining/mirrorservice:0.1 imagePullPolicy: Always ports: - containerPort: 44134
对应的Kubernetes service:
apiVersion: v1 kind: Service metadata: name: mirrorservice-sample spec: type: ClusterIP ports: - name: http port: 44134 selector: app: mirrorservice-sample
默认状况下,Kubernetes 在服务的两个版本之间进行负载均衡。建立以下流量镜像规则将 100% 的流量发送到 v1, 同时指定流量镜像到v2。当流量被镜像时,请求将经过其主机/受权报头发送到镜像服务附上 -shadow 。
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: mirrorservice-sample spec: host: mirrorservice-sample subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: mirrorservice-sample spec: hosts: - mirrorservice-sample http: - route: - destination: host: mirrorservice-sample subset: v1 weight: 100 #- destination: # host: mirrorservice-sample # subset: v2 # weight: 0 mirror: host: mirrorservice-sample subset: v2
Diffy能够做为代理,截取请求并发送至全部运行的服务实例,经过对比响应结果来发现每次迭代代码中可能存在的问题。其中,Diffy上运行了三类代码实例:
在实际Diffy测试中,会发现大部分的接口都会有必定差别,缘由是这些响应中存在了噪音,噪音可能包括:
Diffy可以经过必定的方式,清除这类噪音,保证分析结果不被影响。
经过如下YAML建立Diffy服务:
apiVersion: v1 kind: Service metadata: name: httpbin-diffy labels: app: httpbin-diffy spec: ports: - name: http-proxy port: 8880 - name: http-admin port: 8881 - name: http-console port: 8888 selector: app: httpbin-diffy --- apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: app: httpbin-diffy version: v2 name: httpbin-diffy-v2 spec: replicas: 1 selector: matchLabels: app: httpbin-diffy version: v2 template: metadata: labels: app: httpbin-diffy version: v2 spec: containers: - image: lordofthejars/diffy:1.0 imagePullPolicy: IfNotPresent livenessProbe: exec: command: - curl - localhost:8888 initialDelaySeconds: 10 periodSeconds: 60 timeoutSeconds: 1 name: httpbin-diffy args: ["-candidate=httpbin-candidate:8080", "-master.primary=httpbin-master:8080", "-master.secondary=httpbin-master:8080", "-service.protocol=http", "-serviceName=httpbin", "-proxy.port=:8880", "-admin.port=:8881", "-http.port=:8888", "-rootUrl='localhost:8888'"] ports: - containerPort: 8888 name: http-console protocol: TCP - containerPort: 8880 name: http-proxy protocol: TCP - containerPort: 8881 name: http-admin protocol: TCP readinessProbe: exec: command: - curl - localhost:8888 initialDelaySeconds: 10 periodSeconds: 60 timeoutSeconds: 1 securityContext: privileged: false
经过如下YAML建立示例所用的primary、secondary(当前示例中与primary相同)与candidate服务:
apiVersion: v1 kind: Service metadata: name: httpbin-master labels: app: httpbin-master spec: ports: - name: http port: 8080 selector: app: httpbin version: v1 --- apiVersion: v1 kind: Service metadata: name: httpbin-candidate labels: app: httpbin-candidate spec: ports: - name: http port: 8080 selector: app: httpbin version: v2 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: httpbin-v1 spec: replicas: 1 template: metadata: labels: app: httpbin version: v1 spec: containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:8080", "httpbin:app"] ports: - containerPort: 8080 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: httpbin-v2 spec: replicas: 1 template: metadata: labels: app: httpbin version: v2 spec: containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:8080", "httpbin:app"] ports: - containerPort: 8080
启动 sleep 服务,这样就可使用 curl 来提供负载:
cat <<EOF | istioctl kube-inject -f - | kubectl create -f - apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sleep spec: replicas: 1 template: metadata: labels: app: sleep spec: containers: - name: sleep image: tutum/curl command: ["/bin/sleep","infinity"] imagePullPolicy: IfNotPresent EOF
进入到SLEEP_POD, 具体POD名称根据实际赋值。
kubectl exec -it $SLEEP_POD -c sleep sh
发送流量:
curl -v http://mirrorservice-sample:44134/headers
能够查看 v1的访问日志记录,以下所示建立的请求100%指向了v1。
与此同时,查看Diffy的Web界面,能够看到建立的请求也被镜像到Diffy Proxy:
Diffy可以经过必定的方式,清除这类噪音,保证分析结果不被影响。
流量镜像提供一种尽量低的风险为生产带来变化的强大功能。镜像会将实时流量的副本发送到镜像服务,镜像流量发生在主服务的关键请求路径以外。一旦咱们可以可靠地镜像流量,就能够开始作一些有价值的事情,例如经过请求流量对比工具Diffy,能够将引入测试集群的流量与生产集群中的预期行为进行比较。
支持流量镜像只是 Istio 的众多功能之一,它将使基于大型微服务的应用程序的生产部署与管理变得更加简单。欢迎你们使用阿里云上的容器服务,快速搭建微服务的开放治理平台Istio,比较简单地集成到本身项目的微服务开发中。
原文连接 更多技术干货 请关注阿里云云栖社区微信号 :yunqiinsight