基于SpringCloud微服务系统设计,5万字总结!

1.微服务本质

微服务架构从本质上说其实就是分布式架构, 与其说是一种新架构, 不如说是一种 微服前端

务架构风格。ios

简单来讲, 微服务架构风格是要开发一种由 多个小服务组成 的应用。 每一个服务运 行于独立的进程 ,而且采用 轻量级交互 。多数状况下是一个 *HTTP* 的资源 *API*。这些服务 具有独立业务能力 并能够经过 自动化部署 方式 独立部署 。这种风格使 最小化集中管理 ,从而可使用多种 不一样的编程语言和数据存储技术 。git

对于微服务架构系统, 因为其服务粒度小, 模块化清晰, 所以首先要作的是对系 统总体进行功能、服务规划 ,优先考虑如何在交付过程当中,从 工程实践出发,组织好代码结构、配置、测试、部署、运维、监控 的整个过程,从而有效体现微服务的独立性与可部署性。web

本文将从微服务系统的设计阶段、开发阶段、测试阶段、部署阶段进行综合阐述。docker

理解微服务架构和理念是核心。数据库

2.系统环境

3.微服务架构的挑战

可靠性:编程

因为采用远程调用的方式, 任何一个节点、 网络出现问题, 都将使得服务调用失败,随着微服务数量的增多,潜在故障点也将增多。后端

也就是没有充分的保障机制,则单点故障会大量增长。api

运维要求高:缓存

系统监控、高可用性、自动化技术

分布式复杂性:

网络延迟、系统容错、分布式事务

部署依赖性强:

服务依赖、多版本问题

性能(服务间通信成本高) :

无状态性、进程间调用、跨网络调用

数据一致性:

分布式事务管理须要跨越多个节点来保证数据的瞬时一致性, 所以比起传统的单体架构的事务,成本要高得多。另外, 在分布式系统中,一般会考虑经过数据的最终一致性来解决数据瞬时一致带来的系统不可用。

重复开发:

微服务理念崇尚每一个微服务做为一个产品看待, 有本身的团队开发, 甚至能够有本身彻底不一样的技术、 框架, 那么与其余微服务团队的技术共享就产生了矛盾, 重复开发的工做即产生了。

4.架构设计

4.1. 思惟设计

微服务架构设计的根本目的是实现价值交付, 微服务架构只有遵循 *DevOps* 理念方可进行的更顺畅,思惟方式的转变是最重要的。

实现微服务技术架构, 现有产品须要进行技术上的改进以及相关配套服务的实现,段实施、以及试点产品优先实施的策略 ,主要包括以下:

1、技术上的改进:

一、先后端分离, web 前端经过 Http/Https 协议调用微服务的 API 网关,由API 网关再通过路由服务调用相应的微服务

二、不一样微服务之间经过 REST方式互相调用

三、微服务之间经过消息中间件实现消息交互机制

2、配套服务与功能实现 :

一、须要进行相应的自动化服务实现, 包括自动化构建、 自动化安装部署、 自动化测试、自动化平台发布( Docker 实现)

二、管理服务,对于微服务架构,必须配套相应的监控与管理服务、日志管理服务等

三、协做服务,运用 DevOps 思想提高开发、测试、运维的高效沟通与协做,实现开发与运维的一体化

4.3. 微服务架构设计

一、咱们把整个系统根据业务拆分红若干个子系统或微服务。

二、每一个子系统能够部署多个应用,多个应用之间使用负载均衡。

三、须要一个服务注册中心 Eureka,全部的服务都在注册中心注册,负载均衡也是经过在注册中心注册的服务来使用必定策略来实现。*Eureka*可部署多个,进行高可用保证。

四、全部的客户端都经过同一个网关地址访问后台的服务,经过路由配置 ZUUL 网关来判断一个 URL请求由哪一个服务处理。请求转发到服务上的时候使用负载均衡 Ribbon。

五、服务之间采用 feign 进行调用。

六、使用断路器 hystrix ,及时处理服务调用时的超时和错误, 防止因为其中一个服务的问题而致使总体系统的瘫痪。

七、还须要一个监控功能,监控每一个服务调用花费的时间等。

八、使用 SpringCloud Config 进行统一的配置管理,须要考虑与公司的配置管理平台如何配合使用。

