[关闭]
@bergus 2016-08-12T15:46:13.000000Z 字数 8214 阅读 4322

微服务架构漫谈

微服务


什么是微服务

微服务是一种将应用分解成小的自治服务的软件架构。
服务通常仅关注某个特定的目标并保证服务之间的自治。
每个服务被独立的开发、测试和部署,每个服务往往使用约定的API并通过网络进行通信,虽然在某些情况下网络可能是本地的。

  1. 微服务架构中的 “微”体现了其核心要素,
    即服务的微型化,就是每个服务微小到只需专注做好一件事。
    这件事紧密围绕业务领域,形成高度内聚的自治性。

  2. 以前做大型应用系统,大都采用模块化的分层式架构,
    所有的业务逻辑代码最终会打进一个代码库中统一部署。

  3. 这种应用架构的问题是,全部开发人员会共享一个代码库
    不同模块的边界模糊,实现高内聚、松耦合极其困难。

  4. 如果你接手过这类应用的遗留系统,尝试去做重构改进时,肯定碰到过这类场景,改了一个地方好几个其他模块也需要同步改动,模块的边界轻易被穿透,
    这种应用的架构有一个很形象的名字叫 “洋葱架构”,洋葱的特点就是一层又一层的粘连, 重构这样的系统就像切洋葱一样让人忍不住飙泪。

  5. 微服务架构强调 “微”,但如果采用了 SOA 服务化架构思想的系统会搞出很多胖服务来,一点也不微,这依然带来耦合。
    这一点只能依赖系统架构师的服务化建模能力了,
    但微服务架构强调每个服务一个进程,
    使用进程为边界来隔离代码库至少让同一应用系统不同层次的开发人员享有自己完全自治的领地,
    每个微服务都有一个掌控者。

  6. 从某种程度上让不小心做错事,
    例如:跨出服务边界的代码耦合依赖,变得没那么容易。

  7. 想象一个场景,一个 20 人的团队维护一个 40 万行共享代码库的单一应用,在里面修改 bug和添加功能都将十分困难。
    有一篇文章 《程序员的成长和代码行数的关系》 里提到大部分普通程序员成长生涯的瓶颈在2万行代码左右,
    超过这个代码行数的应用系统维护起来将倍感吃力,所以随着咱们项目的逐渐发展膨胀,咱们团队维护将会无比吃力。

微服务从SOA发展而来,SOA在本世纪初曾获得广泛的认可和流行,SOA是一种反对大型的整体化架构应用的方式。
SOA和微服务的主要区别有:

  1. SOAs是有状态的,而微服务是无状态的
  2. SOAs倾向于使用企业级的服务总线进行通信,而微服务则使用更简单的通信系统
  3. SOAs或许会有上百万行代码,而微服务往往仅有少于100行代码
  4. SOAs强调重用(例如运行时代码、数据库等),而微服务则关注在尽量解耦
  5. SOAs里的一个系统性变化需要修改软件的整体结构,而在微服务中的一个系统性变化将产生一个新的服务
  6. SOAs更经常使用传统的关系型数据库,而微服务则更倾向于现代的、非关系型数据库

许多架构师发现SOA存在通信协议的问题和缺乏有效的如何分割服务的指导,
这些问题构成了微服务的基础,
使得微服务成为了实现一个真正的SOA的最佳实践方法。

微服务与单体

在微服务之前,一个通用的软件设计模式是使用整体化架构(单体架构)。在这种模式下,应用程序在开发、测试、打包和部署阶段都是作为一个整体存在。代码库被整体编译,应用程序被作为一个实体部署。扩展需要将应用程序的二进制文件和依赖的库文件拷贝到不同的服务器上,这些应用程序一般都是单进程运行。这种整体化架构使得持续交付(一种包含了快速、迭代、升级安全的软件开发过程)变得充满挑战,因为哪怕是应用程序栈的最小增量版本也需要重新编译、重新链接和测试。

单体架构图
单体架构图
微服务架构图
微服务架构图
微服务扩展图

微服务的优点和缺点,好处和意义

从行业现状来看,在整个中国的IT生态中,集中式架构还是主流。分布式架构目前主要是互联网行业用的比较多。相对总的来说,占比还是比较小。而微服务,基本上也就是搞分布式架构的一小拨人开始去尝试的新鲜技术。从这个现状来看,新的思维方式,架构人才永远是痛点。很多人连互联网行业常用的分布式架构尚未理解,让它设计或者在生产实践中采用微服务架构。就勉为其难了。即使架构师具备了这种能力,但是负责具体实施的工程师团队是否有这种思维和类似的设计能力,就是一个很大的疑问。因此必然出现了目前只是在一些大的公司,小范围的实践。

