基于Spring Cloud的微服务落地(下)

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 基于Spring Cloud的微服务落地(下)

服务容错保护


在微服务架构中,微服务之间可能存在依赖关系,例如Notification Service会调用Account Service,Account Service调用Statistics Service。真实产品中,微服务之间的调用会更加寻常。倘若上游服务出现了故障,就可能会因为依赖关系而导致故障的蔓延,最终导致整个系统的瘫痪。

Spring Cloud Hystrix通过实现断路器(Circuit Breaker)模式以及线程隔离等功能,实现服务的容错保护。

仍然参考前面的例子。现在系统的微服务包括:

  • 上游服务:demo-service
  • 下游服务:demo-consumer
  • Eureka服务器:eureka-server

假设上游服务可能会出现故障,为保证系统的健壮性,需要在下游服务中加入容错包含功能。首先需要在demo-consumer服务中添加对hystrix的依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

然后在demo-consumer的应用程序类中加入@EnableCircuitBreaker开启断路器功能:

@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args)
    }
}

注意:Spring Cloud提供了@SpringCloudApplication注解简化如上代码。该注解事实上已经包含了前面所述的三个注解。@SpringCloudApplication注解的定义如下所示:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {}

接下来,需要引入一个新的服务类来封装hystrix提供的断路器保护功能,主要是定义当故障发生时需要执行的回调逻辑,即代码中指定的fallbackMethod:

@Service
public class ConsumerService {
    @Autowired
    RestTemplate restTemplate;
    @HystrixCommand(fallbackMethod = "consumerFallback")
    public String consume() {
        return restTemplate.getForEntity("http://demo-service/demo", String.class).getBody(); 
    }
    public String consumerFallback() {
        return "error";
    }
}
@RestController
public class ConsumerController {
    @Autowired
    ConsumerService consumerService;
    @RequestMapping(value = "/demo-consumer", method = RequestMethod.Get)
    public String helloConsumer() {
        return consumerService.consume(); 
    }
}


服务监控


微服务架构将服务的粒度分解的足够细,这使得它在保证服务足够灵活、足够独立的优势下,也带来了管理和监控上的挑战,服务与服务之间的依赖也变得越来越复杂。因此,对服务健康度和运行指标的监控就变得非常重要。

Hystrix提供了Dashboard用以监控Hystrix的各项指标信息。为了监控整个系统的微服务,我们需要为Hystrix Dashboard建立一个Spring Boot微服务。在该服务项目的pom文件中,添加如下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-actuator</artifactId>
</dependency>

服务的Application类需要添加@EnableHystrixDashboard,以启用Hystrix Dashboard功能。同时,可能需要根据实际情况修改application.properties配置文件,例如选择可用的端口号等。

如果要实现对集群的监控,则需要加入Turbine。


API网关


理论上,客户端可以直接向每个微服务直接发送请求。但是这种方式是存在挑战和限制的,调用者需要知道所有端点的地址,分别对每一段信息执行http请求,然后将结果合并到客户端。

一般而言,针对微服务架构模式的系统,采用的都是前后端分离的架构。为了明显地隔离开前端与后端的边界,我们通常可以专门为前端的消费者定义更加粗粒度的Open Service。这些Open Service是对外的RESTful API服务,可以通过F5、Nginx等网络设备或工具软件实现对各个微服务的路由与负载均衡,并公开给外部的客户端调用(注意,内部微服务之间的调用并不需要通过Open Service)。这种对外公开的Open Service通常又被称为边缘服务(edge service)。

如果这些Open Service需要我们自己去开发实现并进行服务的运维,在系统规模不断增大的情况下,会变得越来越困难。例如,当增加了新的微服务又或者IP地址发生变动时,都需要运维人员手工维护这些路由规则与服务实例列表。又例如针对所有垂直分隔的微服务,不可避免存在重用的横切关注点,例如用户身份认证、授权或签名校验等机制。我们不能在所有微服务中都去添加这些相同的功能,因为这会造成横切关注点的冗余。

解决的办法是引入API网关(API Gateway)。它是系统的单个入口点,用于通过将请求路由到适当的后端服务或者通过调用多个后端服务并聚合结果来处理请求。此外,它还可以用于认证、insights、压力测试、金丝雀测试(canary testing)、服务迁移、静态响应处理和主动变换管理。Spring Cloud为API网关提供的解决方案就是Spring Cloud Zuul,它是对Netflix Zuul的包装。


路由规则与服务实例维护


Zuul解决路由规则与服务实例维护的方法是通过Spring Cloud Eureka。API Gateway自身就是一个Spring Boot服务,该服务自身被注册为Eureka服务治理下的应用,同时它会从Eureka中获得所有其他微服务的实例信息。这样的设计符合DRY原则,因为Eureka已经维护了一套服务实例信息,Zuul直接重用了这些信息,无需人工介入。

对于路由规则,Zuul默认会将服务名作为ContextPath创建路由映射,基本上这种路由映射机制就可以满足微服务架构的路由需求。倘若需要一些特殊的配置,Zuul也允许我们自定义路由规则,可以通过在API网关的Application类中创建PatternServiceRouteMapper来定义自己的规则。


