Spring Cloud 微服务架构的五脏六腑!

简介: Spring Cloud 微服务架构的五脏六腑!

image.pngSpring Cloud是一个基于Spring Boot实现的微服务框架,它包含了实现微服务架构所需的各种组件。

Spring Boot简单理解就是简化Spring项目的搭建、配置、组合的框架。因为与构建微服务本身没有直接关系,所以本文不对Spring Boot进行展开。

另外本文有一些例子涉及到Spring和Spring Boot,建议先了解一下Spring和 Spring Boot再阅读本文。

本文的阅读对象主要是没有接触过服务架构,想对其有一个宏观的了解的同学。

本文将从 Spring Cloud 出发,分两小节讲述微服务框架的「五脏六腑」:

  • 第一小节「服务架构」旨在说明的包括两点,一服务架构是什么及其必要性;二是服务架构的基本组成。为什么第一节写服务架构而不是微服务架构呢?原因主要是微服务架构本身与服务架构有着千丝万缕的关系,服务架构是微服务架构的根基。
  • 第二小节「五脏六腑」则将结合Spring Cloud这个特例来介绍一个完整的微服务框架的组成。



「服务架构」


为了方便理解,我先讲一个小故事:(改编自——知乎答主)

Martin(微服务提出者也叫 Martin)刚来到公司时是一个基层员工,它上面有经理、老板,那个时候所有人都听老板的指挥。

但是过了两年,公司的人越来越多,原来的模式下整个公司的运作效率太低,管理也很混乱。

于是已经踏上中层岗位的Martin建议老板进行部门划分(服务化),专门的部门只做专门的事情(单一职责)。例如研发部门只做研发,人事部门只做招聘。

老板听取了Martin的意见,对公司的组织架构进行了调整。

有一天,Martin 发现公司的部门越来越多,各个部门并不能完全知道对方所做的事情,这对跨部门协作(服务调用)带来了困难。

行政部门会(注册中心)来记录所有的部门,每当有新的部门行政都会记录下来(服务注册),然后公布出来让所有部门知道(服务发现)。

在新的组织架构下,公司的效率逐步提高。老板也给Martin发了大量奖金作为奖励,Martin从此赢取白富美走向了人生巅峰。

这是一个公司组织架构演变的故事,主要讲的是随着公司规模的扩大,组织从集中化管理到分布化管理的过程。

映射到我们的信息系统里来也是一样的,随着我们的系统越来越复杂,变得难以管理,也有人想到去拆分然后治理。在解决复杂问题上,分治可以说是一个屡试不爽的办法。

服务化即是拆解的一种手段。而上面圆括号里面的内容其实就对应了一个服务化架构的最小组成元素,分别是服务、服务调用、注册中心、服务注册、服务发现。有了这些基本的组成要素,就可以实现一个最简单的服务架构。

面向服务的架构和微服务架构

面向服务的架构(SOA)和微服务架构是目前两种主流的服务化架构,都符合上面的例子,也有上面提到的所有组件。这两种服务架构有很多可以讲的,但是与本文的相关性不大,本文不做会过多展开,只简单介绍一下两者的区别。

准确地说微服务是去ESB(企业服务总线)的SOA。ESB借鉴了计算机组成原理中的通信模型——总线,所有需要和外部系统通信的系统,通过ESB进行标准化地转换从而消除协议、异构系统之间的差异,这样就可以利用现有的系统构建一个全新的松耦合的异构的分布式系统。微服务架构去掉ESB,本质上是一种去中心化的思想。

「五脏六腑」

顺着上一节的思路,从最简单、最核心的问题出发,假设服务 A 要调用服务 B,会有什么问题?

  • 服务在哪?(服务治理问题)
  • 怎么调用?(服务调用问题)

这两个是最核心的问题,也是任何微服务框架首要解决的两个问题。

为了解决第一个问题Spring Cloud提供了Eureka、Zookeeper、Cloud Foundry、Consul等服务治理框架的集成。它们的工作模式是将所有的微服务注册到一个Server上,然后通过心跳进行服务健康监测。这样服务A调用B时可以从注册中心拿到可用的服务B的地址、端口进行调用。

第二个服务调用有人可能认为就是一个简单的HTTP或者RPC调用,不是什么问题。但是在分布式的场景下,服务调用需要考虑的因素会更多。比如一个服务有多个实例,此时请求进来了交给谁处理,请求的负载怎么平衡到各个实例,都是比较棘手的问题。Spring Cloud提供了两种服务调用的方式:一种是Ribbon + restTemplate,另一种是Feign。

其中Ribbon是基于HTTP和TCP客户端的负载均衡器,restTemplate是Spring 提供的Restful远程调用的模板,两者结合就可以达到远程调用的负载均衡。

