流量镜像

流量镜像,也称为影子流量,流量镜像提供一种尽可能低的风险为生产带来变化的强大功能。镜像会将实时流量的副本发送到镜像服务。镜像流量发生在主服务的关键请求路径之外。

在非生产或者测试环境中,尝试访问一个服务所有可能的测试用例组合是个非常不现实的任务。 在某些情况下,编写这些用例的所有工作也可能与实际生产所需的用例不匹配。在理想情况下,可以使用实时的生产用例和流量来帮助完善在测试环境中错过的功能区域。

一旦我们能够可靠地镜像流量,就可以开始做一些有价值的事情,例如通过请求流量对比工具Diffy,可以将引入测试集群的流量与生产集群中的预期行为进行比较。例如,我们可能想比较请求结果与预期结果间的偏差,或是API协议中的数据损坏情况,以便更好地兼容。
除此之外,需要注意:

  • 当流量镜像到不同的服务时,会发生在请求的关键路径之外;
  • 忽略对任何镜像流量的响应; 流量被视为“即发即忘”;

流量对比

此处,插入一个代理就可以负责此类流量的协调,并对其进行有趣的比较。Diffy就是一款这样的代理工具。Diffy启动一个代理服务(例如监听端口8880),再根据用户设置的primary、secondary两个旧服务地址(primary和secondary代码完全相同,目的是为了减少噪音干扰)、candidate新服务地址。

它还能够检测结果中的噪音,并通过先调用两个实时服务的实例来忽略它们(例如时间戳,单调递增计数器等提示),总结来说就是检测,然后在测试服务中忽略掉这部分。

Diffy还提供了一个不错的页面可以用来查看调用结果、对比情况、和基于某些特征的过滤。它还有一个很好的管理控制台,可以查看有关调用比较结果的功能指标(metrics)和统计数据(statistics)。

创建用于Istio流量镜像的服务

在此任务中,将首先强制所有流量到 v1 版本的服务。然后,将使用规则将一部分流量镜像到 v2版本。

首先部署两个版本的示例服务。

版本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如下:

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

创建流量镜像的Istio策略

默认情况下,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测试中,会发现大部分的接口都会有一定差异,原因是这些响应中存在了噪音,噪音可能包括:

  • server响应中生成的时间戳
  • 随机生成的数字
  • 系统服务间的有条件竞争

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

Istio流量管理实践之(3): 基于Istio实现流量对比分析的更多相关文章

  1. Istio最佳实践:在K8s上通过Istio服务网格进行灰度发布

    Istio是什么? Istio是Google继Kubernetes之后的又一开源力作,主要参与的公司包括Google,IBM,Lyft等公司.它提供了完整的非侵入式的微服务治理解决方案,包含微服务的管 ...

  2. 灵雀云Istio技术实践专题整理

    Istio技术实践专题(1) Service Mesh Istio 基本概念和架构基础 Istio被称作Kubernetes的最佳云原生拍档.从今天起,我们推出"Istio技术实践" ...

  3. Istio最佳实践系列:如何实现方法级调用跟踪?

    赵化冰,腾讯云高级工程师,Istio Member,ServiceMesher 管理委员,Istio 项目贡献者,热衷于开源.网络和云计算.目前主要从事服务网格的开源和研发工作. 引言 TCM(Ten ...

  4. Istio流量管理实现机制深度解析

    https://zhaohuabing.com/post/2018-09-25-istio-traffic-management-impl-intro/TOC 前言 Pilot高层架构 统一的服务模型 ...

  5. istio流量管理

    目录 1 准备工作 1.1 在k8s部署istio 1.2 istio自动注入 1.3 应用部署要求 2 负载均衡 3 流量迁移:金丝雀发布 3.1 发布应用 3.2 创建目标规则:Destinati ...

  6. Istio流量管理能力介绍

    1      Istio是什么? Istio 1.0版本于8月1号凌晨准点发布,核心特性已支持上生产环境,各大微信公众号.博客纷纷发文转载.那么Istio到底是什么?能解决问题什么? 1. Istio ...

  7. istio流量管理:非侵入式流量治理

    在服务治理中,流量管理是一个广泛的话题,一般情况下,常用的包括: 动态修改服务访问的负载均衡策略,比如根据某个请求特征做会话保持: 同一个服务有多版本管理,将一部分流量切到某个版本上: 对服务进行保护 ...

  8. 基于Istio构建微服务安全加固平台的探索

    简介 An open platform to connect, secure, control and observe services. Istio 是一个由谷歌.IBM 与Lyft共同开发的开源项 ...

  9. 【从小白到专家】收官!Istio技术实践之九:路由控制与灰度发布

    本期是Istio技术实践专题的最后一个模块,主题是Istio的路由控制与灰度发布.上一期我们讲到,虚拟服务(Virtual Service)以及目标规则(Destination Rule)是 Isti ...

随机推荐

  1. QQ空间删除日志

    按下F12,贴上如下代码 var delay = 2000; function del() { document.querySelector(".app_canvas_frame" ...

  2. thinkphp 规则路由

    规则路由是一种比较容易理解的路由定义方式,采用ThinkPHP设计的规则表达式来定义. 规则表达式 规则表达式通常包含静态地址和动态地址,或者两种地址的结合,例如下面都属于有效的规则表达式: 'my' ...

  3. HDU - 1560 DNA sequence

    给你最多8个长度不超过5的DNA系列,求一个包含所有系列的最短系列. 迭代加深的经典题.(虽然自己第一次写) 定一个长度搜下去,搜不出答案就加深大搜的限制,然后中间加一些玄学的减枝 //Twenty ...

  4. hdu多校第四场1001 (hdu6614) AND Minimum Spanning Tree 签到

    题意: 一个完全图,某两点边权为这两点编号之按位与,求最小生成树,输出字典序最小的. 题解: 如果点数不为$2^n-1$,则每一点均可找到一点,两点之间边权为0,只需找到该点二进制下其最左边的0是第几 ...

  5. php算法题---连续子数组的最大和

    php算法题---连续子数组的最大和 一.总结 一句话总结: 重要:一定要本机调试过了再提交代码,因为很容易出现考虑不周的情况,或者修改了之后没有考虑修改的这部分 利用空间来换时间,或者利用空间来换算 ...

  6. MAMP mysql无法启动 总结(以后有发现再添加)

    1.错误信息Can't start server : Bind on unix socket: Address already in use 解析:主要原因是上次关闭Mysql是出现异常而导致的, 解 ...

  7. MDK 添加芯片支持 以STM32F103ZE为例

    问题说明: 新建mdk工程时第一步是选芯片(以STM32F103ZE为例),但是芯片没有的话需要自己手动添加,如图: 解决方法: 下载KEIL MDK5以后是没有安装device的,如果此时创建工程会 ...

  8. 面试系列25 dubbo的spi思想是什么

    spi,简单来说,就是service provider interface,说白了是什么意思呢,比如你有个接口,现在这个接口有3个实现类,那么在系统运行的时候对这个接口到底选择哪个实现类呢?这就需要s ...

  9. (转)线程池 ExecutorService 详细介绍以及注意点区别

    线程池 ExecutorService 相信java开发都用到,这里做个简单笔记 一 Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池 ...

  10. 授权指定ip访问mysql 服务器

      授权指定ip访问访问 授权ROOT使用密码1234从应用服务器主机连接到mysql服务器 mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'xxx. ...