九、 Hystrix,监控和断路器。咱们只须要在服务接口上添加 Hystrix 标签,就能够实现对这个接口的监控和断路器功能。

十、Hystrix Dashboard ,监控面板,他提供了一个界面,能够监控各个服务上的服务调用所消耗的时间等。

十一、 Turbine,监控聚合,使用 Hystrix 监控,咱们须要打开每个服务实例的监控信息来查看。而 Turbine 能够帮助咱们把全部的服务实例的监控信息聚合到一个地方统一查看。

这样就不须要挨个打开一个个的页面一个个查看。

架构的可靠性保证:

在关键节点作主备、集群部署,防止单点故障。

待后续确认问题:

一、 Access Control: Zuul网关提供了相关控制功能,与我司CAS如何结合使用

二、 Config Server: Spring Cloud 提供了远程配置中心,与我司的配置管理平台如何结合使用

5.设计阶段

5.1. 整体设计

一、功能规划 :对产品功能进行拆分,拆分为若干个微服务;一个功能能够建立多个微服务并部署在多个服务器节点上,以便进行负载均衡。

二、设计 原子服务层 ,梳理和抽取核心应用、公共应用,做为独立的服务下沉到核心和公共能力层,逐渐造成稳定的服务中心,使应用能更快速的响应多变的客户需求。

三、为每一个服务 设计 *API* 接口 ( REST方式)

四、为不一样的 服务进行分类 ,不一样类型的服务须要的资源不一样,能够配置不一样的资源,包括 CPU、内存、存储等。

5.2. 服务拆分原则

*1*、粒度微小:

根据业务功能划分服务粒度,总的原则是服务内部高内聚,服务之间低耦合。

*2*、责任单一:

每一个服务只作一件事,即单一职责原则。

*3*、隔离性原则:

每一个服务相互隔离,且不互相影响

*4*、业务无关优先原则:

基础服务,是一些基础组件,与具体的业务无关。好比:短信服务、邮件服务。这里的服务最容易划分出来作微服务,也是咱们第一优先级分离出来的服务。

5.3. 服务规划

为实现负载均衡, 容许相同的服务在多个节点注册相同的服务名, 不一样的端口。 若是没有前期的规划, 不一样的服务提供者可能会注册相同的服务名, 致使消费者调用服务时产生调用混乱。

所以,需进行服务名的统一规划:

一、规划期统一制定每一个服务提供者的服务名或者模块标示。

二、服务名的命名规则:ModuleName_ServiceName,且 全部字符小写,不一样单词之间如下划线分隔 。如用户管理模块提供了获取用户信息的服务,则命名为:user_get_info 。

三、新增服务名时,须要提出申请, 审批经过后方可以使用 ,为减小审批复杂度,可只审批 ModuleName ,即在模块内部能够自由增长服务名,不须要进行审批。

没有最好的,只有最适合本身的。

5.4. 开发策略

整体原则:不一样的微服务需进行 物理隔离。

一、 SVN 策略: SVN上建立 独立的分支 ,不一样微服务的代码提交不受相互影响;

*---*由配置管理员统一控制。

问题:开发分支与集成分支,都将增长不少,维护工做量增长。

二、编译策略:代码编译时,各个微服务独立编译、打包, 杜绝直接的依赖 ;

三、工程构建:代码开发时,各微服务 建立独立的工程 ,工程之间不能产生直接依赖

四、持续集成:每一个微服务 独立执行持续集成 。

五、版本集成:由统一的集成工具,实现自动化的版本集成,将全部微服务集成到统一的版本发布包中。

5.5. 版本策略

每一个微服务能够独立制做版本,伴随着服务的增多, SVN分支增多,版本也将增多,版本管理的复杂度将成指数级增长。 在服务之间依赖较多时, 每一个服务的升级或降级都将影响其余服务的正常运行。

所以需执行以下策略:

一、全部服务的版本制做交由专业的版本管理员执行。

二、采用自动化的版本制做策略,最大程度的减小人工操做。

三、每一个服务的版本必须有详细的版本计划、版本说明,对于版本说明要制定模板,明确须要提交的内容、版本号、 SVN标签等。

