关于Sidecar Pattern
本文转载自关于Sidecar Pattern
导语
Sidecar 是一个很纠结的名字,我们在翻译技术雷达时采用了一个比较通俗的翻译,即边车,而这个词随着微服务的火热与 Service Mesh 的逐渐成熟而进入人们的视野。虽然很多企业在自己的后台应用中已经大量的使用了 Sidecar,但是也是没有意识到这是一个极为有用的 pattern,今天我们就来聊一聊。
什么是 Sidecar 与 Sidecar pattern?
Sidecar 直接表示就是挎斗摩托车,也就是常说的“三蹦子”,如果你经常玩吃鸡,你一定不陌生。在“三蹦子”中,往往有个挎子,它不提供动力,但是也是这个机动装置的一个重要的组成部分,如果坐着一个妹子就可以给开车的你喂水果。
sidecar
我们目前很多程序都是奔着 Cloud Native 的目标去的,我们的代码注定是要跑在云上的,当有人问我如果我要做到 Cloud Native 时,有没有合适的学习资料之类的时,我会考虑如果你是有一定经验的开发者,并且对 Design Pattern 有一些了解,那么你非常适合这本来自微软 P & P Group 的书 Cloud Design Patterns,虽然这本书很简单,实例也不多,但是更多的是启发性。我也是在 Cloud Design Pattern 这本书中学到了很多,sidecar 也是其中之一,并且我们写了很多很多 Sidecar 用于管理自己的 Service Mesh 。
[Pattern is] a solution to a problem in a context.
为什么你需要 Sidecar?
非常简单,想象一下你要编写一堆 Web Service API,使用 JSON 作为数据格式暴露给前端,这个应用程序是用最常见的 Spring Boot 编写的,然后你要把他丢在你的虚拟机或者 k8s 上,你除了写代码,还需要考虑什么?
- DNS
- 反向代理
- 服务发现
- 服务注册
- 负载均衡
- HTTPS
- 弹性
- 日志
- 性能监控 APM
- 警报
- 终端安全
- 获取配置
- 等等
很多同事都对这些事情嗤之以鼻,毕竟大多数人的核心工作还是写代码,把应用做起来,至于这些事情是 ops 做的事儿,或者工程师可以做一部分,比如配置日志、给端点加个证书配置等等。于是我问一个朋友,Spring Boot 自带的 server 你知道怎么配证书和日志,那么 node express 呢?那么 on rails 呢?那么 play framework 呢?特别是当你决心要实现微服务架构的时候,这些看起来比较麻烦又很简单的事儿,反倒最消耗人,我们不希望给每个服务都做一遍,但是又不得不做一遍。所以,sidecar 的出现可以让我们以更优雅的方式解决这个事情,刚才我们提到的大量的功能都可以用 out-of-process 的方式实现,比如说反向代理。
Ruby 的 Unicorn Server 是一个很好的 Rack 容器,但是它对慢连接很敏感,而且不是很好处理 access log,熟悉 NGINX 的你一定想到了,如果我在虚拟机上开启一个 NGINX 进程,并且将 443 端口暴露出去,然后在这个 NGINX 中配置好 access log 与证书,并且将收到的请求使用 linux socket 的方式转发给 unicorn(或者直接走 docker network),这样我的 unicorn server 不就很简单了,我甚至都不需要配置。这样的一个 NGINX 就是一个 sidecar,它实现了访问记录、端点安全、进程隔离、并且轻量。你的应用程序不用再在乎这些,大约长得像这样:
server {
listen 80;
...
location / {
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Request-Start "t=\${msec}";
proxy_set_header Host \$http_host;
proxy_redirect off;
proxy_pass http://backend;
...
再举一个例子,我们每个应用程序都会记录日志,而我们并不希望日志保存在每台机器上或者容器中,我们希望每个应用是不产生任何状态的。但是这很难,我们必须开发所谓的日志收集系统,并且相关的日志组件,往往我们只能兼顾一两个流行语言或平台,例如 Java 与 JavaScript,而且我们还得维护这些东西,直到公司倒闭。有没有更优雅的解决办法呢?答案是有,在 12 factor app: logs 中,我们希望以事件流的方式去处理日志,如果我的应用把日志丢到 stdout 与 stderr 中,然后有人来自动收集,归档并发送到日志中心呢?这就是日志收集器,这也是一个 sidecar。
Sidecar 核心思想
Sidecar 不是应用程序的必要组成部分,当你使用 docker-compose 在本地启动一个小服务做开发测试的时候,Sidecar 并不会起作用,所以它不影响你的核心功能。但是,Sidecar 在真正的生产环境中,是和你的应用程序绑定在一起的,应用在哪里启动,它就出现在哪里。我们的应用不论是在虚拟机或者是在容器中,每一个应用的实体,都有大量的 sidecar 来做这种与核心功能无关的活儿。
每个“三蹦子”都有自己的 sidecar,每个 sidecar 都是紧紧的 attach 到它的“三蹦子”上的。
没有上容器云之前的 Sidecar 例子
那么,引用并修改一下 sidecar 的特性
- Sidecar 是独立于其应用程序之外的,不使用应用程序的运行环境与编程语言。比如你可以使用 JavaScript 去做日志收集器,而不用关心应用程序用的什么语言,你们使用进程通信的方式或者更粗暴的流
- Sidecar 是可以访问一些相同的系统资源的,和应用程序一样。这样你才能进行系统监控与收集程序的健康数据。但是也有一些数据是在应用程序内打桩,然后暴露出去的比如 transaction
- Sidecar 实际上对性能的损失非常小,特别是使用了容器化技术后,本来启动容器就是很廉价的事情,而且使用 docker image 发布 sidecar 让这个事情成本更低
- Sidecar 同样可以进行应用程序扩展,比如说,我们可以将 circuit breaker 实现在 sidecar 中,这样就可以避免代码中使用各种 circuit breaker 的实现,你的代码依旧可以简单的 RestTemplate 去做你想做的事儿,也不用担心下游服务的实效,导致串联失效的问题
Sidecar 的适合场景
如果你们公司已经开始使用微服务架构,践行了小组自治,那么大量的应用程序会用各种流行语言编写,并且使用了各种不同的框架,那么 Sidecar 就是你一定要考虑的。使用 out-of-process 的方式封装共有的一些功能,让应用程序变得简单,而这些共有的功能,最理想的情况下就是部署脚本中的一些配置。
Sidecar 在微服务领域是服务治理的重要工具,也是实现 Service Mesh 的必备工具,在 Service Mesh 的概念下,我们希望提供一层额外的抽象来保证服务的简单、可以相互调用,并且帮助我们轻松的解决服务发现、服务调用、服务监控、服务注册等等功能,这额外的一层可以通过 sidecar 来实现。不论是 Istio 还是 conduit 很多关键功能就是这么实现的。当然,很多情况下我们还是会自己去写适合自己组织架构的 sidecar,之前我们提到的 NGINX 与日志收集器就是一些很好的例子。而之前我们列举出一个 Web Service 可能会需要的功能,也有一部分是根据你的云平台进行裁剪的,比如负载均衡和弹性,完全可以使用 AWS 的 ELB 与 AutoScaling 来解决。
那么什么时候不适用呢?
- 应用程序过小,或者成本问题:如果没有使用微服务架构或者你的程序就一个 MVC App 就解决了,那就不需要使用 sidecar,毕竟开发成本很高
- 对性能要求极高:进程间通信还是有成本的,有时也是会有显著的延迟或者被阻塞;docker network 的性能也是赶不上进程间通信的,所以如果你的应用有小于毫秒级别的性能要求的话,这个 sidecar 不适合你
Sidecar 与 DevOps
我在与别人聊 Sidecar 时,很多朋友觉得这个东西的难点不在于创建一个又一个的 sidecar,而是在于如何在部署时,按照应用程序的要求将 sidecar 与应用程序紧紧的组合在一起。这是非常难的,首先每个企业使用的平台并不相同,每个企业的部署方式也不一样,这是没有通用解的问题,只能按照现有情况。在之前我们使用 aws ec2 + docker 时,我们会在 ec2 的 launch config 中去启动不同的 docker image 并且配置其 docker network,但这是一种比较低效的做法,因为只是使用 docker image 来封装你的产出物,而不是使用其作为秒级开启的容器。但是如果在 k8s 上做这件事儿,我们更倾向于在一个容器中把应用的事情做好,很难做到每个应用所运行的容器上都有 attached sidecars。所以这个话题没有好的回答,只能说是 It depends。
Reference
- https://docs.microsoft.com/en-us/azure/architecture/patterns/
- https://rubygems.org/gems/unicorn/versions/5.1.0
- https://www.nginx.com/blog/what-is-a-service-mesh/
- https://12factor.net
- https://istio.io/
- https://github.com/runconduit/conduit
- https://martinfowler.com/bliki/CircuitBreaker.html
- http://www.baeldung.com/rest-template
关于Sidecar Pattern的更多相关文章
- image management in kubernet
Image How can I edit an existing docker image metadata? docker-copyedit Registry Disk kubevirtis a g ...
- Kubernetes与容器设计模式
目录贴:Kubernetes学习系列 在程序设计领域,面向对象设计和面向对象语言是大家最为熟悉和强大的工具,而面向对象除了其强大的核心特性之外,还有人们通过实践总结出来的一系列设计模式,可以用来解决实 ...
- 《Kubernetes与云原生应用》系列之容器设计模式
http://www.infoq.com/cn/articles/kubernetes-and-cloud-native-app-container-design-pattern <Kubern ...
- k8s管理pod资源对象(上)
一.容器于pod资源对象 现代的容器技术被设计用来运行单个进程时,该进程在容器中pid名称空间中的进程号为1,可直接接收并处理信号,于是,在此进程终止时,容器即终止退出.若要在一个容器中运行多个进程, ...
- docker,容器,编排,和基于容器的系统设计模式
目录 从容器说起 背景 docker实现原理 编排之争 基于容器的分布式系统设计之道 单节点协作模式 Sidecar pattern(边车模式) Ambassador pattern(外交官模式) A ...
- 浅析 Dapr 里的云计算设计模式
Dapr 实际上是把分布式系统 与微服务架构实践的挑战以及k8s 这三个主题的全方位的设计组合,特别是Kubernetes设计模式 一书作者Bilgin Ibryam 提出的Multi-Runtime ...
- k8s sidecar, Ambassador, Adapter containers
When you start thinking in terms of Pods, there are naturally some general patterns of modular appli ...
- K8S 使用 SideCar 模式部署 Filebeat 收集容器日志
对于 K8S 内的容器日志收集,业内一般有两种常用的方式: 使用 DaemonSet 在每台 Node 上部署一个日志收集容器,用于收集当前 Node 上所有容器挂载到宿主机目录下的日志 使用 Sid ...
- 按照Enterprise Integration Pattern搭建服务系统
在前一篇文章中,我们已经对Enterprise Integration Pattern中所包含的各个组成进行了简单地介绍.限于篇幅(20页Word以内),我并没有深入地讨论各个组成.但是如果要真正地按 ...
随机推荐
- 十三:SpringBoot-基于Yml配置方式,实现文件上传逻辑
SpringBoot-基于Yml配置方式,实现文件上传逻辑 1.文件上传 2.搭建文件上传界面 2.1 引入页面模板Jar包 2.2 编写简单的上传页面 2.3 配置页面入口 3.SpringBoot ...
- Docker+Prometheus+Alertmanager+Webhook钉钉告警
Docker+Prometheus+Alertmanager+Webhook钉钉告警 1.环境部署 1.1 二进制部署 1.2 docker部署 1.2.1 webhook 1.2.2 alertma ...
- jQuery——选择元素
###理解DOM jQuery最强大的特性之一就是能够简化在DOM中选择元素的任务.**DOM(文档对象模型)**充当了JavaScript与网页之间的接口,它以对象网络而非纯文本的形式来表现HTML ...
- Centos7服务器安装Docker及Docker镜像加速,Docker删除
Centos7服务器安装Docker及Docker镜像加速,Docker删除 1.Centos7服务器安装Docker 1.1 root账户登录,查看内核版本如下 1.1.1 卸载服务器旧版本Dock ...
- Go语言学习-import
import我们在写Go代码的时候经常用到import这个命令用来导入包文件,而我们经常看到的方式参考如下:import("fmt")然后我们代码里面可以通过如下的方式调用fmt. ...
- 深入理解Java虚拟机读书笔记 -- Java内存区域
Graal VM: Run Programs Faster Anywhere. 跨语言全栈虚拟机,可以作为"任何语言"的运行平台使用. Java内存结构 程序计数器:线程私有,较小 ...
- Python: 捕获正在运行的CMD窗口内容
最近需要捕获已经在运行的CMD窗口内容,并且需要根据指定输出内容来判断下一步的行动(输入指定内容). 尝试了很多次后,想到一个思路: 通过inspect.exe来获取CMD窗口Name信息通过uiau ...
- 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest PART(10/12)
$$2017-2018\ ACM-ICPC,\ Asia\ Daejeon\ Regional\ Contest$$ \(A.Broadcast\ Stations\) \(B.Connect3\) ...
- java中static修改成员变量和函数和其他使用
一.通过static修饰的成员变量初始化只会初始化一次 //静态变量初始化只会初始化一次 public class zuishuai { public static void main(String[ ...
- java——字符串常量池、字符串函数以及static关键字的使用、数组的一些操作函数、math函数
字符串常量池: 字符串比较函数: 字符串常用方法: 字符串截取函数: 字符串截取函数: static关键字使用: 要调用类中的static类型的变量的时候,可以用"类名.变量名&quo ...