微服务架构模式有很多好处

  1. 通过分解巨大单体式应用为多个服务方法解决了复杂性问题
    在功能不变的情况下,应用被分解为多个可管理的分支或服务。
    每个服务都有一个用RPC-或者消息驱动API定义清楚的边界
    微服务架构模式给采用单体式编码方式很难实现的功能提供了模块化的解决方案,由此,单个服务很容易开发、理解和维护。

  2. 专门团队开发专门服务,技术选型灵活
    这种架构使得每个服务都可以有专门开发团队来开发。
    开发者可以自由选择开发技术,提供API服务。
    当然,许多公司试图避免混乱,只提供某些技术选择。
    然后,这种自由意味着开发者不需要被迫使用某项目开始时采用的过时技术,他们可以选择现在的技术。
    甚至于,因为服务都是相对简单,即使用现在技术重写以前代码也不是很困难的事情。

  3. 微服务架构模式是每个微服务独立的部署
    开发者不再需要协调其它服务部署对本服务的影响。
    这种改变可以加快部署速度。
    UI团队可以采用AB测试,快速的部署变化。
    微服务架构模式使得持续化部署成为可能。

  4. 微服务架构模式使得每个服务独立扩展
    你可以根据每个服务的规模来部署满足需求的规模。
    甚至于,你可以使用更适合于服务资源需求的硬件。
    比如,你可以在EC2 Compute Optimized instances上部署CPU敏感的服务,而在EC2 memory-optimized instances上部署内存数据库。

  5. 缩短产品上市时间
    在整体化架构的应用中,任何微小的修改都需要重新部署整个应用栈,因此带来了更高的风险和复杂度。
    这造成了更长的版本周期,因为修改可能会被累积,直到达到某个阈值时才发布新的版本。
    使用微服务,对于某个服务的修改可以被迅速的提交、测试和部署,因为对此服务的修改跟系统的其它部分是不相关的。

  6. 持续集成
    一种每天数次集成和测试开发人员的代码改动的软件开发实践
    因为有更少的功能需要去测试而变得更简单和快速。
    结果是版本的发布节奏更快,因为更少的代码需要被编译和重新测试。
    编排框架例如Kubernetes通过自动化上线、容器滚动更新和必要时的回滚进一步加快了产品上市的节奏。

  7. 灵活性和可扩展性
    单体架构的应用需要系统中的全部组件同时扩展。
    如果某个服务需要更高的性能,唯一的选项就是扩展系统中的所有服务而不是仅仅扩展需要扩容的单个服务。
    使用微服务,仅需要额外能力的单个服务需要扩容。
    扩容通过部署更多的容器来实现、可以实现更有效的容量计划,更少的软件授权和更低的总体拥有成本;
    因为服务和软件可以更好的匹配。

  8. 弹性,容错性
    整体架构应用的一个主要问题是当某个服务失效时可能整个系统可能都会受到连累。
    在微服务中,各个服务之间的隔离性使得单个服务的失效不会扩展到系统的其它部分进而造成全局性的影响。
    如果使用容器,编排框架可以提供额外的弹性:当某个容器失效时,一个新的容器会被启动,进而实现完全的冗余和容量。

  9. 组织架构匹配
    微服务可以更好的匹配组织架构,因为团队的规模可以根据需要完成的任务进行更好的定义。
    团队可以被分成更小的小组并专注在应用的某个组件上。
    这对分布在不同地理位置的团队来讲是非常有用的。例如,在新加坡的团队处理三个服务,在旧金山的团队处理五个服务,这两个团队可以独立的发布和部署功能组件。 这可以帮助处理相同组件的不同职能的团队(Ops、Dev、QA)打破疆界和更好的合作。这也可以保证不同团队之间的沟通跟不同的服务之间的API相匹配。本质上来讲,服务之间的API定义了不同开发团队之间应该相互提供的服务的契约。

  10. 降低成本
    通过使用容器,应用和环境(设计、测试、生产、支持)可以共享相同的基础设施,
    结果是更高的硬件利用率和由于管理简化带来的成本降低。
    另外,微服务也会降低技术方面的开销。
    在整体化架构的应用中,重构一个大型应用的代码会带来开销(时间、资源)。
    通过将应用分解成可以通过API访问的微服务,代码重构可以逐个服务进行,结果是更少的时间去维护和更新代码。

  11. 易于开发、理解
    由于每个服务只负责单一功能,开发者可以聚焦于自己负责的几个服务模块,对于其他服务,只需要理解接口即可。
    当然,单体应用经过良好设计也可以达到这个效果,
    但是,与单体应用的进程内通信或单机内的进程间通信不同的是,
    微服务的各服务之间一般采用RESTfulAPI或者异步消息队列进行通信,无论 RESTful接口还是异步消息队列都是开发语言无关的,极易理解的通信方式。

  12. 全局稳定性提高
    由于每个服务负责的功能单一,各服务的资源需求也相对更低。
    从而可以选择将服务分散的部署到多台中低配的服务器上,而不是一台高配的机器上。
    如果某个机器上的服务故障,譬如说内存泄漏,故障只会影响该机器上的某一个或几个服务,对全局影响不大。
    不受限于任何技术栈,极大的提高团队搭建的速度。
    这一点对初创公司尤为重要,组建开发团队对初创公司来说本来就是个头疼的问题,如何还要求团队的技术栈一致,招聘难度可想而知。但是,如果产品架构采用微服务架构,那么我们可以允许不同的服务模块采用不同的技术栈,只需要定义好对外接口即可。局部的修改很容易部署,从而大大的提高了功能的交付效率。