四、对项目经理的要求提高,需对总体的版本计划有严格的制定,尤为是版本之间的依赖关系要很是明确,版本升级、降级的 风险评估 需彻底充分。

五、接口管理: 严格执行接口管理制度, 任何接口的变动必须进行审批、 发公告等流程。

5.6. 数据库挑战与策略

每一个微服务都有本身独立的数据库, 那么后台管理的联合查询怎么处理?这应该是你们会广泛遇到的一个问题,有三种处理方案。

1)严格按照微服务的划分来作,微服务相互独立,各微服务数据库也独立,后台须要展现数据时, 调用各微服务的接口来获取对应的数据, 再进行数据处理后展现出来, 这是标准的用法,也是最麻烦的用法。

2) 将业务高度相关的表放到一个库中,将业务关系不是很紧密的表严格按照微服务模式来拆分,这样既可使用微服务,也避免了数据库分散致使后台系通通计功能难以实现,是一个折中的方案。

3)数据库严格按照微服务的要求来切分,以知足业务高并发,实时或者准实时将各微服务数据库数据同步到 NoSQL 数据库中,在同步的过程当中进行数据清洗,用来知足后台业务系统的使用,推荐使用 MongoDB 、HBase 等。

第一种方案适合业务较为简单的小公司; 第二种方案, 适合在原有系统之上, 慢慢演化为微服务架构的公司;第三种适合大型高并发的互联网公司。

建议,咱们当前采用第二种方案。

5.7. 负载均衡

再也不采用通常的增长负载均衡服务器的方式进行负载均衡,如 F五、 Nginx、 LVS 等,而是把负载均衡的功能 以库的方式集成到服务消费方的进程内 ,这种方案称为 软负载均衡( Soft Load Balancing)或者客户端负载均衡。 在 Spring Cloud 中配合 Eureka 的服务注册功能,Ribbon 子项目则为 REST客户端实现了负载均衡。

使用 Ribbon 进行负载均衡,其工做原理能够归纳为下面四个步骤:
1. Ribbon 首先根据其所在 Zone 优先选择一个负载较少的 Eureka Server;
2. 按期从 Eureka Server 更新并过滤服务实例列表 ;
3. 根据指定的负载均衡策略,从可用的服务器列表中选择一个服务实例的地址 ;
4 而后经过 RestClient 进行服务调用。

Ribbon 自己提供了下面几种负载均衡策略:

RoundRobinRule:轮询策略,Ribbon以轮询的方式选择服务器,这个是默认值。因此示例中所启动的两个服务会被循环访问 ;

RandomRule: 随机选择,也就是说 Ribbon 会随机从服务器列表中选择一个进行访问

BestAvailableRule: 最大可用策略,即先过滤出故障服务器后,选择一个当前并发请求数最小的;

WeightedResponseTimeRule: 带有加权的轮询策略, 对各个服务器响应时间进行加权处理,而后在采用轮询的方式来获取相应的服务器 ;

AvailabilityFilteringRule: 可用过滤策略,先过滤出故障的或并发请求大于阈值一部分服务实例,而后再以线性轮询的方式从过滤后的实例清单中选出一个 ;

ZoneAvoidanceRule: 区域感知策略, 先使用主过滤条件 (区域负载器, 选择最优区域)对全部实例过滤并返回过滤后的实例清单,依次使用次过滤条件列表中的过滤条件对主过滤条件的结果进行过滤,判断最小过滤数(默认 1)和最小过滤百分比(默认 0),最后对知足条件的服务器则使用 RoundRobinRule( 轮询方式 ) 选择一个服务器实例。

5.8. 性能策略

一、网络优化:优化组网结构,提高网络间通信性能;

二、配置优化:优化 Spring Cloud 组件集以及其余组件的配置信息,使得性能最大化。

5.9. 技术管理策略

微服务的架构理念中指出各微服务能够 独立建设,可使用不一样的技术、语言、框架等,以便能更快速的使用新技术、 新框架等响应特定客户需求, 解决单体应用架构更新技术、更新框架时面临的困难或阻碍。

但这也同时带来了诸多问题,以下:

一、各服务是否能够任意使用本身的技术、本身的组件、框架呢?若是这样,势必带来更大的管理困难、维护困难、技术共享困难。