而Feign是一个更加声明式的HTTP客户端,开发者可以像调用本地方法一样调用它,完全感觉不到是远程调用,结合Ribbon也可以做负载均衡。

既然两个问题都得到了解决,我们就用一个例子来进一步说明一下,例子包含了微服务中最基本的三个角色(注册中心、服务提供者、服务消费者):

注册中心

注解@EnableEurekaServer表示该Spring Boot应用是一个注册中心。

@EnableEurekaServer
@SpringBootApplication
public class EurekaserverApplication {
  publicstaticvoidmain(String[] args) {
      SpringApplication.run(EurekaserverApplication.class, args);
  }
}


eureka.client.registerWithEureka: falsefetchRegistry: false来表明自己是一个eureka server。


server:
port: 8080

eureka:
instance:
  hostname: localhost
client:
  registerWithEureka: false
  fetchRegistry: false
  serviceUrl:
    defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/


service-hello服务

注解@EnableEurekaClient表示他是一个Eureka客户端,它会在注册中心注册自己。

注解@RestController表示这是一个控制器,@RequestMapping("/hello") 表示匹配到请求 '/hello' 时会调用该方法进行响应。

@SpringBootApplication
@EnableEurekaClient
@RestController
publicclass ServiceHelloApplication {

  publicstaticvoid main(String[] args) {
      SpringApplication.run(ServiceHelloApplication.class, args);
  }

  @Value("${server.port}")
  String port;
  @RequestMapping("/hello")
  publicString home(@RequestParamString name) {
      return"hello "+name+",i am from port:" +port;
  }

}


注册中心的地址为http://localhost:8080/eureka/,也就是上面我们定义的。服务名为service-hello,将会被调用者使用。


eureka:
client:
  serviceUrl:
    defaultZone: http://localhost:8080/eureka/
server:
port: 8081
spring:
application:
  name: service-hello

服务消费者 service-ribbon


假设service-ribbon端口为8082,当我们访问http://localhost:8080/hello时,HelloControler接收到请求,并调用HelloService中的helloService方法,HelloService中通过定义的restTemplate去调用 http://service-hello/hello。此处要注意的是@LoadBalanced注解,它表示启用负载均衡。

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceRibbonApplication {

  publicstaticvoidmain(String[] args) {
      SpringApplication.run(ServiceRibbonApplication.class, args);
  }
 
  @Bean
  @LoadBalanced
  RestTemplaterestTemplate() {
      returnnewRestTemplate();
  }

}
@Service
publicclassHelloService {

  @Autowired
  RestTemplate restTemplate;

  publicStringhelloService(String name) {
      returnrestTemplate.getForObject("http://service-hello/hello?name="+name,String.class);
  }

}
@RestController
publicclassHelloControler {

  @Autowired
  HelloService helloService;
 
  @RequestMapping(value = "/hello")
  public String hello(@RequestParam String name){
      returnhelloService.helloService(name);
  }

}


至此其实一个微服务应用的雏形已经搭建出来了,服务治理、服务调用可以说是「五脏六腑」中的「心脏」。


「心脏」的依托

接下来我们要进一步思考的是「五脏六腑」中其余的部分,因为少了它们人也是活不久的。下面通过一个问题或需求对应一个组件的方式进行介绍。

服务“雪崩”与断路器

由于网络等原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗殆尽,导致服务瘫痪。

由于服务与服务之间存在依赖,故障会在调用链路上传播,导致整个微服务系统崩溃,这就是服务故障的“雪崩”效应。

为了解决这个问题,Spring Cloud提供了对Hystrix断路器的集成,当服务调用失败的频次达到一定阈值,断路器将被开启,降级的策略可以开发者制定,一般是返回一个固定值。这样就能够避免连锁故障。参考:分布式服务防雪崩熔断器,Hystrix理论+实战。

此外Spring Cloud还提供Hystrix Dashboard和Hystrix Turbine,帮助我们进行监控和聚合监控。

服务暴露与路由网关

微服务中的服务很多,直接暴露给用户一是不安全,二是对用户不友好。因此在微服务和面向服务的架构中,通常会有一个路由网关的角色,来负责路由转发和过滤。对应到Spring Cloud中有Zuul和Gateway两个组件可用。

路由网关接收了所有的用户请求,有着很高的负载,因此它通常是一个集群。用户的请求会先经过一层负载均衡被发到路由网关。

服务配置与配置中心

在微服务应用中,服务数量巨多,而每个服务不同环境都有着不同的配置,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。需要注意的是此处的配置与注册中心注册的配置信息是两个概念,此处的配置是服务本身的一些配置信息,如下图:

image.png