微服务架构模式下的缺点或者说难处

  1. 如何确定软件功能切分的粒度,边界。
    太多的微服务模块会导致服务间通信成本和运维成本的增加,过犹不及;
    但是若粒度过大,又违背了微服务的初衷。

  2. 多种技术栈(譬如 C,Java,Python,Scala 等)我们需要为每种语言准备编译环境,运行环境等,增加了维护成本。

  3. 微服务模块多了,会导致全局的上线次数变多,从而需要更复杂的版本管理和Bug跟踪等,间接导致项目管理成本增加。

  4. Fred Brooks在30年前写道,“there are no silver bullets”,像任何其它科技一样,微服务架构也有不足。
    其中一个跟他的名字类似,『微服务』强调了服务大小,实际上,有一些开发者鼓吹建立稍微大一些的,10-100 LOC服务组。
    尽管小服务更乐于被采用,但是不要忘了这只是终端的选择而不是最终的目的。
    微服务的目的是有效的拆分应用,实现敏捷开发和部署。

  5. 微服务应用是分布式系统,由此会带来固有的复杂性。开发者需要在RPC或者消息传递之间选择并完成进程间通讯机制。
    更甚于,他们必须写代码来处理消息传递中速度过慢或者不可用等局部失效问题。
    当然这并不是什么难事,但相对于单体式应用中通过语言层级的方法或者进程调用,微服务下这种技术显得更复杂一些。

  6. 分区的数据库架构。
    商业交易中同时给多个业务分主体更新消息很普遍。这种交易对于单体式应用来说很容易,因为只有一个数据库。
    在微服务架构应用中,需要更新不同服务所使用的不同的数据库。使用分布式交易并不一定是好的选择,不仅仅是因为CAP理论,还因为今天高扩展性的NoSQL数据库和消息传递中间件并不支持这一需求。
    最终你不得不使用一个最终一致性的方法,从而对开发者提出了更高的要求和挑战。

  7. 微服务架构模式应用的改变将会波及多个服务。
    比如,假设你在完成一个案例,需要修改服务A、B、C,而A依赖B,B依赖C。
    在单体式应用中,你只需要改变相关模块,整合变化,部署就好了。
    对比之下,微服务架构模式就需要考虑相关改变对不同服务的影响。
    比如,你需要更新服务C,然后是B,最后才是A,幸运的是,许多改变一般只影响一个服务,而需要协调多服务的改变很少。

  8. 部署一个微服务应用也很复杂,一个分布式应用只需要简单在复杂均衡器后面部署各自的服务器就好了。
    每个应用实例是需要配置诸如数据库和消息中间件等基础服务。
    相对比,一个微服务应用一般由大批服务构成。
    例如,根据Adrian Cockcroft,Hailo有160个不同服务构成,NetFlix有大约600个服务。
    每个服务都有多个实例。
    这就造成许多需要配置、部署、扩展和监控的部分,
    除此之外,你还需要完成一个服务发现机制,以用来发现与它通讯服务的地址(包括服务器地址和端口)。
    传统的解决问题办法不能用于解决这么复杂的问题。
    接续而来,成功部署一个微服务应用需要开发者有足够的控制部署方法,并高度自动化。