二、公共的方法如何实现共享?如格式化时间的一个简单方法须要共享,也须要封装为一个服务接口吗?

管理策略:

一、整体原则:仍然须要进行统筹考虑,全部组件统一管理,组件放置在产品仓库中,每一个产品或服务须要共享组件时,从产品仓库获取。

二、特殊状况:特殊服务须要使用特殊的组件、框架,需提出申请,统筹规划后进行决策。

6.开发阶段

6.1. 服务的调用

6.1.1. AIP网关调用

全部服务经过 Zuul 网关进行调用,不容许直接调用微服务提供者。

Zuul 可能会成为系统瓶颈,在项目复杂时可考虑为 Zuul 进行主备或负载均衡处理。

6.1.2.同步调用

采用 HTTP REST方式进行调用, 针对业务需求能够进行负载均衡, 负载均衡的调用方式有两种:

一、 FeignClient

二、 RestTemplate

建议使用 *FeignClient*方式进行服务调用。

无论是什么方式,他都是经过 REST接口调用服务的 http 接口,参数和结果默认都是经过 Jackson 序列化和反序列化。由于 Spring MVC 的 RestController 定义的接口,返回的数据都是经过 Jackson序列化成 JSON数据。

6.1.3.异步调用

rabbitMq 、 kafka、 Spring Cloud Stream 均是能够选择的方案。

Spring Cloud Stream ,基于 Redis、Rabbit 、Kafka 实现的消息微服务, 简单声明模型用以在Spring Cloud 应用中收发消息。

6.1.4. 服务间调用的权限验证

通常咱们的 API接口都须要某种受权才能访问, 登录成功之后, 而后经过 token 或者 cookie等方式才能调用接口。使用 Spring Cloud Netfix 框架的话,登陆的时候,把登陆请求转发到相应的用户服务上,登录成功后, 会设置 cookie 或 header token 等。而后客户端接下来的请求就会带着这些验证信息,从 Zuul 网关传到相应的服务上进行验证。

Zuul 网关在把请求转发到后台的服务的时候,会默认把一些 header 传到服务端,如:Cookie、Set-Cookie、Authorization 。这样, 客户端请求的相关 headers 就能够传递到服务端,服务端设置的 cookie 也能够传到客户端。

可是,若是你想禁止某些 header 透传到服务端,能够在 Zuul 网关的 application.yml 配置里经过下面的方式禁用:

刚才说了咱们的某个服务有时候须要调用另外一个服务,这时候,这个请求不是客户端发起,他的请求的 header 里面也不会有任何验证信息。这时候,要么,经过防火墙等设置,保证服务间调用的接口,只能某几个地址访问;要么,就经过某种方式设置 header 。

同时,若是你想在某个服务里面得到这个请求的真是 IP ,(由于请求的经过网关转发而来,你直接经过 request 得到 ip获得的是网关的 IP ),就能够从 headerX-Forwarded-Host 得到。若是想禁用这个 header,也能够:

若是你使用 RestTemplate 的方式调用,能够在请求里面添加一个有 header 的 Options 。也能够经过以下的拦截器的方式设置,它对 RestTemplate 方式和 FeignClient 的方式均可以起做用:

@Bean

public RequestInterceptor requestInterceptor() {

return new RequestInterceptor() {

@Override
public void apply(RequestTemplate template) {
String authToken = getToken();
template.header(AUTH_TOKEN_HEADER, authToken);

}
};
}

6.1.5.服务编排

主要的做用是减小项目中的相互依赖。好比如今有项目 a 调用项目 b,项目 b 调用项目c...一直到 h,是一个调用链,那么项目上线的时候须要先更新最底层的 h 再更新 g...更新 c更新 b 最后是更新项目 a。这只是这一个调用链,在复杂的业务中有很是多的调用,若是要记住每个调用链对开发运维人员来讲就是灾难。

有这样一个好办法能够尽可能的减小项目的相互依赖, 就是服务编排, 一个核心的业务处理项目,负责和各个微服务打交道。好比以前是 a 调用 b, b 掉用 c, c 调用 d,如今统一在一个核心项目 W 中来处理, W 服务使用 a 的时候去调用 b,使用 b 的时候 W 去调用 c。

