前言
自从2015年的微服务元年开始, 微服务就已经成为了当前软件开发领域的热门话题. 越来越多的博客, 文章, 演讲都是围绕着微服务展开. 那微服务到底是什么东西, 和我们常见的架构, 以及我们现在开发的模式有什么异同点?
这系列文章, 我将尝试基于我了解到的知识, 以及阅读的文章来对微服务涉及到的知识做一个入门的介绍. 文章内容将会包含以下内容:
微服务概述, 优点及缺点
服务划分
服务间通信方式
事务处理
服务间交互的挑战
CI\CD的挑战
对外服务
希望通过阅读这系列文章, 各位能大致了解微服务架构, 并能在工作中运用相关的知识来设计服务.
monolithic服务
微服务相对应的是monolothic
服务. 一般翻译为巨石服务
, 或者单体服务
. 在项目开始的时候, 往往都是先收集一波需求, 经过模块化的设计后, 套上一套现成的服务框架, 就开始编写服务了. 通常情况下, 服务的架构类似于下图:
这类架构被称作 modular hexogonal architecture
, 其特点是:
核心服务被拆成了多个模块
-
包含了一系列的组件, 例如
处理请求, 并返回相应的数据
业务逻辑
访问数据库组件
应用集成逻辑, 用于发送消息等
虽然经过了模块化设计, 但整个核心服务仍作为整体进行部署
通过增加拷贝, 服务是可以平行扩容的
优点
开发简单. 代码都在一个code base里, 获取到全部的代码就可以开始开发
调用都在本地, 调用成本低廉
缺点
这种架构在业务初期能快速支持迭代开发, 而且得益于其整体部署的策略, 使得部署, 扩容都十分容易. 但, 随着业务的快速发展, 模块的规模不断扩大, 开发人员不断的增多, 弊病就展现出来了.
代码可读性降低. 随着功能不断迭代与开发, 代码的复杂性不断的增强, 使得新人接手代码的难度变得越来越大. 当新人加入后, 需要了解的系统模块往往会非常多且繁杂, 细节居多. 从而导致学习的难度大幅增加. 进而延缓了新人发挥战力的时间, 从而拖慢了整体开发及bug修复的时间.
资源竞争. 核心模块中, 不同模块对资源的需求是不同的. 有的可能更消耗内存, 有的则重度依赖I/O. 因为同时部署在一台机器上, 所以想要分离开是不可能的.
并行开发难度增大. 因为所有人都基于一个代码仓库进行开发. 在特性开发的过程中, 冲突的可能性会增大不少, 从而使得合并代码更为困难.
服务的可用性降低. 显而易见, 如果一个模块中出现了bug, 那整个服务都会处于不可用的状态.
技术栈切换成本高. 现在技术发展非常快, 新的框架, 工具层出不穷. 在服务迭代的过程中, 有可能某个工具或者框架非常合适某个模块. 但由于语言\框架等原因, 使得引入工作编的十分困难. 此外, 在跨团队的配合的场景下, 不同团队间使用的技术栈可能完全不同.
微服务
为了解决这类单体应用的弊病, 微服务就被提出来了. 微服务是一种架构模式, 其特点是:
-
一组小的服务
微服务是一组小的服务. 拆分的规则, 具体多小算作是微服务并没有特别限制. 一般来说, 一个开发者能阅读理解, 即可成为微服务.
-
独立的进程
每个服务都是一个独立的进程. 比如说docker容器中的一个容器, 或者一个tomcat的一个jar包等.
-
轻量级的通信
服务之间通过API或者消息机制来进行通信.
-
基于业务拆分
类似于模块化设计, 微服务也是根据业务的需求, 对单体服务进行拆分, 形成了多个小的服务. 单个微服务类似于前面提到的单体服务, 完整包含了业务逻辑, 暴露的API接口, 与外部交互的接口. 常见的类似于登录服务, 用户管理服务, 订单服务等.
-
独立数据源
每个微服务具有自己的数据源.
-
独立部署
每个服务之间是独立部署的. 单个服务可以有多个拷贝, 以提高服务的吞吐能力和性能.
-
松耦合, 无集中化管理
服务之间松耦合, 仅以API等方式进行交互. 不同服务可以采用完全不同的技术栈, 数据库等设施. 服务的负责团队具有很高的自主权.
-
SOA-like
微服务的架构非常类似于传统的SOA. 都是以服务为核心进行构建. 相较于传统的SOA, 微服务更为落地及轻量, 例如使用了更为轻量级的协议(REST或者RPC), 抛弃了ESB而使用类似于ESB的实现等.
以上面的单体应用为例, 拆成相应的微服务之后, 整体架构会变成:
每个模块都相应的拆成了独立的服务. 服务与服务之间独立部署, 并提供相应的REST接口用于调用. 而原来的模块间调用就变成了服务间的调用.
每个服务代表了某块业务, 包含了该业务的所有处理逻辑. 根据每个业务的不同特性, 服务可以选择最适合自己的存储数据库.
引入的动机
那什么时候需要引入微服务呢? 这里需要考虑到的方面比较多, 一般来说, 会考虑到的推动力如下:
-
单个服务涉及到多个团队
单个服务如果涉及到了多个团队, 协同开发以及沟通的成本会大大增加. 此时, 使用微服务, 通过定义接口的方式, 能提高各自的开发效率. 同时, 不同团队间, 可以根据团队的特点, 各自定义自己服务的架构和技术栈.
-
服务分享
服务以接口方式提供给其他方进行调用, 方便数据共享等操作
-
团队新成员必须快速上手
单一项目代码复杂度到达一定程度, 希望通过解耦的方式, 来降低新人学习的难度
应用应该易于理解和修改
-
你想对应用进行持续集成
通过引入CI\CD工具, 配合自动化测试, 从而提高开发效率, 增强代码的质量, 降低发布的难度. 大型的单体服务, 由于涉及到的模块很多, 操作复杂. 使得单元测试等方式不容易执行. 通过划分成微服务, 单个服务所承载的功能和逻辑较少, 使得单元测试更为简单.
-
你必须在多台机器上部署多份应用的拷贝,以满足可伸缩性和可用性的要求
每个微服务的可用性, 性能的需求都不同. 通过分离单体服务成为多个微服务的方式, 可以根据每个服务的具体情况, 来修改服务的数量, 从而达到性能\成本的均衡.
-
你想使用新技术(框架、编程语言等)
由于没有集中化的管理, 使得每个团队可以根据自己的技术栈来修改服务的实现. 同时, 因为每个服务的规模不会很大, 从而使得调整技术栈, 引入新技术成为可能
优缺点比较
微服务不是个灵丹妙药, 适用于任何场景. 微服务核心就是将原有的系统变成了分布式系统. 服务与服务之间的调用从函数调用变成了远程的服务调用. 整体上来看, 微服务带来的优点和缺点:
优点
-
强模块边界
传统开发, 我们会使用MVC等方式对系统进行划分, 以类等方式做抽象, 按层进行开发. 微服务在这方面更为极端. 以服务的模式, 通过API调用来提供能力.
-
独立部署
服务相对来说更为独立. 开发, 发布, 部署不需要涉及到多个团队来做集成和回归测试. 方便频繁部署新版本.
-
提高故障隔离能力.
服务之间不会相互影响. 即使某个服务引入了内存泄漏等问题, 也不会导致整个服务挂掉.
-
单服务规模更小
由于单服务规模较小, 从而更便于新人学习, 接手代码.
-
按需扩容服务
每个服务可以按照实际的需求来增加拷贝
-
更贴合组织架构
服务可以根据组织架构的层面进行切分, 每个团队负责其中单个或多个服务. 每个团队独立于其他团队进行开发\部署, 减少项目之间交流成本.
-
提高技术多样性, 减少对单一技术栈的长期投入
服务之间项目不影响. 团队可以根据自己的技术栈来构建服务. 对于某些场景, 可以使用更贴合的数据存储方式来存储. 前端团队可以使用
nodejs
来构建自己的服务, 后端团队可以使用java
,go
来支撑数据.
缺点及挑战
-
分布式引入的复杂性
微服务是分布式服务的一种形式. 通过将服务拆解微服务, 就引入了分布式的一些经典问题. 譬如
服务间通信
服务发现
错误处理
-
事务以及一致性问题
单个微服务会有自己的数据库. 这也使得跨业务的事务成为了一个棘手的难题. 在单体模式下, 服务连接的是同一个数据库. 这使得在处理事务的过程中, 只需要使用数据库提供的
2PC
就可以解决了. 但是在微服务下, 跨服务间的事务, 则必须交由业务处理.此外, 由于
CAP
原则, 数据一致性也会成为一个问题. 通常情况下, 在互联网业务中都会倾向于最终一致性
以来保证更高的服务吞吐量. -
测试
在微服务下, 由于服务间的关系更为疏远. 服务与服务之间调用关系更为复杂, 从而导致集成测试就更为难做. 而且, 引入微服务往往意味着团队在遵循敏捷开发模式, 测试如何能支撑快速迭代与发布, 也是需要考虑的.
-
部署
在微服务下, 由于每个服务单独部署, 而不同服务依赖的环境可能完全不同, 需要的拷贝数量也不同, 需要的配置也不同. 这对于运维团队带来了更大的挑战.
总结
微服务其实并不神秘. 从整体上来看, 微服务就是原有的模块化设计转化成服务化设计. 将单体的应用整合成为服务间的调用, 从而更好的适应互联网的开发及服务场景. 例如
服务分享
快速迭代
高性能高可用
跨团队合作
当然, 微服务也带来了很多挑战, 需要基础设施来解决:
更好的集成能力
更好的快速部署方式
简单的服务间发现\通信方式
服务监控, 包括日志, metrics
对于各个大型的互联网厂商来说, 微服务早已经实践许久. 从netflix
的微服务改造, 从而贡献出多种优秀的微服务组件, 例如consul
, eureka
, 到单语言, 全解决方案的spring boot
框架, ali的dubbo
, 腾讯开源的tars
, 都很好的支撑了微服务的发展. 但整体来说, 使用微服务的成本还相对较高, 需要有专门的团队来维护这套基础设施, 才能很好的把微服务使用起来.
然而, 随着云厂商的兴起, ci/cd工具的流行, 尤其是k8s的逐渐成熟, 使得容器化部署, 服务发现, 快速扩容等问题对于小团队来说不再是个问题. 再搭配上最新的service mesh
, 引入微服务的门槛不断降低, 使得微服务越来越被广大开发者接受.