微服务架构相关技术(java)

  1. 服务注册和服务发现:consul
  2. 服务健康检查:consul
  3. 配置管理:consul、etcd
  4. 集群容错:hystrix
  5. 计数监控:metrics
  6. 服务路由:ribbon
  7. 服务通信:retrofit、AsyncHttpClient(不选择okhttp,是因为okhttp性能比较差)
  8. 文档输出:swagger
  9. 日志统计:logback+ELK
  10. 简化代码:lombok
  11. 消息队列:rabbitmq
  12. 分布式锁:redis实现和consul实现
  13. 本地缓存:guava cache
  14. 链路跟踪:zipkin、spring-cloud-sleuth
  15. 基本技术:springboot

微服务最佳实践原则

  1. 自动化:自动构建、自动测试、自动部署。
  2. 围绕业务能力建模服务,松耦合、高内聚、暴露接口而隐藏实现细节。
  3. 服务协作模型:中心化(乐队模型:中心指挥)和去中心化(舞蹈模型:群舞自组织),各自场景不同。
  4. 服务交互方式:RPC/REST/WS 技术很多但考虑统一。
  5. 服务部署的独立性、失败隔离性、可监控性。
  6. 服务流控:降级、限流
  7. 服务恢复:多考虑故障发生如何快速恢复而非如何避免发生故障。
  8. 服务发布:灰度
  9. 服务部署:一服务一主机模型,需要虚拟化(Hypervisor)、容器化(LXC, Docker)等技术支持,实现硬件资源隔离。
  10. 服务配置:中心化配置服务支持
  11. 康威定律:任何设计系统的组织,最终产生的设计等同于组织之内、之间的沟通结构。系统架构的设计符合组织沟通结构取得的收益最大。
  12. 伯斯塔尔法则:服务健壮性原则 —— 发送时要保守,接收时要开放。
  13. 小体积, 微服务最基础的原则就是每一个应用程序都比较小,它只做一件事情并且要把它做好。
  14. 拥有事务边界。明确定义消息属于哪里是非常重要的,哪怕整个系统的状态并不确定。
  15. 自监控。微服务应该对外暴露它本身以及它所依赖的各种资源的状态的信息。用户能够通过JMX等方式获取统计数据,例如处理消息的平均、最短和最长时间,成功的和失败的消息数,内存的使用情况等。
  16. 容错性。每一个微服务都能失败或者无响应一段时间,但是这并不会导致整个系统崩溃。微服务应该具有容错性并且能够恢复。
  17. 高度可配置。通过配置拥有不同的自由度。
    支持智能终端。 17. 微服务喜欢REST协议和轻量级的消息而不是Web服务。
  18. 可测试。消息流的测试和业务POJO的测试相互隔离。
  19. 单独配置。 微服务最重要的特性就是每个服务都是独立运行的,最常见的形式就是作为单独的Java应用程序。
  20. 语言中性。小而独立部署的应用程序让开发人员能够为指定的任务选择最合适的语言。

自进化的微服务架构

早期人们把软件开发和建筑学作类比,Architect 这个词来就源于建筑学,但软件产品和建筑物的性质完全不同。

建筑物本身一旦建成则几无变化了,唯有老化后被替代了。

软件系统会在其生命周期中不断变化,唯一不变的就是变化,拥抱变化,需用进化的观点看待架构演进。

与此类似的是城市,城市的演进发展总是渐进式的,我们不会在一座旧城旁建一座新城,然后把旧城的居民迁到新城然后再把旧城废弃了。

但经常我们会用这样的方法重写一个新系统并替换掉旧系统,付出高昂的成本。

而微服务架构思路是不鼓励这种方式的,系统的演进是通过局部的新增、改进或替换微服务来实现的。

而微服务本身的变化周期是不同步的,从整体上就形成了一种渐进式的、符合自然进化的系统演进道路。

所以 Architect(架构师)更像是城市规划师而非建筑师,对软件系统进行类似城市划分区域的规划。

从常识上我们知道把学校和住宅放在一个区域内是合理的,但如果再放一个垃圾处理厂则不合理。
学校和住宅就是提供两种不同能力的服务,垃圾处理厂是另一种服务,但现实中软件系统的规划其实不像城市规划那么有常识性,
这是架构师能力和经验发挥作用的地方,前期规划的不合理会在后期带来维护成本的放大。
每个历史悠久的城市都有各自不同的味道,城市中的人、时间、技术进步共同决定了今天城市的面貌。