其实能够理解为面向对象的设计, 减小方法之间的一层层嵌套调用, 而采起一个方法进行业务流程的串联,如方法 W 实现一个完整的业务处理,则采起下面方式:

function w ()

{

一、调用方法 a;

二、调用方法 b;

三、调用方法 c;

}

6.2. 服务的熔断处理

在服务之间进行调用时, 因为各类缘由会致使远程 服务不可用 或压力过载等异常致使的故障蔓延 ,此时须要有一种机制进行保护处理。 Spring Cloud 经过 Netflix 的 Hystrix 组件实现熔断和降级 处理解决此问题。断路器 (Cricuit Breaker) 是一种可以在远程服务不可用时自动熔断(打开开关 ),并在远程服务恢复时自动恢复 (闭合开关 )的设施, Spring Cloud 经过 Netflix 的Hystrix 组件提供断路器、资源隔离与自我修复功能。

6.3. 统一日志管理

不一样微服务部署在不一样节点上, 登陆每一个节点查看日志是比较麻烦的, 同时对于须要关联多个微服务日志联合查看分析的状况将更加麻烦。 伴随节点数量的增长, 若是没有合适的管理机制与工具,定位问题、发现问题的复杂性将愈来愈大, 将成指数级增加,所以须要进行统一日志管理。

一、创建统一的日志管理规范;

二、开发并使用统一的日志组件,为全部微服务提供统一的日志服务,由 log4j 或 Blitz4j封装;

三、在每一个服务节点上部署日志采集 Agent 组件,由此 Agent 进行日志的采集与转发;

四、创建统一的日志中心,全部日志写入日志中心。

说明:上述日志的实现由公司的“日志管理平台”进行实现,采用的是 ELK集合框架。

6.4. 统一监控管理

使用 Hystrix 组件进行服务的监控,使用 Nagios 进行服务器等资源的监控。

一、 Hystrix ,监控和断路器。咱们只须要在服务接口上添加 Hystrix 标签,就能够实现对这个接口的监控和断路器功能。

二、 Hystrix Dashboard ,监控面板,他提供了一个界面,能够监控各个服务上的服务调用所消耗的时间等。

三、 Turbine,监控聚合,使用 Hystrix 监控,咱们须要打开每个服务实例的监控信息来查看。而 Turbine 能够帮助咱们把全部的服务实例的监控信息聚合到一个地方统一查看。

这样就不须要挨个打开一个个的页面一个个查看。

6.5. 统一配置管理

实现各微服务的 统一参数配置以及版本管理 ,可采用公司的配置管理平台或者 SpringCloud Config 配置中心。

pring Cloud Config 就是咱们一般意义上的配置中心。 Spring Cloud Config- 把应用本来放在本地文件的配置抽取出来放在中心服务器, 本质是配置信息从本地迁移到云端 。从而可以提供更好的管理、发布能力。

Spring Cloud Config 分服务端和客户端, 服务端负责将 git (svn )中存储的配置文件发布成 REST接口 ,客户端能够从服务端 REST接口获取配置。但 客户端并不能主动感知到配置的变化 ,从而主动去获取新的配置,这须要 每一个客户端经过 POST 方法触发各自的/refresh。为解决配置信息能及时通知到各服务, 同时减小每一个微服务处理配置信息更新的复杂度,

为此咱们经过消息总线来解决此问题,方案以下:

1. Git 仓库、 Config Server 、以及微服务“ Service A ”、 “Service B”的实例中都
引入了 Spring Cloud Bus ,因此他们都链接到了 RabbitMQ 的消息总线上。
2. 从 Git 仓库中配置的修改到发起 /bus/refresh 的 POST请求这一步能够经过 Git 仓库
3. /bus/refresh 请求再也不发送到具体服务实例上,而是发送给 Config Server ,并经过
destination 参数来指定须要更新配置的服务或实例。
4. 因为全部链接到消息总线上的应用都会接受到更新请求,因此在 WebHook 中就不须要
维护全部节点内容来进行更新,从而解决了经过 Web Hook 来逐个进行刷新的问题。

6.6. 分布式 session

采用 Redis 做为缓存组件以及 session 的共享组件。

6.7. REST 资源响应结构

制定规范和解析方法。

