“故障注入 Sidecar“——为您的微服务注入故障以验证集群性能! 因为导师和实验室师兄们的科研须要,本人专门以 Sidecar
的模式设计了一个用于错误注入的微服务模块。该模块能够与任何微服务应用共同部署运行,为其模拟cpu、内存等错误。 本项目的 Github
地址: https://github.com/iscas-micr...
个人联系方式: leontian1024@gmail.com || 或直接留言 欢迎您提出问题批评指点!
目前,本人正在中科院软件所的微服务研究组从事部分研究工做。因为本人所在科研小组的研究内容( 微服务自动扩缩容相关 ),须要常常使微服务应用处于"高 CPU 利用率" 和 "高内存使用"的状态。所以,为了方便导师和实验室的各位师兄进行实验,本人特意开发了一个能够注入进 Pod 中的错误注入容器,来模拟上述的高负载状态。node
导师和师兄们使用后对个人工做给予了确定,所以我准备将开发过程和简单使用方法写成文章作个记录( 也就是本文 ),一来方便本身往后工做学习,二来也方便有相似实验需求的其余同仁们使用这个小项目,为你们的研究节省时间。更具体的安装和使用方法,能够移步本项目 Github 的代码仓库,其中有很是详细的说明。git
什么是微服务中的"Sidecar 运行模式?"github
上图: 以 Sidecar 模式部署并运行的微服务单元
Sidecar 运行模式是最近两年比较火的一种微服务部署和运行方法,它由目前流行的 ServiceMesh(服务网格) 架构推广而来。docker
具体而言,Sidecar 运行模式是一种"将不属于业务应用的功能以独立的容器运行于业务容器旁边",在 K8s 中表现出的样子就是将具备不一样功能的模块封装成不一样的镜像,并以不一样的容器运行在同一个 Pod 中。这种说法很是形象,由于 Sidecar 这个单词的本意就是三轮摩托侧面的"跨斗",这里形容独立于业务应用但又与业务应用部署在一块儿很是合适。api
上图: Sidecar ,中文意思为摩托车的跨斗,不禁赞叹命名的很是生动
本项目的错误注入模块也采用了 Sidecar 这种设计思想,将用于模拟 CPU、内存等故障的模块独立封装成一个镜像,并在 Pod 启动时以 Sidecar 的形式运行在主业务容器旁边。这样,不用它时他就会安安静静地当个美男子,彻底不用担忧它会影响到正常业务的运行;一旦须要它模拟错误产生,因为与业务容器同处于一个 Pod 之中(而 K8s 又以 Pod 为基本单元),所以他模拟出的错误亦被 K8s 集群视为业务应用所在 Pod 产生而被监测到。网络
上图: Pod 中的每一个容器都有本身的端口映射到外部主机,所以不会相互影响
本项目在设计之初是采用“在容器内修改环境变量”的方式对容器注入故障的,但事实证实这种方法太low,并且很是麻烦。所以在后续设计和实现中采用了目前较为流行的经过 REST API 传递 POST 请求的方式使容器模拟错误,这样就极大地方便了师兄们展开实验,并且也能够模拟出“微服务间调用而产生错误”的场景( 上游服务调用错误注入的 API 而模拟下游服务产生错误 )。架构
此外,本来该项目的实现是单进程的,故每注入一个错误都要等待错误结束后才能得到应答并注入下一个错误,这十分不利于实验的进行。所以在后面咱们改成了多进程运行,即每当一个错误产生时,程序都会创建一个子进程用于运行错误故障,而原来的进程则马上产生注入是否成功的应答并继续监听相应的服务端口,从而知足应答实时汇报和多种错误同时注入的功能需求。app
上图: 该程序的主要运行流程-以 “A 进程监听服务端口”的状态为起点
本应用以 Web 服务的方式运行,并封装为镜像保存于 DockerHub 上。所以使用以前须要先以容器的形式运行镜像。以 docker 命令运行本应用的参考命令以下所示:curl
# 使用 docker 命令简单测试该应用( 测试版本为 docker 18.03-ce ) docker run --rm -it -d --name fault-injection-server -p 5000:5000 xinyaotian/micro-fault-injection:1.0.0
待容器就绪后,访问您启动该容器的主机 IP 的 5000 号端口,若是出现了使用指引界面,就代表您的服务启动成功,能够参考使用说明进行错误注入了。ide
上图: 为了方便师兄们和你们的使用, 特意在服务首页制做了简易的使用方法指引, 为你们节省查 Github 文档的时间
本项目主要支持四种故障类型: cpu、内存、磁盘和网络,均经过 POST 请求向 /fault-inject 搭配相应参数进行注入。具体的注入方法以下所示( 注意更改 IP 和端口号 ):
1.注入 CPU 故障
# fault_type=cpu 指定错误故障类型(此处为 cpu 类型) # thread_num=4 触发该错误的线程数(此处为 4 个线程) # duration=15 故障持续时间,单位为秒(此处为 15 秒) curl -X POST -d 'fault_type=cpu&thread_num=4&duration=15' http://localhost:5000/fault-inject
2. 注入内存故障
# fault_type=mem 指定错误故障类型(此处为 mem 类型) # mem_size=120M 指定内存泄露的数值(此处为 120M ,注意 M 不能省略) # thread_num=4 触发该错误的线程数(此处为 4 个线程) # duration=15 故障持续时间,单位为秒(此处为 15 秒) curl -X POST -d 'fault_type=mem&mem_size=120M&thread_num=4&duration=15' http://localhost:5000/fault-inject
3.注入磁盘故障
# fault_type=disk 指定错误故障类型(此处为 disk 类型) # io_times=4 # duration=15 故障持续时间,单位为秒(此处为 15 秒) curl -X POST -d 'fault_type=disk&io_times=4&duration=15' http://localhost:5000/fault-inject
4.注入网络故障
# fault_type=net 指定错误故障类型(此处为 net 类型) # net_port=100 curl -X POST -d 'fault_type=net&net_port=100' http://localhost:5000/fault-inject
本项目的镜像将做为本来微服务应用的 Sidecar 独立部署运行, 所以在 K8s 环境中其应该与业务应用部署于同一个 Pod 之中。
您能够利用 yaml 启动一个单独的 Pod 来初步体验一下这个应用。快读启动的 yaml 以下所示( Istio 一样能够这样写, K8s 版本为 1.13.1, Istio 版本为 1.0.6 ):
--- # 为 fault injection 建立 service 分配端口 # --- apiVersion: v1 kind: Service metadata: name: single-fault-injection namespace: default spec: selector: # deployment identifier # 这个标签要与 deployment 中相对应 app: fault-injection ports: - protocol: TCP port: 5000 # 容器内端口为 5000 nodePort: 30050 # 映射至主机的 30050 端口 type: NodePort # 映射方式为 NodePort --- # 将该模块做为一个独立的 Pod 在 K8s 上进行部署 # --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: single-fault-injection namespace: default spec: replicas: 1 template: metadata: labels: # svc identifier # 这个标签要与 service 中相对应 app: fault-injection spec: containers: # 错误注入模块的 container - name: fault-injection-container image: xinyaotian/micro-fault-injection:1.0.0 imagePullPolicy: IfNotPresent ports: - containerPort: 5000 # 该容器的资源限制, 错误注入可以使其达到峰值 # resources: limits: cpu: "0.4" memory: 128Mi
若是您但愿以 Sidecar 的形式将本应用部署在其余微服务的 Pod 之中一样可行,这也是本项目的设计初衷。在 K8s 环境下部署和启动的 yaml 以下所示意( Istio 一样能够这样写, K8s 版本为 1.13.1, Istio 版本为 1.0.6 ):
--- # 为 fault injection 建立 service 分配端口 # --- apiVersion: v1 kind: Service metadata: name: your-microapp-with-faultinjection namespace: default spec: selector: # deployment identifier # 这个标签要与 deployment 中相对应 app: sidecar-fault-injection ports: - protocol: TCP port: 5000 nodePort: 30050 type: NodePort --- # 相应的 deployment 配置( 与原应用配置在一块儿 ) --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: your-microapp-with-faultinjection namespace: default spec: replicas: 1 template: metadata: labels: # svc identifier # 这个标签要与 service 中相对应 app: sidecar-fault-injection spec: containers: # 你原来应用的 container 信息 - name: your-micro-app image: your-docker-name/project:1.0 imagePullPolicy: IfNotPresent env: - name: PATH_VALUE value: "example" ports: - containerPort: 80 # ------------------- # # Sidecar 错误注入模块的 container - name: fault-injection-sidecar image: xinyaotian/micro-fault-injection:1.0.0 imagePullPolicy: IfNotPresent ports: - containerPort: 5000 # ------------------- # ---
在我本身的实验集群上,利用 Istio 启动该服务,并对其注入内存故障后,能够在 Grafana 监控面板上清晰地看到微服务 Pod 的内存忽高忽低,很是有趣。 错误注入的结果以下图所示。
上图: 注入内存故障后, 我本身的 Istio 集群监测微服务资源面板的可视化展示
项目到这里已经知足了实验室内师兄们绝大部分的科研需求。在以后的迭代中预计还会加入故障的产生速率( 例如 CPU 使用率会呈线性或指数上涨等 ),相应的 API 也会采用向前兼容的形式进行扩充( 添加更多的可选参数,不填则设置为默认值 ),以确保这个版本或以前版本使用者的代码无需改变而可继续使用后续版本。
此外,简单的用户控制面板也会在后续版本中开发。经过提供的用户界面,使用者能够在界面上输入参数并经过按钮进行错误注入,而再也不仅仅经过发送 POST 请求( 虽然底层原理仍是本地请求 )。相信用户界面会在汇报演示时为导师和师兄们带来诸多便利。
本项目主要以 Sidecar 的方式开发了一个用于错误注入的实验镜像,并经过在 docker 和 k8s 上运行从而达到对微服务单元注入故障的目标,为研究集群自动扩缩容、微服务自动扩缩容等课题提供了前提保障和研究条件。
感谢您的阅读,若是您对这个项目有什么更好的建议,或指出哪里设计有问题,我都会很是欢迎,洗耳恭听。很是但愿于读完本文的您进行交流,欢迎您在下方留言。
若是您的科研团队也有相似需求,也很是欢迎与咱们进行合做,并对针对本项目提出宝贵的改进意见。