一文带你了解微服务架构和设计(多图)

南岳衡阳(封面)

最近几年微服务很火,你们都在建设微服务,若是不懂点微服务相关的技术,都很差意思跟同行打招呼了,也见过身边不少人在微服务踩过不少坑,我从 16 年开始接触微服务,有多家大型企业的微服务分布式系统的架构经验,因此就打算跟你们作一期关于微服务的分享,不过微服务和涉及的分布式计算很是的复杂,绝非是一篇文章就能够讲清楚的,本文只是从最简单的概念的基本使用带你入门,若是后续还有兴趣的话,能够查阅相关的文献和技术书籍去深刻学习git

本文的微服务分享如下三部分,整体大纲以下:github

  • 微服务的概念和原则(理论)
  • Spring Cloud 如何低成本的实现微服务(实现)
  • Spring Cloud 大型项目的架构方案(真实案例)

微服务的概念和原则

什么是微服务?

简单举例:看军事新闻的同窗应该都知道,一艘航空母舰做战能力虽然很强,可是弱点太明显,就是防护能力太差,单艘的航空母舰不多单独行动,一般航空母舰战斗群才是主要军事力量,你能够把单艘航母理解为的单体应用(防护差,机动性很差),把航母战斗群(调度复杂,维护费用高)理解为微服务。spring

简单讲特征就是:数据库

  • 单体应用:简单,脆弱(某个模块出问题,整个系统不可用),战斗力弱,维护成本低
  • 微服务架构:复杂,健壮(某个模块出问题,不会影响系统总体的可用性),战斗力强,维护成本高
单体做战的应用

单体做战的应用(图)编程

微服务战斗群

微服务战斗群(图)api

大部分的开发者经历和开发过单体应用,不管是传统的 SSM,仍是如今的 SpringBoot/Rails,它们都是单体应用,那么长期陪伴咱们的单体应用有什么弊端?咱们是面临了什么问题,致使咱们要抛弃单体应用转向微服务架构?我的总结主要问题以下:缓存

  • 部署成本高(不管是修改1行代码,仍是10行代码,都要全量部署替换)
  • 改动影响大,风险高,测试成本高(不论代码改动多小,成本都相同)
  • 由于成本高,风险高,因此致使部署频率低(没法知足快速交付客户需求)

固然还有例如没法知足快速扩容,弹性伸缩,没法适应云环境特性等问题安全

但咱们不一一详谈了,以上的问题,都是微服务架构要解决的问题,至于具体是怎么解决的,咱们先放到后面再聊服务器

hMIKpW

历代应用程序的架构变迁(图)架构

解决什么问题,又引入了什么问题?

咱们先看看微服务能带给咱们什么?微服务架构的特色:

  • 针对特定服务发布,影响小,风险小,成本低
  • 频繁发布版本,快速交付需求
  • 低成本扩容,弹性伸缩,适应云环境

咱们知道一个朴素的理念,没有任何事物是完美的,任何东西都有两面性,有得必有失

那么在选择微服务在解决了快速响应和弹性伸缩的问题同时,它又给咱们带来了什么问题?我的总结以下:

  • 分布式系统的复杂性
  • 部署,测试和监控的成本问题
  • 分布式事务和 CAP 的相关问题

系统应用由原来的单体变成几十到几百个不一样的工程,会所产生例如包括服务间的依赖,服务如何拆封,内部接口规范,数据传递等等问题,尤为是服务拆分,须要团队熟悉业务流程,懂得取舍,要保证拆分的粒度服务既符合“高内聚,低耦合”的基本原则,还要兼顾业务的发展以及公司的愿景,要还要说服团队成员为之努力,而且积极投入,在多方中间取得平衡。

对于分布式系统,部署,测试和监控都须要大量的中间件来支撑,并且中间件自己也要维护,原先单体应用很简单的事务问题 ,转到分布式环境就变得很复杂,分布式事务是采用简单的重试+补偿机制,仍是采用二阶段提交协议等强一致性方法来解决,就要取决对业务场景的熟悉加上反复的权衡了,相同问题还包括对 CAP 模型的权衡,总之微服务对团队总体的技术栈水平总体要求更高