横切关注点


诸如授权认证、签名校验等业务逻辑本身与微服务应用所要处理的业务逻辑没有直接关系,我们将这些可能横跨多个微服务的功能称为“横切关注点”。这些横切关注点往往会作为“装饰”功能在服务方法的前后被调用。Spring Cloud Zuul提供了一套过滤器机制,允许开发者创建各种过滤器,并指定哪些规则的请求需要执行哪个过滤器。

自定义的过滤器继承自ZuulFilter类。例如我们要求客户端发过来的请求在路由之前需要先验证请求中是否包含accessToken参数,如果有就进行路由,否则就拒绝,并返回401 Unauthorized错误,则可以定义AccessFilter类:

public class AccessFilter extends ZuulFilter {
    private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
    @Override
    public String filterType() {
        return "pre"
    }
    @Override
    public int filterOrder() {
        return 0;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());
        Object accessToken = request.getParameter("accessToken");
        if (accessToken == null) {
            log.warn("access token is empty");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            return null;
        }
        log.info("access token ok");
        return null;
    }
}

要让该自定义过滤器生效,还需要在Zuul服务的Application中创建具体的Bean:

@EnableZuulProxy
@SpringCloudApplication
public class ZuulApplication {
    public static void main(String[] args) {
        new SpringApplicatonBuilder(ZuulApplication.class).web(true).run(args);
    }
    @Bean
    public AccessFilter accessFilter() {
        return new AccessFilter();
    }
}

Zuul一共提供了四种过滤器:

  • pre filter
  • routing filter
  • post filter
  • error filter

下图来自官网,它展现了客户端请求到达Zuul API网关的生命周期与过滤过程:

image.png

通过starter添加Zuul的依赖时,自身包含了spring-cloud-starter-hystrix与spring-cloud-starter-ribbon模块的依赖,因此Zuul自身就拥有线程隔离与断路器的服务容错功能,以及客户端负载均衡。但是,倘若我们使用path与url的映射关系来配置路由规则,则路由转发的请求并不会采用HystrixCommand来包装,因而这类路由是没有服务容错与客户端负载均衡作用的。所以在使用Zuul时,应尽量使用path和serviceId的组合对路由进行配置。


分布式配置中心


为什么要引入一个分布式配置中心?一个微服务就需要至少一个配置文件,怎么管理分散在各个微服务中的配置文件呢?如果微服务采用的是不同的技术栈,如何来统一微服务的配置呢?微服务是部署在不同的节点中,显然我们无法在单机中实现对分布式节点的配置管理。这就是引入Spring Cloud Config的目的。

Spring Cloud Config提供了服务端和客户端支持。服务端是一个独立的微服务,同样可以注册到Eureka服务器中。每个需要使用分布式配置中心的微服务都是Spring Cloud Config的客户端。Spring Cloud Config默认实现基于Git仓库,既可以进行版本管理,还可以通过本地Git库起到缓存作用。Spring Cloud Config不限于基于Spring Cloud开发的系统,而是可以用于任何语言开发的程序,并支持自定义实现。


配置中心服务端


Spring Cloud Config Server作为配置中心服务端,提供如下功能:

  • 拉取配置时更新git仓库副本,保证是最新结果
  • 支持数据结构丰富,yml, json, properties等
  • 配合Eureke可实现服务发现,配合cloud bus可实现配置推送更新
  • 配置存储基于git仓库,可进行版本管理
  • 简单可靠,有丰富的配套方案

建立一个Config服务,需要添加如下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

服务的Application类需要添加@EnableConfigServer注解:

@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class, args);
    }
}

配置服务的基本信息和Git仓库的信息放在application.yml文件中:

spring:
  cloud:
    config:
      server:
        git:
            uri: http://localhost/workspace/springcloud-demo
            username: user
            password: password
server:
  port: 8888
security:
  user:
    password: ${CONFIG_SERVICE_PASSWORD}


Git库与配置服务


在Config服务中配置了Git服务器以及Git库的信息后,我们就可以在git库中提交配置文件。存储在git库中配置文件的名字以及分支名(默认为master分支)会组成访问Config服务的URI。假设有一个服务为Notification服务,则它在配置中心服务端的配置文件为notification-dev.yml,内容如下:

devMode:  true
spring:
    application:
        name: notification
    jdbc:
        host: localhost
        port: 3306
        user: root
        password: 123456
logging:
    file: demo


配置中心客户端


需要读取配置中心服务端信息的微服务都是配置中心的客户端,为了能够读取配置服务端的信息,这些微服务需要:

  • 在pom中添加对spring-cloud-starter-config的依赖
  • 在bootstrap.properties或者bootstrap.yml中配置获取配置的config-server位置

例如,Account服务的配置是由Spring Cloud Config进行管理的。在它的资源目录下,提供了bootstrap.yml配置文件,内容如下所示:

spring:
  application:
    name: account-service
  cloud:
    config:
      uri: http://config:8888
      fail-fast: true
      password: ${CONFIG_SERVICE_PASSWORD}
      username: user

