1. 微服务简介
如今越来越多的公司使用微服务架构来开发维护自己的业务,微服务技术早已证实它的价值。那什么是微服务?微服务最初是由 Martin Fowler 于 2014 年发表的论文《MicroServices》 中提出的名词,它一经提出就成为了技术圈的热门话题。如今我们在谈论微服务时常认为是一个庞大且复杂的概念集合,它既是一种架构模式,也是实现这种架构模式时所使用的技术方案的集合,包括服务拆分、数据管理、通讯模式、外部API、服务发现、安全、测试、可靠性、部署模式、可观测性等等。
与常见的单体架构相比,微服务架构有诸多优势,罗列了以下几方面:
不同点 |
微服务架构 |
单体架构 |
团队规模 |
微服务架构可以将传统模式下的单个应用拆分为多个独立的服务,每个微服务都可以单独开发、部署和维护。每个服务从设计、开发到维护所需的团队规模小,团队管理成本小。 |
单体架构的应用程序通常需要一个大型团队,围绕一个庞大的应用程序工作,团队管理的成本大。 |
数据存储方式 |
不同的微服务可以使用不同的数据存储方式,例如有的用 Redis,有的使用 MySQL。 |
单一架构的所有模块共享同一个公共数据库,存储方式相对单一。 |
部署方式 |
微服务架构中每个服务都可以独立部署,也可以独立于其他服务进行扩展。如果部署得当,基于微服务的架构可以帮助企业提高应用程序的部署效率。 |
采用单体架构的应用程序的每一次功能更改或 bug修复都必须对整个应用程序重新进行部署。 |
开发模式 |
在采用微服务架构的应用程序中,不同模块可以使用不同的技术或语言进行开发,开发模式更加灵活。 |
在采用单体架构的应用程序中,所有模块使用的技术和语言必须相同,开发模式受限。 |
故障隔离 |
在微服务架构中,故障被隔离在单个服务中,避免系统的整体崩溃。 |
在单体架构中,当一个组件出现故障时,故障很可能会在进程中蔓延,导致系统全局不可用。 |
项目结构 |
微服务架构将单个应用程序拆分为多个独立的小型服务,每个服务都可以独立的开发、部署和维护,每个服务都能完成一项特定的业务需求。 |
单体架构的应用程序,所有的业务逻辑都集中在同一个工程中。 |
2. Spring Cloud
实现微服务架构有许多方式,本文主要针对Spring Cloud 做了调研。Spring Cloud 中包含了 spring-cloud-config、spring-cloud-bus 等近 20 个子项目,提供了服务治理、服务网关、智能路由、负载均衡、断路器、监控跟踪、分布式消息队列、配置管理等领域的解决方案。
Spring Cloud 本身并不是一个拿来即可用的框架,它是一套微服务规范,这套规范有两代实现用的比较广泛。
第一代实现: Spring Cloud Netflix,
第二代实现: Spring Cloud Alibaba。
下面来介绍以下Spring Cloud一些常用的组件。
3. Eureka: Spring Cloud服务注册与发现组件
Eureka 采用 CS(Client/Server,客户端/服务器) 架构,它包括以下两大组件:
Eureka Server:Eureka服务注册中心,主要用于提供服务注册功能。当微服务启动时,会将自己的服务注册到 Eureka Server。Eureka Server 维护了一个可用服务列表,存储了所有注册到 Eureka Server 的可用服务的信息,这些可用服务可以在 Eureka Server 的管理界面中直观看到。
Eureka Client:Eureka 客户端,通常指的是微服务系统中各个微服务,主要用于和 Eureka Server 进行交互。在微服务应用启动后,Eureka Client 会向 Eureka Server 发送心跳(默认周期为 30 秒)。若 Eureka Server 在多个心跳周期内没有接收到某个 Eureka Client 的心跳,Eureka Server 将它从可用服务列表中移除(默认 90 秒)。
Eureka 实现服务注册与发现的流程如下:
搭建一个 Eureka Server 作为服务注册中心;
服务提供者 Eureka Client 启动时,会把当前服务器的信息以服务名(spring.application.name)的方式注册到服务注册中心;
服务消费者 Eureka Client 启动时,也会向服务注册中心注册;
服务消费者还会获取一份可用服务列表,该列表中包含了所有注册到服务注册中心的服务信息(包括服务提供者和自身的信息);
在获得了可用服务列表后,服务消费者通过 HTTP 或消息中间件远程调用服务提供者提供的服务。
实现一个Eureka Server配置如下:
# 服务注册中心 (单节点)
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com
client:
fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为false
register-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.
service-url:
# 设置与Eureka Server的地址,查询服务和注册服务都需要依赖这个地址.默认是http://localhost:8761/eureka/;多个地址可使用','风格.
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #集群版 将当前的 Eureka Server 注册到 7001 和 7003 上,形成一组互相注册的 Eureka Server 集群
同时在Spring Boot 启动类上添加注解@EnableEurekaServer,就可以成为一个单节点Eureka Server,如果要成为一个集群,只需要将自身注册到其他Eureka Server中即可。
实现一个服务提供者配置如下:
server:
port: 8002
spring:
application:
name: eureka-producer
eureka:
client:
service-url:
#defaultZone: http://localhost:7001/eureka # 指定服务注册中心
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #将服务注册到 Eureka Server 集群
实现一个服务消费者配置如下:
server:
port: 9001
spring:
application:
name: eureka-consumer
eureka:
client:
service-url:
register-with-eureka: false #本微服务为服务消费者,不需要将自己注册到服务注册中心
fetch-registry: true #本微服务为服务消费者,需要到服务注册中心搜索服务
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #将服务注册到 Eureka Server 集群
同时在Spring Boot 启动类上添加注解@EnableDiscoveryClient,就可以成为一个服务提供者或提供消费者。
下图是启动了3台Eureka Server,1个服务提供者,一个服务消费者的视图,DS REplicas表示Eureka Server集群中另外两台机器,而Application是注册在这个集群上的具体应用。
4. Ribbon: Spring Cloud负载均衡与服务调用组件
Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡器,当我们将 Ribbon 和 Eureka 一起使用时,Ribbon 会从 Eureka Server(服务注册中心)中获取服务端列表,然后通过负载均衡策略将请求分摊给多个服务提供者,从而达到负载均衡的目的。
5. OpenFeign: Spring Cloud声明式服务调用组件
Feign 对 Ribbon 进行了集成,利用 Ribbon 维护了一份可用服务清单,并通过 Ribbon 实现了客户端的负载均衡。Feign 是一种声明式服务调用组件,它在 RestTemplate 的基础上做了进一步的封装。通过 Feign,我们可以像调用本地方法一样来调用远程服务,而完全感觉不到这是在进行远程调用。而OpenFeign 是 Spring Cloud 对 Feign 的二次封装,它具有 Feign 的所有功能,并在 Feign 的基础上增加了对 Spring MVC 注解的支持,例如 @RequestMapping、@GetMapping 和 @PostMapping 等。
利用OpenFeign 实现远程服务调用只需要申明@FeignClient,代码如下:
//添加为容器内的一个组件
@Component
// 服务提供者提供的服务名称,即 eureka-producer
//@FeignClient(value = "EUREKA-PRODUCER")
@FeignClient(value = "EUREKA-PRODUCER")
public interface FeignService {
@RequestMapping(value = "/sayHello", method = RequestMethod.GET)
String sayHello(@RequestParam String param);
}
在调用的时候注入FeignService bean即可:
@RestController
public class TestController {
@Resource
private FeignService feignService;
@RequestMapping("sayHello")
public String sayHello(@RequestParam String name) {
return feignService.sayHello(name);
}
}
6. Hystrix: Spring Cloud服务熔断与降级组件
Hystrix 是一款优秀的服务容错与保护组件,在微服务系统中,Hystrix 能够帮助我们实现以下目标:
保护线程资源:防止单个服务的故障耗尽系统中的所有线程资源。
快速失败机制:当某个服务发生了故障,不让服务调用方一直等待,而是直接返回请求失败。
提供降级(FallBack)方案:在请求失败后,提供一个设计好的降级方案,通常是一个兜底方法,当请求失败后即调用该方法。
防止故障扩散:使用熔断机制,防止故障扩散到其他服务。
监控功能:提供熔断器故障监控组件 Hystrix Dashboard,随时监控熔断器的状态。
概括的讲,Hystrix主要提供两种功能,一个服务降级,一个服务熔断。
6.1 服务降级
当程序运行异常、服务超时、线程池资源耗尽时,Hystrix可以提供一种能力,让服务快速返回一个降级逻辑结果,使这个服务不堵塞其他正常服务,保障主题业务不受影响,从而减少影响面。
可以配置Hystrix超时时间:
feign:
# client:
# config:
# default:
# # 指的是建立连接所用的时间,适用于网络状态正常的情况下,两端连接所用的时间,默认10s
# ConnectTimeOut: 5000
# # 指的是建立连接后从服务器读取可用资源所用的时间,默认60s
# ReadTimeOut: 5000
hystrix:
enabled: true
######################配置请求超时时间##########################
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
通过@HystrixCommand添加方法专属的回退方法:
@RequestMapping("hystrixClientTimeout")
@HystrixCommand(fallbackMethod = "timeoutHandler") //为该请求指定专属的回退方法
public String hystrixClientTimeout(Integer second) {
return feignService.hystrixClientTimeout(second);
}
// hystrixClientTimeout方法的 专用 fallback 方法
public String timeoutHandler(Integer second) {
return "服务端系统繁忙,请稍后再试!(客户端 timeout 专属的回退方法触发)";
}
也可以通过@DefaultProperties添加全局回退方法:
@RestController
@DefaultProperties(defaultFallback = "globalTimeoutHandler")
public class TestController {
/**
* 全局的 fallback 方法,
* 回退方法必须和 hystrix 的执行方法在相同类中
*/
public String globalTimeoutHandler() {
return "服务端系统繁忙,请稍后再试!(客户端 timeout 全局回退方法触发)";
}
}
6.2 服务熔断
熔断机制是为了应对雪崩效应而出现的一种微服务链路保护机制。当微服务系统中的某个微服务不可用或响应时间太长时,为了保护系统的整体可用性,熔断器会暂时切断请求对该服务的调用,并快速返回一个友好的错误响应。这种熔断状态不是永久的,在经历了一定的时间后,熔断器会再次检测该微服务是否恢复正常,若服务恢复正常则恢复其调用链路。
在熔断机制中涉及了三种熔断状态:
熔断关闭状态(Closed):当务访问正常时,熔断器处于关闭状态,服务调用方可以正常地对服务进行调用。
熔断开启状态(Open):默认情况下,在固定时间内接口调用出错比率达到一个阈值(例如 50%),熔断器会进入熔断开启状态。进入熔断状态后,后续对该服务的调用都会被切断,熔断器会执行本地的降级(FallBack)方法。
半熔断状态(Half-Open): 在熔断开启一段时间之后,熔断器会进入半熔断状态。在半熔断状态下,熔断器会尝试恢复服务调用方对服务的调用,允许部分请求调用该服务,并监控其调用成功率。如果成功率达到预期,则说明服务已恢复正常,熔断器进入关闭状态;如果成功率仍旧很低,则重新进入熔断开启状态。
通过@HystrixCommand设置是否开启熔断器、统计时间窗、统计时间窗内请求次数、休眠时间窗口期、请求失败率阈值,同时可以指定熔断后执行方法。
//Hystrix 熔断案例
@Override
@HystrixCommand(fallbackMethod = "deptCircuitBreaker_fallback", commandProperties = {
//以下参数在 HystrixCommandProperties 类中有默认配置
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启熔断器
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "1000"), //统计时间窗
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //统计时间窗内请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //休眠时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), //在统计时间窗口期以内,请求失败率达到 60% 时进入熔断状态
})
public String circuitBreaker(int id) {
if (id < 0) {
//当传入的 id 为负数时,抛出异常,调用降级方法
throw new RuntimeException("id 不能是负数!");
}
return Thread.currentThread().getName() + "\t" + "调用成功,流水号为:" + id;
}
//deptCircuitBreaker 的降级方法
public String deptCircuitBreaker_fallback(int id) {
return "id 不能是负数,请稍后重试!\t id:" + id;
}
7. Gateway: Spring Cloud API网关组件
API 网关是一个搭建在客户端和微服务之间的服务,我们可以在 API 网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等。API 网关就像整个微服务系统的门面一样,是系统对外的唯一入口。有了它,客户端会先将请求发送到 API 网关,然后由 API 网关根据请求的标识信息将请求转发到微服务实例。
Spring Cloud GateWay 最主要的功能就是路由转发,而在定义转发规则时主要涉及了以下三个核心概念,如下表。
核心概念 |
描述 |
Route(路由) |
网关最基本的模块。它由一个 ID、一个目标 URI、一组断言(Predicate)和一组过滤器(Filter)组成。 |
Predicate(断言) |
路由转发的判断条件,我们可以通过 Predicate 对 HTTP 请求进行匹配,例如请求方式、请求路径、请求头、参数等,如果请求与断言匹配成功,则将请求转发到相应的服务。 |
Filter(过滤器) |
过滤器,我们可以使用它对请求进行拦截和修改,还可以使用它对上文的响应进行再处理。 |
成为一个网关配置如下:
spring:
application:
name: cloud-gateway
cloud:
gateway: #网关路由配置
discovery:
locator:
enabled: true #默认值为 true,即默认开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
#将 micro-service-cloud-provider-dept-8001 提供的服务隐藏起来,不暴露给客户端,只给客户端暴露 API 网关的地址 9527
- id: provider_hystrix_route #路由 id,没有固定规则,但唯一,建议与服务名对应
#uri: http://localhost:8004 #匹配后提供服务的路由地址
uri: lb://EUREKA-PRODUCER #匹配后提供服务的路由地址
predicates:
#以下是断言条件,必选全部符合条件
- Path=/gateway/** #断言,路径匹配 注意:Path 中 P 为大写
- Method=GET #只能时 GET 请求时,才能访问
filters:
- AddResponseHeader=X-Request-Id,hello #过滤器工厂会在匹配的请求头加上一对请求头,名称为 X-Request-Id 值为 hello
其中Predicate表示一组断言,常见的配置如下:
断言 |
示例 |
说明 |
Path |
- Path=/dept/list/** |
当请求路径与 /dept/list/** 匹配时,该请求才能被转发 |
Before |
- Before=2021-10-20T11:47:34.255+08:00[Asia/Shanghai] |
在 2021 年 10 月 20 日 11 时 47 分 34.255 秒之前的请求,才会被转发 |
After |
- After=2021-10-20T11:47:34.255+08:00[Asia/Shanghai] |
在 2021 年 10 月 20 日 11 时 47 分 34.255 秒之后的请求,才会被转发 |
Between |
- Between=2021-10-20T15:18:33.226+08:00[Asia/Shanghai],2021-10-20T15:23:33.226+08:00[Asia/Shanghai] |
在 2021 年 10 月 20 日 15 时 18 分 33.226 秒 到 2021 年 10 月 20 日 15 时 23 分 33.226 秒之间的请求,才会被转发 |
Cookie |
- Cookie=name,c.biancheng.net |
携带 Cookie 且 Cookie 的内容为 name=c.biancheng.net 的请求,才会被转发 |
Header |
- Header=X-Request-Id,\d+ |
请求头上携带属性 X-Request-Id 且属性值为整数的请求,才会被转发到 h |
Method |
- Method=GET |
只有 GET 请求才会被转发 |
filters是过滤器,Spring Cloud Gateway 内置了多达 31 种 GatewayFilter,下表中列举了几种常用的网关过滤器及其使用示例。
路由过滤器 |
描述 |
参数 |
使用示例 |
AddRequestHeader |
拦截传入的请求,并在请求上添加一个指定的请求头参数。 |
name:需要添加的请求头参数的 key; value:需要添加的请求头参数的 value。 |
- AddRequestHeader=my-request-header,1024 |
AddRequestParameter |
拦截传入的请求,并在请求上添加一个指定的请求参数。 |
name:需要添加的请求参数的 key; value:需要添加的请求参数的 value。 |
- AddRequestParameter=my-request-param,c.biancheng.net |
AddResponseHeader |
拦截响应,并在响应上添加一个指定的响应头参数。 |
name:需要添加的响应头的 key; value:需要添加的响应头的 value。 |
- AddResponseHeader=my-response-header,c.biancheng.net |
PrefixPath |
拦截传入的请求,并在请求路径增加一个指定的前缀。 |
prefix:需要增加的路径前缀。 |
- PrefixPath=/consumer |
PreserveHostHeader |
转发请求时,保持客户端的 Host 信息不变,然后将它传递到提供具体服务的微服务中。 |
无 |
- PreserveHostHeader |
RemoveRequestHeader |
移除请求头中指定的参数。 |
name:需要移除的请求头的 key。 |
- RemoveRequestHeader=my-request-header |
RemoveResponseHeader |
移除响应头中指定的参数。 |
name:需要移除的响应头。 |
- RemoveResponseHeader=my-response-header |
RemoveRequestParameter |
移除指定的请求参数。 |
name:需要移除的请求参数。 |
- RemoveRequestParameter=my-request-param |
RequestSize |
配置请求体的大小,当请求体过大时,将会返回 413 Payload Too Large。 |
maxSize:请求体的大小。 |
- name: RequestSize args: maxSize: 5000000 |
当然也可以自定义全局过滤器GlobalFilter:
@Component
@Slf4j
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("进入自定义的全局过滤器 MyGlobalFilter" + new Date());
String path = exchange.getRequest().getPath().toString();
if (path.startsWith("/gateway/timeout")) {
log.info("path 不能以 /gateway/timeout 开头!");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
//过滤器的顺序,0 表示第一个
return 0;
}
}
8. Spring Cloud Alibaba
Spring Cloud Alibaba是对Spring Cloud的标准实现,Spring Cloud Alibaba 从19 年初开始提交代码就获得了业界的广泛关注,如今已经成为流行的微服务框架。
Spring Cloud Alibaba主要包含以下几个模块:
Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
Dubbo:Apache Dubbo 是一款高性能Java RPC 框架。
Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于Cron 表达式)任务调度服务。
Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
9. Nacos: Spring Cloud Alibaba服务注册与配置中心
Nacos 提供了一系列简单易用的特性,能够帮助我们快速地实现动态服务发现、服务配置等功能。
与 Eureka 类似,Nacos 也采用 CS(Client/Server,客户端/服务器)架构。Nacos Server由阿里巴巴团队使用 Java 语言编写并将 下载地址给用户,用户只需要直接下载并运行即可。Nacos Server可作为服务注册中心或配置中心。Nacos 客户端需要用户自己搭建。
9.1 注册中心
Nacos服务端配置如下:
# 应用名称
spring.application.name=nacos-discoveryprovider-sample
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# 注册到 nacos 的指定 namespace,默认为 public
spring.cloud.nacos.discovery.namespace=public
# 应用服务 WEB 访问端口
server.port=8089
# Actuator Web 访问端口
management.server.port=8081
management.endpoints.jmx.exposure.include=*
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
Nacos消费端配置和服务端一致,区分应用名称、端口号即可。启动成功后,可以在Nacos Server中查看管理服务列表:
9.2 配置中心
使用Nacos配置中心配置如下:
# Nacos帮助文档: https://nacos.io/zh-cn/docs/concepts.html
# Nacos认证信息
spring.cloud.nacos.config.username=nacos
spring.cloud.nacos.config.password=nacos
spring.cloud.nacos.config.contextPath=/nacos
# 设置配置中心服务端地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
# Nacos 配置中心的namespace。需要注意,如果使用 public 的 namcespace ,请不要填写这个值,直接留空即可
# spring.cloud.nacos.config.namespace=
启动成功后,可以在Nacos Server中查看管理配置列表:
10. Sentinel: Spring Cloud Alibaba高可用流量控制组件
Sentinel 是阿里巴巴开源的,面向分布式服务架构的高可用防护组件,主要以流量为切入点,从流量控制、流量整形、熔断降级、系统自适应保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。从功能上来说,Sentinel 与 Spring Cloud Netfilx Hystrix 类似,但 Sentinel 要比 Hystrix 更加强大,例如Sentinel 提供了流量控制功能、比 Hystrix 更加完善的实时监控功能等等。
同Nacos一样,Sentinel也有自己的控制台,可以在控制台操作流控规则、熔断规则等等。
Sentinel可实现流量控制和熔断降级,主要通过注解@SentinelResource实现,blockHandler实现流量控制方法,表示限流后执行的逻辑,fallback实现熔断降级方法,表示熔断后执行的方法。Sentinel熔断状态与Hystrix一致,也是熔断关闭状态、熔断开启状态、半熔断状态。另外Sentinel 提供了 3 种熔断策略:慢调用比例、异常比例、异常数,强于Hystrix。
@SentinelResource(value = "/sentinel/timeout", fallback = "fallBackTime", blockHandler = "blockHandlerTestTime")
@RequestMapping("/timeout")
public String timeout(@RequestParam int second) {
return feignService.timeout(second);
}
public String fallBackTime(int second) {
return "熔断降级了:" + second;
}
public String blockHandlerTestTime(@RequestParam int second, BlockException exception) {
return "您已被限流,请稍后重试! second:" + second;
}
11. 写在最后
Spring Cloud 版本众多,组件也在不断扩充中,是一个非常强大的微服务框架,不过也不是万能的,首先带来的是微服务化后服务过多,治理成本变高的问题,同时对整个团队分布式系统开发的能力要求也会变高,再者Java语言的限制也是Spring Cloud的一大掣肘,任何框架都不是完美的,需要适当的评估是否适合自己。