微服务有应该遵循哪些原则?

古人云:兵马未动,粮草先行。建设微服务是须要创建长远规划,不是像写 CMS 那样建好数据库表,而后就开始干活,这样十有八九是会失败的。咱们要进行微服务改造前,架构师要提早作好规划,咱们把这里分为三步,前期阶段,设计阶段,技术阶段

前期阶段,大体要作好以下事情:

  • 和多方充分沟通,确保能符合客户和组织的需求,而且获得认同
  • 和团队沟通,让队友(开发/测试/运维)理解,而且积极投入
  • 和业务部门沟通,指定版本计划和上线时间

设计阶段,参考 Sam Newman 的著做《微服务设计》,单微服务必需要知足如下的条件,才符合微服务的基本要求:

  • 标准的 REST 风格接口(基于 HTTP 和 JSON 格式)
  • 独立部署,避免共享数据库(避免由于数据库而影响整个分布式系统)
  • 业务上的高内聚,减小依赖(从设计上要避免服务过大或者过小)

庞大的分布式系统,须要强大基础设施来支撑,微服务涉及哪些基础设施?

  • CI/CD和自动化(分布式系统几乎不可能经过人工手动发布)
  • 虚拟化技术(要保证微服务运行环境隔离,目前行业主流的是使用 Docker 容器)
  • 日志聚合,全链路监控(高度可观察和分析诊断问题)

