Sidecar是一种日军在二战期间广泛使用的偏三轮摩托,由于它比两轮摩托多一轮,且多出的一轮在其中一侧,不影响另一侧的结构,因此得名Side-Car。
由于sidecar这个词过于形象,后来被广泛使用,比如支撑iPad作为MacBook副屏的系统叫Sidecar System。
在容器编排领域,k8s pod 被设计成编排的最小单位,但每个pod里可以安排多个container,主container提供核心业务逻辑,其他container提供配置初始化、请求proxy、日志等辅助功能,这种使用模式也被称为sidecar模式。
由于pod内的container共享一个ip,通过localhost通信,虽然比不上unix socket和mmap内存共享,不过也很少存在容器间网络通信的性能问题。
下面我们聊一聊sidecar模式的产生背景、实现细节和应用场景。
应用和服务的正常运行通常需要执行一些通用的任务,比如监控、日志、配置更新、服务发现等。这些外围任务可以通过独立的组件或服务来实现。如果把这些任务集成到服务中,和主干逻辑运行在同一个进程的不同线程中,可以充分使用资源。不过副作用是这些外围逻辑和主干逻辑没有被充分隔离开,其中任何一个组件出现问题都会影响其他组件,甚至导致整个应用的崩溃。另外一个问题是,编写外围组件用的语言需要和主干逻辑保持一致,最终,外围组件和主干逻辑的相互依赖会越来越严重。
如果把一个应用解耦成不同的服务,每个服务都可以使用不同的编程语言实现。这样的灵活性会大大增强,不过由于每个服务都会有自己的依赖,需要特定编程语言的库来访问底层的共享资源和数据,整体运维成本上升。由于每个任务都是独立的服务,应用内服务通信的延迟会变高。
针对上面的场景,我们可以把外围任务与主干逻辑部署在一起(一个pod里),但每个任务拥有自己的进程或容器,为不同语言编写的业务服务提供同质化的接口。
Sidecar服务可以不是应用的组成部分,但必须能够与应用高效地通信。应用部署在哪里,Sidecar服务就部署在哪里。Sidecar服务与主应用的服务同时部署。因此,Sidecar服务的生命周期与主应用保持一致。对于每个主应用的实例,都有一个sidecar实例与之部署在一起,运行在一起。
Sidecar 模式的优点有:
Sidcar有自己的编程语言和运行时环境,与主应用分离,所以不需要给每个编程语言都开发一套;
Sidecar与主应用有同样的数据访问权限。比如sidecar可以监控系统资源的使用情况,不管对象是sidecar服务本身,还是主应用;
由于在物理上很近,Sidecar和主应用的通信延迟非常小;
即便主应用不提供扩展能力,也可以通过sidecar对其进行扩展;
需要考虑服务的部署和打包格式,最合适的场景是打包成容器;
设计sidecar服务时,尤其要考虑进程间通信的机制。不要使用依赖于特定语言或框架的技术,除非性能无法满足要求;
在把功能塞到sidecar里之前,先想想放到独立的服务或传统的后台进程里是否更合适;
优先考虑使用一个库或插件机制去实现,基于特定语言的库通常与系统集成度更高,也没有网络延迟;
适用场景有:
主应用是由多个的语言和框架编写而成,sidecar里的组件需要和不同语言不同框架编写的服务配合使用;
组件是由另一个团队或组织提供的;
组件必须和主应用部署在同一台机器上;
需要一个服务能够感知主应用的整个生命周期,且能够独立进行更新;
我们需要监控系统对内存的使用情况;
不适用场景有:
进程间的通信延迟成为了系统瓶颈,需要进行优化;
应用程序比较简单,应用sidecar耗费的资源已经超出了隔离带来的收益;
服务需要独立与主应用进行更新,这种情况更适合部署独立的服务;
基础架构服务API,比如日志、环境数据、配置数据、服务发现、health check、watchdog服务灯。sidecar也可以监控主应用的宿主机情况和进程运行情况,记录到一个中心化的服务;
管理NGINX/HAProxy。把NGINX和sidecar部署到一块,sidecar可以监控环境状态的变化、更新NGINX配置文件、必要时重启进程;
充当大使sidecar。部署一个大使服务作为sidecar,主应用通过大使服务调用其他服务。大使服务提供的功能有请求日志记录、路由、熔断器、和其他网络相关的功能;
充当降负载的代理。把NGINX放到nodejs服务的前面,提供静态文件的加载;