关于微服务和容器
In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.
—ThoughtWorks 公司的首席科学家 Martin Fowler
近几年,越来越多的开发人员使用“微服务”一词来阐述他们的系统或应用架构。究竟什么是微服务呢?
什么是微服务
简而言之,微服务架构风格是一种将单个应用程序作为一组小型服务开发的方法,每个服务都在自己的进程中运行,并使用轻量级机制(通常是基于HTTP的API)进行通信。 这些服务是围绕业务功能构建的,可以通过全自动部署机制独立部署。 这些服务不需要集中式管理,可以用不同的编程语言编写,并使用不同的数据存储技术。
图1: Martin Fowler微服务VS 单体服务
❖ 相比单体服务,微服务的特点
一组小服务
服务粒度要小,每个服务是针对一个单一职责的业务能力的封装,专注做好一件事情。但是又不能太小,否则易发生“服务爆炸”。通常在工程实践中,如果一个功能被两个或两个以上的服务调用,它就可以被封装为服务。
独立的进程
每个服务能够独立部署并运行在一个进程内。这种运行和部署方式能够赋予系统灵活的代码组织方式和发布节奏,使得快速交付和应对变化成为可能。
轻量级的通信
使用REST/RPC,抛弃重量级的SOAP。
独立开发和演化
技术选型灵活,不受遗留系统技术约束。合适的业务问题选择合适的技术可以独立演化。服务与服务之间采取与语言无关的API进行集成。相对单体架构,微服务架构是更面向业务创新的一种架构模式。
❖ 微服务的优点
- 每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求。
- 微服务能够被小团队单独开发,这个小团队可以是2到5人的开发人员组成。
- 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
- 微服务能使用不同的语言开发。
- 微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins, bamboo。
- 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
- 微服务允许你利用融合新技术。
- 微服务能够即时被要求扩展。
- 微服务能部署中低端配置的服务器上。
- 易于和第三方集成。
- 每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库。
❖ 微服务的缺点
- 运维开销及成本增加:单体服务可能只需部署至一小片应用服务区集群,而微服务架构可能变成需要构建/测试/部署/运行数十个独立的服务,并可能需要支持多种语言和环境。
- 隐式接口及接口匹配问题:把系统分为多个协作组件后会产生新的接口,这意味着简单的交叉变化可能需要改变许多组件,并需协调一起发布。
- 分布式系统的复杂性:作为一种分布式系统,微服务引入了复杂性和其他若干问题,例如网络延迟、容错性、消息序列化、不可靠的网络、异步机制、版本化、差异化的工作负载等,开发人员需要考虑以上的分布式系统问题。
- 异步机制:微服务往往使用异步编程、消息与并行机制,如果应用存在跨微服务的事务性处理,其实现机制会变得复杂化。
- 可测性的挑战:在动态环境下服务间的交互会产生非常微妙的行为,难以可视化及全面测试。
微服务架构
幸运的是我们从零开始构建微服务。
目前比较好的微服务框架,如spring cloud、dubbo等,已经提供了完整的微服务生态链。
图2: 微服务框架
在上图中,我们将微服务框架的能力分为2类,类是基础能力,这部分能力并不是微服务特有的,而是很多系统都必需的一些基础能力,例如:
第二类是微服务框架的核心能力,主要解决微服务架构中的特有问题,例如:
服务注册与发现
在微服务架构中,一般每一个服务都有多个拷贝来做负载均衡。一个服务随时可能下线,也可能应对临时访问压力增加新的服务节点。那么,服务之间如何相互感知?服务如何管理?这就是服务发现的问题了。
一般有两类做法,也各有优缺点。基本都是通过zookeeper等类似技术做服务注册信息的分布式管理。当服务上线时,服务提供者将自己的服务信息注册到ZK(或类似框架),并通过心跳维持长链接,实时更新链接信息。服务调用者通过ZK寻址,根据可定制算法,找到一个服务,还可以将服务信息缓存在本地以提高性能。当服务下线时,ZK会发通知给服务客户端。
图3: 服务注册与服务调用
配置集成
目前大部分公司都是把配置写到配置文件中,遇到需要修改配置的时候,成本会很高。并且没有修改配置的记录,出了问题很难溯源。
微服务架构中,使用配置中心统一管理配置参数。实现方式有两种,一种是push,一种是pull。下图所示为某公司配置中心架构图:
图4 :配置中心
调用链埋点
使用埋点技术追踪微服务的调用链,其理论基础来源于Google公司发表的论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》。目前比较流行的调用链监控框架有zikpin等。
限流熔断
假设服务A依赖于服务B和服务C,而服务B和服务C有可能继续依赖于其他服务,这样一条调用链上,如果某个服务不可用或者延迟较高,则会导致调用服务A的请求被堵住,占用系统的CPU、IO等资源。当该类请求越来越多,占用的系统资源越来越多,会导致系统瓶颈出现,造成其他的请求也不可用。终导致业务系统崩溃。
一般情况下,对于服务依赖的保护主要有两种方式:限流熔断与线程隔离。目前比较流行的熔断框架是Hystrix。
下图中,服务A和服务B都依赖于服务C2和C3,服务A另外依赖于服务C1,当服务C1不可用或者延迟较高时,启动熔断机制,释放占用的线程资源,保证不影响服务B的正常功能。
图5:熔断与隔离
什么是容器
容器技术有时会被称为轻量化虚拟技术。但不同于基于Hypervisor的传统虚拟化技术,容器技术并不会虚拟硬件。容器本身和容器内的进程都是运行在宿主Linux 系统的内核之 上。但与直接运行的进程不同,运行在容器内的进程会被隔离和约束。从而以直接运行的高效实现了虚拟技术的大部分效果。
图6: 容器与传统虚拟化
什么是Docker
Docker 的出现并非创造了一个新的容器技术,而是在LXC (LinuX Container)、cgroups、namespaces 技术之上所构建的一种技术。
Docker 简化了容器的运行:它通过一个简单的命令就能够运行起一个容器。
Docker 简化了容器镜像的构建和分发:提供了Dockerfile和docker commit两种方式构建镜像,并且提供了Docker image registry机制以保存和分发镜像。
Docker主要由Docker Hub和Docker引擎组成。前者是Docker官方提供的容器镜像仓库;后者运行在宿主机上,可分为服务器端和客户端两部分。服务器端负责构建、运行和分发Docker容器等重要工作,客户端负责接收用户的命令和服务程序进行通信。
图7: Docker的组成
Docker是如何实现的
Docker使用了如下几个重要技术,实现了不同层次的隔离:
namespaces
Linux容器通过Kernel的namespaces 技术,为一个或一组进程创建独立的pid、net 等namespaces,从而与其它进程相互隔离。
cgroups
namespaces对进程分组以实现资源隔离,但这隔离还是不够的。一个进程可以通过占用过度的硬件资源的方式去影响另一个分组中的进程。所以,要想实现完善的资源隔离,不仅要对资源分组,还要能对这一组内的进程所使用的资源进行约束。cgroups可限制进程对CPU、内存、块存储和网络的使用。
为什么使用Docker
Docker的出现带动了一些列技术的发展,形成了一个庞大的生态圈。这个生态圈中的产品可大致分为如下几类:
容器编排管理
以Google Kubernets和Apache Mesos为代表。主要解决基于容器组成分布式集群应用的管理工作,例如对容器的运行状态的监控、容器自动化的故障恢复、基于容器的应用 的扩容和缩容、服务发现。
基于容器的操作系统
以CoreOS和Redhat Atomic为代表。它们抛弃了Linux上面传统的包管理机制,而使用Docker作为应用的运行平台。同时精简系统。CoreOS还引入了Ectd、Fleet等组件 以更好地支持分布式系统。
网络
如何管理大量的Docker容器所使用的网络,便成为新的挑战。在这个领域主要有Pipework、Weave和Flannel等技术。
配置管理
像Puppet、Ansible这样的配置管理工具已经升级了对Docker的支持。
微服务为什么要容器化
微服务区别于单体架构的地方就在于“分而治之”,即通过切分服务以明确模块或者功能边界。
然而,仅有“分”是不行的,软件系统是一个整体,很多功能来自若干服务模块的配合,因此必然要有“合”的手段,这对矛盾会体现在多个方面。
应用开发
微服务很好地支持了语言技术栈的多元化,它通过切分系统的方式,为不同功能模块划定了清晰的边界,边界之间的通信方式很容易做到独立于某种技术栈,因此也就为纳入其它技术带来了空间。
但是不同技术栈的微服务之间,除了需要考虑通信机制,还要确保这些技术能以较低成本结合成一个系统。终在线上,它们应当成为一个整体。
Docker将所有应用都标准化为可管理、可测试、易迁移的镜像/容器,因此为不同技术栈提供了整合管理的途径。在这种情况下,开发人员可以自由选择或者保持自己的常用工具,不必因为微服务的分裂产生过高的学习成本。
组织结构
说到团队和组织,不能绕开的一个话题就是“康威定律”(Conway’s law):
软件系统的结构受制于其生产者组织的沟通结构。
从这个角度看,微服务的拆分会对团队扩张带来帮助,这不难理解,因为系统拆分为若干微服务会促进这些微服务之间的边界更清晰,我们知道,边界清晰等于在边界之间协作信息量少,如果按照微服务拆分团队,团队之间的协作成本将是比较低的。
◈然而,“边界之间协作信息少”是有代价的。这代价就是团队的每个人对系统失去了整体视角和掌控能力,在这一点上,单体架构显然要好很多——每个开发者的开发环境都有完整的系统构建,所以很容易就可以获得对系统的整体印象和理解。这是微服务的短板,其核心在于构建成本,由于微服务来自不同团队和部门,因此如何搭建它就成为一个谜,同时由于不能低成本的获得一个完整的系统,系统整体的知识也就容易被开发者忽略,终导致整体视角缺失。
对于大多数外部服务,我们需要考虑建立自动化系统构建和测试的方法,这是微服务架构带来的研发挑战。
如果首先对各系统进行Docker化,就很容易通过统一的docker build,建立一致性的构建服务,再结合compose等基础设施处理服务依赖,这些工作终就可以产生一个平台,(自动化的)将被微服务打散的整个系统再构建出来(由于使用了微服务,构建速度在理论上就可以是并行的,因此甚至会比单体架构更敏捷)。◈
系统变更碎片化
理论上,由于进行了分解,微服务架构的系统应该更加有利于系统的“改良”,不必动辄就伤筋动骨甚至另起炉灶。但是实际上并不一定会这样。例如服务接口的升级,所有依赖该服务的其他服务也不得不升级,我们都知道,部分升级有时候还不如整体升级。
如果使用docker,由于每个服务打包可以封装为一个docker镜像,每个运行时的服务都表现为一个独立容器,我们之前建立的容器依赖就可以很容易的对应到服务依赖上,基于这种统一性,系统升级就很容易配合一些自动化工具实现“整体升级”(甚至还可以“整体降级”)。
总结
面对膨胀的未来,微服务走了一条拆解之路,但要想完整的实现你的业务,还要能够在某些情况下自由融合、彼此协作,Docker开启的正是这样一个方便之门。
无论是协同不同语言技术栈,降低运维的成本,还是支持分布式系统的自动化测试和持续交付,甚至是从单体架构向微服务的逐步演化,Docker相关技术都可以为微服务提供有力帮助。
相关文章