6.8. API 调用链追踪

Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案,而且兼容支持了 zipkin ,你只须要在 pom 文件中引入相应的依赖便可。

6.9. 单元测试

作微服务架构, 进行系统测试的复杂度较大, 为保证产品质量与开发、 测试效率, 单元测试是必不可少的。

可采用 Mock 方式进行测试模拟, 由持续集成进行自动化单元测试的执行以及结果输出。

6.10. 代码调试

对于单体架构系统, 可直接本地化调试, 但对于微服务架构, 接口间的调用需采用远程通信的方式, 也就是说被调用的服务必须启动后方可被调用, 所以当微服务增多时, 你可能须要启动大量的微服务或者 web 服务器,这给本地化调用与调试带来了困难。

解决方案待研究。

7.测试

7.1. 自动化测试

单元测试:

由开发人员实现。

采用 Mock 方式进行测试模拟, 由持续集成进行自动化单元测试的执行以及结果输出。

业务测试:

开发进行实现,测试也需考虑如何实现。将多个服务或业务单元进行串联, 测试一个完整的业务, 甚至是不一样业务之间组成的系统测试,须要采用相关的自动化测试框架执行,如 RobotFramework 自动化测试框架。

7.2. 依赖测试

也能够称为接口测试或者契约测试, 在微服务逐渐增多的状况下, 如何有效保证服务之间可以按照接口的约定正常工做, 即符合契约, 成为微服务实施过程当中, 测试面临的主要挑战。

1、 开发自动化的接口测试工具,

一、检测接口是否知足约定

二、检测接口是否发生变化

三、检测接口是否能够正常被调用。

2、测试方法:

采起基于消费者驱动的契约测试,测试架构以下:

其优点以下:

从价值实现的角度定义契约从消费者使用契约的角度出发, 首先保证消费者基于此契约是能够实现价值的, 有了这个前提,再使用契约来验证提供者, 若是提供者提供的契约同定义的契约一致,则证实提供者提供的契约是可以实现服务消费者的。 经过这种方式, 使得更聚焦于如何从价值实现出发。

隔离消费者和提供者的测试对于契约的消费者和提供者能够分开独立测试, 有效解决传统集成测试服务架构的弊端,将微服务的接口测试成本降到最低。

3、测试工具:

*Pact**Janus**Pacto*等。

7.3. 系统测试

7.4. 熔断测试

一、经过中止微服务的方式测试服务路由的正确性

二、经过压力测试,将某个微服务产生过载等异常,测试服务熔断或降级

三、经过压力测试,测试负载均衡策略的正确性

7.5. 性能测试

原有本地化的 api 调用将会变成 REST的远程调用,调用速度势必受到影响,所以须要对系统性能进行考虑以及性能测试,主要影响因素以下:

一、网络:远程调用时受到网络通信速度的影响,这涉及到网络速度、网络部署以及系统架构,有相互依赖的服务应采起 就近部署原则 。

二、服务器:受到远程服务所在服务器性能的影响。

三、数据量: 数据量这里指的是数据大小以及数据传输的次数以及频率, 此时 REST调用方式会产生瓶颈,固然, 最好的方式是避免此种状况发生 ,此种场景采起消息中间件的方式异步通信。

8. 持续集成

一、持续集成:每一个微服务独立执行持续集成。

二、版本集成:由统一的集成工具,实现自动化的版本集成,将全部微服务集成到统一

的版本发布包中。

三、持续集成可制做多种场景的版本,包括测试环境、开发环境、生产环境。

四、统计测试覆盖率等指标数据。

五、工具: Jenkins、 Sonar 等。

9.持续部署

1经过持续集成自动制做发布版本的 Docker 镜像;

2将 docker 镜像自动上传到 docker 容器中。

10.运维阶段

10.1. 远程升级

微服务不断增长后, 意味着部署容器也在同步增长, 对于后续升级维护的工做量将会逐渐增长,开发统一管理中心,支持远程维护与升级将可减小运维的复杂度。

10.2. 统一配置中心

使用 Spring Cloud Config 或者配置管理平台进行统一的配置管理。

10.3. 统一日志中心

使用日志管理平台进行统一的日志采集、日志分析。

相关文章
相关标签/搜索