Spring Cloud提供了Spring Cloud Config组件,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中,帮助我们管理服务的配置信息。

信息同步与消息总线

前一个问题讲到了每个服务都有一些配置信息,那么配置信息更新了我们该怎么办,手动一个个去更新?当然不是,Spring Cloud提供了Spring Cloud Bus组件,它通过轻量消息代理连接各个分布的节点。当配置信息更新的时候,我们只要更新一个节点的配置,这个更新就会被广播到这个分布式系统中。

问题定位与链路追踪

在微服务系统中,服务之间可以相互调用,因此我们一个请求可能会一条调用链,而整个系统会存在一张调用网,其中任意一个服务调用失败或网络超时都可能导致整个请求失败。因为调用关系的复杂,这给问题的定位造成了极大的困难,这也是必须提供服务链路追踪的原因。

Spring Cloud为我们提供了Spring Cloud Sleuth组件,它能够跟进一个请求到底有哪些服务参与,参与的顺序是怎样的,从而达到每个请求的步骤清晰可见。借助服务链路追踪,我们可以快速定位问题。

至此,Spring Cloud的所有基础组件都介绍完了。但是目前所有的组件介绍都是分散的,它们组合起来,完整的样子是什么样的?如下图:

image.png

偷懒偷了张图,图中漏掉了Config Server和链路追踪组件。但是结合上文的介绍,我们大致可以脑补出这两个东西在图中的位置。Config Server是一个与所有服务相连的服务集群,链路追踪组件则集成在每个服务中。

小结


服务治理为心脏,路由网关、消息中心、断路器、链路追踪、配置中心等为依托,构造了整个微服务框架的「五脏六腑」。


当然,一个微服务系统远比本文所写的复杂得多,尤其是在不同的业务场景之下,因此想要更深入地了解它就需要我们不断地去实践。而作为前端,我了解这些内容一是为了更好地了解整个请求的流程,二是为了后续在SOA中接入Node子服务积累相关知识。

最后分享一句有趣的调侃Spring的话:在Spring中没有什么是一个注解解决不了的,如果有,那么就用两个注解。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
目录
相关文章
|
6月前
|
监控 Java 数据库
从零学 Dropwizard:手把手搭轻量 Java 微服务,告别 Spring 臃肿
Dropwizard 整合 Jetty、Jersey 等成熟组件,开箱即用,无需复杂配置。轻量高效,启动快,资源占用少,内置监控、健康检查与安全防护,搭配 Docker 部署便捷,是构建生产级 Java 微服务的极简利器。
675 117
|
7月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1101 3
|
9月前
|
JavaScript 前端开发 Java
垃圾分类管理系统基于 Spring Boot Vue 3 微服务架构实操指南
本文介绍了基于Java技术的垃圾分类管理系统开发方案与实施案例。系统采用前后端分离架构,后端使用Spring Boot框架搭配MySQL数据库,前端可选择Vue.js或Java Swing实现。核心功能模块包括垃圾分类查询、科普教育、回收预约等。文中提供了两个典型应用案例:彭湖花园小区使用的Swing桌面系统和基于Spring Boot+Vue的城市管理系统,分别满足不同场景需求。最新技术方案升级为微服务架构,整合Spring Cloud、Redis、Elasticsearch等技术,并采用Docker容器
529 1
|
5月前
|
Cloud Native Serverless API
微服务架构实战指南:从单体应用到云原生的蜕变之路
🌟蒋星熠Jaxonic,代码为舟的星际旅人。深耕微服务架构,擅以DDD拆分服务、构建高可用通信与治理体系。分享从单体到云原生的实战经验,探索技术演进的无限可能。
微服务架构实战指南:从单体应用到云原生的蜕变之路
|
5月前
|
监控 Cloud Native Java
Spring Boot 3.x 微服务架构实战指南
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Spring Boot 3.x与微服务架构,探索云原生、性能优化与高可用系统设计。以代码为笔,在二进制星河中谱写极客诗篇。关注我,共赴技术星辰大海!(238字)
Spring Boot 3.x 微服务架构实战指南
|
5月前
|
负载均衡 Java API
《深入理解Spring》Spring Cloud 构建分布式系统的微服务全家桶
Spring Cloud为微服务架构提供一站式解决方案,涵盖服务注册、配置管理、负载均衡、熔断限流等核心功能,助力开发者构建高可用、易扩展的分布式系统,并持续向云原生演进。
|
6月前
|
Java 数据库 数据安全/隐私保护
Spring Boot四层架构深度解析
本文详解Spring Boot四层架构(Controller-Service-DAO-Database)的核心思想与实战应用,涵盖职责划分、代码结构、依赖注入、事务管理及常见问题解决方案,助力构建高内聚、低耦合的企业级应用。
1224 1