微服务架构的妙处就在于它符合城市历史演进规律,随着人员变化、时间、技术改进而引发自然渐进式的进化。

微服务架构与架构师

  1. 架构师的一个角色是技术决策者,技术决策涉及很多权衡取舍(trade-off),而微服务架构给了架构师更多权衡取舍的空间。
  2. 每个微服务实现层面的技术决策更多由服务负责人决定,服务的分拆伴随着决策权和责任的分拆,这也减轻了整体应用负责人的责任负担。
  3. 架构师解放出来从整体和全局上将更加关注服务之间是如何交互,并确保能正确的监控系统全局的健康性。
  4. 分拆了服务实现的技术决策权,那何时又该适当的介入以避免服务实现不当危及整体系统的安全?
  5. 就像教孩子骑车,你无法代替它们去骑,你小心的看着他们骑的歪歪扭扭,担心他们摔倒。事实上,孩子骑车摔倒的次数比你担心的要少,但如果每快摔倒时都去扶住,那么他们也许永远学不会骑车。 当孩子骑车失控时冲向了繁忙的马路或要冲下路边的深沟,那时才有必要介入去稳住他们。
  6. 架构师工作在抽象和具体两个层面:
    架构是一项技术工作,技术工作要服务于组织的战略目标。
    大量的工程实践在每日的工作中不断变化,而渐渐稳定的实践方式被抽象提炼为一系列原则。
    原则的普及带来整体效率的提升和边际成本的下降,以更有效的支持组织战略目标的快速达成。

  7. 跟踪新技术发展确保能在合适的时候做出正确的取舍折衷。
    让开发人员理解某项技术决策的影响和制约以便最有效的执行,甚至在特定情形下深入到代码的实现层面。
    文章开头说了,这是我们实施系统的第四个大版本,而之前每一个大版本升级都是一次旧城倒新城的整体搬迁。
    而微服务架构天然的自然进化属性是否预示着这应该是最后一个大版本升级了?
    微服务架构述说着没有永恒的架构,只有进化的架构,但微服务架构不是银弹,也没有银弹。

微服务和容器的关系

  1. 微服务架构深度依赖于容器化技术的使用。容器将微服务进程和应用程序隔离到更小的实例里,这些实例仅仅使用虚拟化了的操作系统,而不是整个虚拟机以及VM所包含的整个抽象硬件资源。

  2. 从微服务的运行载体来看,微服务架构的普及,依赖Docker等基于容器的技术在生产领域的大规模普及。微服务的思想,其实在之前的SOA的架构就萌发了,但是那事面向服务的思想,而少了一个“微”字。服务内部,依然是一个大杂烩。微服务,有点像原子,没有办法再进行切割。其核心的思想是每一个微服务的实体就是一个小的自治系统。这个实体不依赖其他的实体而独立存在,运行。它能快速的创建,也能快速的销毁。能够相互组合,也能快速拆散。容器技术,为这种“原子”提供了一个很好的执行载体。而Docker技术,就是他们相互组合的粘合剂。但是,从目前的现状来看,Docker在生产领域还尚未有大规模应用。这也是微服务技术无法大规模普及的原因之一。

  3. 微服务架构,和一个公司的研发团队的组织架构也有关系。如果一个公司,其团队按照服务进行划分,彼此松散耦合,就很容易践行这种微服务架构。如果按照职能进行划分,所谓的按照设计,前端,后台,测试,运维等划分,这种微服务架构,就很难玩的转。

微服务注册,发现

  1. zookeeper
  2. consul

基础镜像选择,构建

  1. python基础镜像
  2. 系统基础镜像
  3. alpine

自动化编译,打包,测试,分发,部署,监控,警告,日志

  1. CI系统:持续化部署,gitlab-ci,jenkins

docker registry

集群的管理

  1. mesos+marathon
  2. rancher
  3. kubernetes
  4. swarm
  5. 集群最重要的部分是集群的监控,怎么去管理容器,管理主机

微服务实践

  1. 微服务实战(一):微服务架构的优势与不足
  2. 微服务实战(二):使用API Gateway
  3. 微服务实战(三):深入微服务架构的进程间通信
  4. 微服务实战(四):服务发现的可行方案以及实践案例
  5. 微服务实践(五):微服务的事件驱动数据管理
  6. 微服务实践(六):选择微服务部署策略
  7. 微服务实践(七):从单体式架构迁移到微服务架构
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注