说了那么多,那什么样的状况下,你的团队不适合建设微服务?(请勿对号入座)

  1. 开发团队不具有自主性,所在组织对开发团队限制很是多(具体请参考 康威定律
  2. 团队不熟悉业务,没法识别出服务的边界,进行合理的拆分(请参考 DDD 领域驱动设计

微服务设计实际上是很早就有的设计思想,由于随着虚拟化技术的崛起,微服务能够低成本的实现,因此也开始流行和兴起。

微服务的内涵很深,其中就包括,自动化,去中心化,独立性等等,其中细节没法用一篇文章概述清楚,咱们在作技术选型或者方案的时候,尽量多去了解技术的自己和起源再结合咱们业务的特色,进行更好的选择。

如何低成本的实现微服务的 ?

Spring Cloud 为何是国内最流行的微服务框架,它提供哪些开箱即用的组件 ?概览以下:

  • Srping Boot 服务应用
  • Spring Cloud Config 配置中心
  • Spring Cloud Eureka 服务发现
  • Spring Cloud Hystrix 熔断保护
  • Spring Cloud Zuul 服务网关
  • Spring Cloud OAuth 2 服务保护
  • Spring Cloud Stream 消息驱动
  • 分布式全链路跟踪
  • 部署微服务

建议参考资料:微服务架构集成,云计算最佳实践

Spring Boot 微服务基石
Srping Boot Admin

SpringBoot是构建微服务的理想框架,主要得益于 SpringBoot 能够打包成为单个可执行JAR文件交付服务,Spring Actuator 公开服务健康信息都是微服务的基石,为甚么这么说 ?

咱们先看看构建微服务的 4 个重要原则

  • 服务应该是独立和可独立部署的
  • 应该从中央(配置中心)读取配置
  • 对客户端是透明的
  • 传达健康信息

微服务有优势和缺点,并不是全部应用都适合用微服务架构,架构师须要能作到如下要求:

  • 分解业务问题:描述业务问题,注意动词,寻找数据内聚
  • 创建服务粒度:讲大服务重构到更小的服务,重点关注服务如何相互交互,服务职责随时间改变
  • 定义服务接口:拥抱REST的理念,使用URI来传达意图,使用HTTP状态码传达结果

糟糕的微服务有哪些特征?

  • 过于粗粒度:服务承担过多的职责,服务跨大量表来管理数据,测试用例太多
  • 过于细粒度:服务彼此依赖严重,服务内部没有逻辑

什么时候不该该使用微服务 ?

  • 不肯投入(须要高度成熟的运维,伸缩,复杂性问题)
  • 管理 / 监控散乱的服务器也须要很高的成本
  • 小型应用不适合,太昂贵
  • 数据事务(分布式系统处理事务很是困难)
Spring Cloud Config 配置服务

Spring Config 工做原理

Spring Config 是 Spring 提供的配置中心轻量级实现,基于 Git 存储,

国内用户大多推荐使用 Alibaba 开源的 Nacos (集成配置中心和注册中心)都是很是不错的配置中心的实现

微服务程序对于配置中心的几点管理原则:

  • 应用程序的配置和部署的实际代码分离(配置中心和应用程序分离)
  • 集中(将配置中心集中在少许的存储库中)
  • 稳定(配置中心要保证高可用)

Spring Config 这款配置中心提供的核心功能:

  • 配置服务器容许使用环境特定值
  • 使用Spring Profile区分环境值
  • 可使用基于文件或基于Git存储属性
  • 容许对称加密和非对称加密
Spring Cloud Eureka 服务发现

服务发现的运行原理

服务发现是微服务架构中很是重要的概念,也称注册中心相似咱们生活中的房地产中介的角色,买房卖房都要经过它,因此是全部微服务上线/下线的必经之路,也掌握微服务的生杀大权,注册中心会根据 CAP 策略和对微服务的健康检查,做出对具体服务剔除,下线,恢复上线等操做,主要还有如下几个核心功能:

  • 快速对环境中服务数量水平伸缩(功能和 k8s 有些重合,不过也能够设定具体服务的运行时数量)
  • 抽象服务的物理位置(微服务一般运行在 Docker 容器内,没有固定 IP,只能经过注册中心才能找到它)
  • 提升程序的弹性,自动伸缩
  • 信息共享, 健康检测

微服务架构里面要实现注册中心,须要达到哪些基本要求?

  • 高可用,注册信息共享(注册中心集群部署),不可能由于注册中心挂了,致使全部集群不可用
  • 负载均衡(对服务间的动态请求负载均衡),合理在服务间分配流量
  • 有弹性(客户端缓存服务信息)
  • 容错,健康检查(检测坏掉的服务自动移除,无需人工干预)

Spring Cloud Eureka 的工做页面

Spring Eureka 提供的服务发现实现,具有哪些特色 ?

  • 服务发现抽象服务的物理位置
  • 无感知添加和移除服务
  • 为服务间调用提供负载均衡
  • 使用 3种不一样机制来调用服务:DiscoveryClient,支持Ribbon的RestTemplate,Netflix的FeignClient
Spring Cloud Hystrix 熔断保护

tACQPW

熔断的概念很是好理解,好比当咱们家里的消耗电量负载过高,到达设定的阈值的时候,电路系统就会启动熔断机制,也叫过载保护,经过跳闸,强行断电的方式,来保护总体电路的稳定,熔断在微服务中的概念也是同样,是保护是微服务稳定的防火墙,避免单个服务溃崩或者异常致使出现整个集群系统的雪崩和连锁反应现场

为何微服务进行熔断 ?当一个服务出现问题:

  • 一般都是从小部分开始,到耗尽线程完全崩溃
  • 服务间调用会长时间阻塞
  • 服务未关闭就会一直被调用,致使连锁效应
  • 一个性能不佳的服务能够迅速拖垮整个应用

为何熔断很重要 ?

  • 每一个节点(调用服务和数据库)实现断路器,能够避免服务崩溃的连锁效应
  • 实现只有出问题的服务受影响,其他的服务功能都是完整的(影响范围降到最小)
  • 熔断是服务器的灵活的基础

断路器提供的关键能力

  • 快速失败
  • 功能降级(替代方案)
  • 无缝恢复(断路器按期检查,自动恢复服务)

Spring Boot Admin - Hystrix & Turbine

Netflix 研发和出品的 Hystrix 实现是一款成熟稳定的熔断实现,在 Netflix 在生产实践和运行多年,很是可靠,后面加入 Spring Cloud 体系,成为 Spring Cloud 微服务生态链的一员,使用起来也很是的简单和方便

Hystrix 支持 4 种断路模式:

  • 客户端负载均衡模式(检测服务出错,移除服务)
  • 断路器模式(出现超时抛出异常强行失败,超过阈值强行失败全部调用)
  • 后备模式(不是抛出异常而是执行替代方案,例如排队,稍后再试等)
  • 舱壁模式(把远程调用的资源分配到独立的线程池中,调用出问题只是线程池饱和并中止请求)

跳闸会致使的3种结果:

  • 服务B当即知道服务C有问题,没必要等待,当即失败
  • 服务B执行服务C的替代代码来采起行动(后备模式)
  • 服务C能够再跳闸后,检查问题,快速恢复

Spring Cloud Hystrix 实现的流量监控

熔断的几个处理原则:

  • 设计分布式应用必须考虑弹性
  • 服务的完全故障是很容易检测和处理,只是须要时间,断路器给了这个时间窗口
  • 一个服务性能不佳,可能致使集群崩溃,由于相互调用会阻塞线程,耗尽资源
  • Hystrix支持两种隔离模型,即 THREAD 和 SEMAPHORE
Spring Cloud Zuul 网关

网关是整个微服务分布式集群的入口,对于用户来讲,用户无需知道你每一个服务的地址,只须要记住网关地址就能够了,这样理解可能比较抽象,举一个生活的例子,微服务集群是一个大型公司,公司内部有不少个不一样的职能部门(对应每一个微服务),可是你若是要访问具体的职能部门,你必须先到前台登记,再由前台带你到你想访问的具体职能部门去办理实际的业务(智能路由)

微服务对于网关实现的规范:

  • 一个独立负责全部服务调用过滤和路由的服务
  • 服务和客户端的中间人,简化客户端开发

网关一般要作哪些事情:

  • 静态路由,从注册中心获取每一个微服务的具体位置
  • 动态路由(根据参数特色,调用特定服务,少许用户体验新功能,一般用于灰度发布)
  • 验证和受权:验证访客的身份信息(统一验证,服务只须要关注业务逻辑)
  • 数据收集和日志(收集调用次数和响应时间等)

Zuul 网关的具体运行参考图:

Zuul Api Gateway 工做流程

Spring Cloud Zuul 是初期版本的 API 网关实现,提供如下功能:

  • 结合 Spring Cloud Eureka 将服务发现的注册地址加入到 Zuul 路由
  • Zuul 能够给全部服务轻松的添加 /api 之类的前缀路由地址
  • 在全局上定制 Zuul 的 Spring Cloud Hystrix 和 Spring Cloud Ribbon (调度策略)的超时
  • 实现动态路由,不一样版本进行A/B测试
  • 检查参数合法性等,例如 JWT,时间戳等等
Spring Cloud OAuth 2 服务保护

Oauth 2 是用于保证请求的合法和正确性,为了让微服务自己更加专一于业务,因此 OAuth 2 相似配置中心被单独抽离出来做为基础组件的统一认证中心来使用,OAuth 2 的做用相似咱们生活中的公安局的角色,当咱们须要去正规机构办理业务的时候,咱们须要提供有效的身份证(合法的身份认证标示),若是没有你就须要去公安局(OAuth)申请一张在有效期内的身份证(Token),而后带着这张身份证咱们才能去购买机票,酒店等其余社会服务(微服务),社会服务机构在拿到你提供的身份证(Token)后,也会向公安局(OAuth)联网发送信息,来验证你的身份证的合法性(Token 合法性校验),身份认证不经过就会被拒绝服务,合法的身份才能进行业务的办理,关于 OAuth 的工做流程,能够结合下图来理解:

OAuth 工做流程

微服务对于 OAuth2 规范的4中类型受权:密码/客户端凭据/受权码/隐式

Spring Cloud OAuth 2 为咱们提供哪些便利?

  • 安全框架,提供令牌生成,验证等逻辑
  • 开箱即用,和其余服务无缝集成
  • 行业标准,轻松与云服务商集成

OAuth 2:/auth/oauth/token的返回信息

  • access_token(OAuth2令牌,每次调用出示)
  • token_type(令牌类型,经常使用bearer token)
  • refresh_token(续约令牌)
  • expires_in(过时描述,默认12H)
  • scope(令牌有效做用域)

OAuth 2 支持 JWT (JSON Web Token)的规范,关于 JWT 的原理就不特别解释了,简单的 JWT 有如下几个特色

  • 小巧(Base64编码)
  • 密码签名(防篡改)
  • 自包含(不须要调用验证服务确认内容,经过相同的密钥进行对称解密)
  • 可扩展(可在令牌内包含额外的信息)

OAuth 2 的简单总结:

  • OAuth2 是一个令牌验证框架
  • 使用OAuth2 须要创建OAuth2验证服务
  • 调用受保护的资源都要经过OAuth2验证
Spring Cloud Stream 消息驱动

咱们和世界的互动不是同步的,不少时候是基于消息异步驱动模型,好比邮件,点餐,订票等等,想要了解 Spring Cloud Stream,必须先要理解基于事件(MQ)编程的模型,基于消息驱动有利于开发构建高度解耦的系统,由于 Spring Cloud Stream 并非本身实现了消息中间件,而是对于市场上主流(例如 RabbitMQ,KafKa)的 MQ 产品作了一层封装和抽象,Spring Cloud Stream 作的事情并非什么新鲜的事情,很是相似 ORM 所作的事情,了解 ORM 框架的同窗应该都熟悉对于多种数据库(MySQL,Oracle,SQL Server)产品的抽象是何等重要,面向 ORM 进行数据库访问,可让你脱离对于指定数据库产品的深度依赖和绑定,并且能够不用特地去学习不一样数据库的本地化特性和方言,下降学习成本,假如你想从 Oracle 迁移到 MySQL 上面,几乎是不须要改动一行代码,只须要改动 ORM 的配置就能够实现了,参考下图简单了解一下 ORM:

简单了解 ORM

Spring Cloud Stream 相似 ORM,你只须要基于 Spring Cloud Stream 提供的消息模型进行编程,至于底层的消息组件是用的 RabbitMQ 仍是 kafka 仍是其余的消息中间件产品,都没有关系,甚至更换底层消息组件也不会对你的应用产生任何影响,这就是标准化所带来的收益,关于如何更好的理解 Spring Cloud Stream 工做模型能够简单参考下图:

Stream 相似 ORM 的工做流程

微服务中使用的的两种服务通讯方式对比:

  1. 同步:经过REST端点接口进行请求:服务之间紧耦合(强依赖),服务之间的脆弱性(连锁效应),增长新的消费者不灵活

  2. 异步:基于消息中间件通讯:松耦合(无接口直接调用的依赖),耐久性(服务重启后能够消费历史消息),可伸缩性(消息过多可启动多服务来处理消息),灵活性(轻松添加新的消费者)

消息传递架构的缺点:

  1. 消息处理语义:消息顺序处理,消息异常处理
  2. 消息可见性:消息不会马上被处理,事务关联ID在消息中的传递

消息中放置什么数据 ?

  1. 消息体要尽量的小,减小传输成本:一般只返回action类型和id,而后用id获取最新数据
  2. 只使用消息传递状态:在消息中包含版本号和时间戳,处理数据服务能够检查数据的版本号

Spring Cloud Stream 的消息模型和概念:

  • 发射器(Source):接收对象(对象表示要发布的消息),序列化对象,将消息发布到通道
  • 通道(Channel):队列的抽象,通道写在配置文件,更改配置切换通道(读取和写入队列)
  • 绑定器(Binder):与消息平台对话的 Spring 代码,没必要依赖特定的API来发布和消费消息
  • 接收器(Sink):从队列接收消息,将消息反序列化为POJO

Spring Cloud Stream 的简单总结:

  • 使用消息传递的异步通讯是微服务架构的关键部分
  • 使用消息传递可使服务可以伸缩而且更具备容错性
  • Spring Cloud Stream 经过简单的注解抽象底层的消息平台细节
Sleuth 和 Zipkin 分布式跟踪

微服务分布式架构带来了复杂度,成本最高的就是跟踪检查和运维,分布式意味要在多个服务,机器跟踪一个事务,Sleuth 和 Zipkin 都是用于 Spring Cloud 服务体系的分布式跟踪技术,先直接看下最终效果,下图一个简单的可视化链路跟踪调用,ZipKin 能够清晰的看到一个客户端请求在每一个服务上面处理所消耗的事情,点击进去能够看到具体的事务执行内容,方便排查错误

全链路跟踪

Spring Cloud Sleuth 的工做流程:

  1. 透明地建立并注入一个关联ID到服务调用中
  2. 管理关联ID到出站服务调用的传播
  3. 将关联信息添加到Spring的MDC日志记录(应用/跟踪ID/跨度ID/数据发送)
  4. 将服务调用中的跟踪信息发布到Zipkin跟踪平台

Open Zipkin 的简单概述:

  1. 调用链使用一张干净简洁的图片,比一百万条日志要好看的多
  2. 分布式跟踪平台,用于跟踪多个服务调用的事务
  3. 图形的方式查看事务占用的时间量,分解每一个服务所用的时间
  4. 4种不一样的数据存储:内存数据/MySQL/Cassandra/Elasticsearch

关于微服务全链路跟踪的总结:

  • SpringCloudSleuth 能够无缝将关联ID添加到微服务中
  • 可使用关联ID查看事务涉及的全部服务行为
  • 关联ID须要与日志聚合结合使用
  • 日志平台很重要,可是可视化跟踪事务也是有价值的工具
部署微服务

构建和部署管道是微服务架构重最要的部分,微服务的主要特色是快速构建,修改,发布

符合微服务特征的部署要达到如下几个要求:

  1. 自动的(自动构建和部署代码
  2. 完整的(软件成品是镜像),不可变(发布过程不可人为干预)
  3. 良好的微服务部署管道应该容许在几分钟部署新功能和修复bug

Spring Cloud 大型项目的架构方案

真实案例讲解

这是一个真实用于国内某大型企业的微服务架构体系,支撑日均百万订单的项目,由于已通过了2年的保密期,因此能够拿出来分享

恰好能够结合前面凌乱的知识点,看看 Spring Cloud 这套组件是如何搭建起来的,整套微服务就是下面这张架构图:

微服务架构设计-3

具体每一个组件的做用就不在这里详细说明了,在这套架构方案里面

咱们没有彻底照搬 Spring Cloud 全家桶的组建,仍是根据本身的需求对其中组件进行的更换例如:

  • 配置中心从 Spring Cloud Config 更换为 Apollo ,除了有更好的性能,还有更加简化的操做页面,修改配置文件毫秒级响应
  • 服务发现 Eureka 官网已经中止维护,咱们后面更换为 Alibaba Nacos,服务注册和心跳检测都提高到毫秒级,Eureka 是90秒轮询
  • 分布式任务调度引入了 XXL-JOB,这是国内主流的分布式任务调度平台,没有特别须要说明的地方
  • 日志聚合也是用了主流的 ELK 技术方案,用于收集和检索日志

PS:另外在值得补充的是,在写这篇文章的时候 Spring Cloud Zuul 已经不被官方推荐使用了,替代品是性能更好的 Spring Cloud Gateway ,你们能够在了解的时候须要注意一下

最后总结:

微服务是将来大型企业的必经之路,虽然成本很高,可是能够提高 IT 系统的健壮性和提高技术人员的广度和深度都仍是颇有帮助的

相关文章
相关标签/搜索