注意,该配置文件除了配置了该Account服务应用的name之外,主要是支持该应用获得配置服务端的信息。微服务自身的配置信息则统一放到配置中心服务端的文件中,并由Git库进行管理。例如,Account服务的详细配置在配置中心服务端的account-dev.yml文件中:

security:
  oauth2:
    client:
      clientId: account-service
      clientSecret: ${ACCOUNT_SERVICE_PASSWORD}
      accessTokenUri: http://auth-service:5000/uaa/oauth/token
      grant-type: client_credentials
      scope: server
spring:
  data:
    mongodb:
      host: account-mongodb
      username: user
      password: ${MONGODB_PASSWORD}
      database: piggymetrics
      port: 27017
server:
  context-path: /accounts
  port: 6000

Spring Cloud Config通过Git实现分布式的配置管理。当配置中心服务端的配置信息发生变更时,各个作为配置客户端的微服务会向Git库提交pull更新,获得最新的配置信息。

当然,Spring Cloud Config还可以使用SVN库进行配置管理,也支持简单的本地文件系统的存储方式。此时需要将spring.profiles.active设置为native,并设置搜索配置文件的路径。如果不配置路径,默认在src/main/resources目录下搜索。如下配置文件:

spring:
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/shared
  profiles:
    active: native

搜索路径放在classpath下的shared目录下,那么在代码中,目录就是resources/shared。如果使用本地文件系统管理配置文件,则无法支持分布式配置管理以及版本管理,因此在生产系统下,还是推荐使用Git库的方式。


总结


在实施微服务时,我们可以将微服务视为两个不同的边界。一个是与前端UI的通信,称为Open Service(Edge Service),通过引入API Gateway来实现与前端UI的通信。另一个是在边界内业务微服务之间的通信,通过Feign实现微服务之间的协作。所有的微服务都会通过Eureka来完成微服务的注册与发现。一个典型的基于Spring Cloud的微服务架构如下所示:

image.png

微服务的集成可以通过Feign+Ribbon以RESTful方式实现通信,也可以基于RPC方式(可以结合Protocol Buffer)完成服务之间的通信,甚至可以通过发布事件与订阅事件的机制。事件机制可以使微服务之间更加松散耦合。这时,我们可以引入RabbitMQ或Kafka来做到服务与服务之间的解耦。事件机制是异步和非阻塞的,在某些业务场景下,它的性能会更加的好。Spring Cloud也提供了相关的组件Spring Cloud Stream来支持这种事件机制。

对于微服务之间的协作,到底选择Feign这种REST方式、事件机制或者RPC方式,取决于业务场景是否需要同步方式,还是异步方式;是高性能高并发,还是普通方式;是要求彻底解耦,还是做到一般的松散耦合。我们需要针对实际情况作出实际的判断,作出正确的选择。没有谁坏谁好之分,而是看谁更加的适合

本文链接: http://zhangyi.xyz/micro-service-based-on-spring-cloud/

相关文章
|
1月前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
58 2
|
2月前
|
Java 对象存储 开发者
解析Spring Cloud与Netflix OSS:微服务架构中的左右手如何协同作战
Spring Cloud与Netflix OSS不仅是现代微服务架构中不可或缺的一部分,它们还通过不断的技术创新和社区贡献推动了整个行业的发展。无论是对于初创企业还是大型组织来说,掌握并合理运用这两套工具,都能极大地提升软件系统的灵活性、可扩展性以及整体性能。随着云计算和容器化技术的进一步普及,Spring Cloud与Netflix OSS将继续引领微服务技术的发展潮流。
61 0
|
1月前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
1月前
|
JSON Java 数据格式
【微服务】SpringCloud之Feign远程调用
本文介绍了使用Feign作为HTTP客户端替代RestTemplate进行远程调用的优势及具体使用方法。Feign通过声明式接口简化了HTTP请求的发送,提高了代码的可读性和维护性。文章详细描述了Feign的搭建步骤,包括引入依赖、添加注解、编写FeignClient接口和调用代码,并提供了自定义配置的示例,如修改日志级别等。
89 1
|
1月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
1月前
|
Java 数据库 数据安全/隐私保护
Spring 微服务提示:使用环境变量抽象数据库主机名
Spring 微服务提示:使用环境变量抽象数据库主机名
45 1
|
1月前
|
监控 Java 对象存储
监控与追踪:如何利用Spring Cloud Sleuth和Netflix OSS工具进行微服务调试
监控与追踪:如何利用Spring Cloud Sleuth和Netflix OSS工具进行微服务调试
44 1
|
1月前
|
安全 Java 对象存储
安全性考量:Spring Security与Netflix OSS在微服务安全中的作用
安全性考量:Spring Security与Netflix OSS在微服务安全中的作用
43 1
|
2月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
113 5
|
2月前
|
前端开发 API 微服务
SpringCloud微服务之间使用Feign调用不通情况举例
SpringCloud微服务之间使用Feign调用不通情况举例
576 2
下一篇
无影云桌面