Spring Cloud 是一个基于 Spring Boot 实现的微服务架构开发工具集。主要的组件有:
一、服务治理
Eureka:
在 Eureka 中,节点健康检查机制主要是通过服务实例定期向 Eureka Server 发送心跳(heartbeat)来实现的。
心跳机制
服务实例启动时,会向 Eureka Server 注册自己的信息,包括服务名称、IP 地址、端口号等。同时,服务实例会启动一个定时任务,每隔一段时间(默认 30 秒)向 Eureka Server 发送一次心跳,以表明自己仍然处于活跃状态。
Eureka Server 在接收到服务实例的心跳后,会更新该服务实例在注册表中的状态信息,将其标记为 “UP”(可用状态)。如果 Eureka Server 在一段时间内(默认 90 秒)没有收到某个服务实例的心跳,就会将该服务实例从注册表中剔除,并将其状态标记为 “DOWN”(不可用状态)。
自我保护机制
Eureka Server 还具有自我保护机制,以防止在网络分区等情况下错误地剔除服务实例。当 Eureka Server 检测到在一定时间内(15 分钟内)收到的心跳次数低于一个阈值(85%)时,就会进入自我保护模式。在自我保护模式下,Eureka Server 不会剔除任何服务实例,即使这些服务实例没有按时发送心跳。自我保护机制的目的是为了避免在网络不稳定等情况下,由于误判而导致大量服务实例被剔除,从而影响整个系统的可用性。
客户端的健康检查
除了服务实例向 Eureka Server 发送心跳外,Eureka 客户端也会对注册到它的服务实例进行健康检查。客户端可以通过调用服务实例的某个端点(通常是 /health
端点)来检查服务实例的健康状态。如果服务实例的健康状态为 “DOWN”,客户端会将该服务实例从本地缓存中剔除,不再向其发送请求。
总的来说,Eureka 的节点健康检查机制通过心跳机制和自我保护机制来确保服务注册表中的服务实例信息的准确性和可用性,同时客户端也会对服务实例进行健康检查,以提高整个系统的可靠性和稳定性。
在 Spring Cloud 中,可以通过以下方式配置 Eureka 客户端的健康检查:
添加依赖
确保你的项目中已经引入了相关的依赖,通常情况下,如果使用了 Spring Boot 和 Spring Cloud 的依赖管理,以下依赖会自动包含:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
这个依赖提供了 /actuator/health
端点用于健康检查。
配置文件设置
在 application.properties
或 application.yml
配置文件中进行以下配置:
对于 application.properties
:
eureka.client.healthcheck.enabled=true
application.yml
:eureka:
client:
healthcheck:
enabled: true
开启这个配置后,Eureka 客户端会定期调用 /actuator/health
端点来检查自身的健康状态,并将结果上报给 Eureka Server。
自定义健康检查逻辑
如果默认的 /actuator/health
端点不能满足你的需求,你可以自定义健康检查逻辑。可以通过实现 HealthIndicator
接口来创建自己的健康检查器:
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// 进行自定义的健康检查逻辑
boolean isHealthy = // 检查条件判断
if (isHealthy) {
return Health.up().build();
} else {
return Health.down().build();
}
}
}
这样,Eureka 客户端在进行健康检查时,会调用你自定义的健康检查器来确定自身的健康状态
二、客户端负载均衡
Ribbon:
三、服务调用
Feign:
四、断路器
Hystrix:
五、网关
Zuul:
六、配置中心
Spring Cloud Config:
七、服务总线
Spring Cloud Bus:
以下是 Spring Cloud 中各个主要组件的示例代码:
Eureka 简介
Eureka 是 Netflix 开发的一款服务注册与发现工具,在微服务架构中扮演着重要的角色。它主要用于管理微服务实例的注册信息,并提供服务发现的功能,使得各个微服务之间能够相互找到并进行通信。
工作原理
服务注册:
当一个微服务启动时,它会向 Eureka Server 发送一个注册请求,将自己的服务名称、IP 地址、端口号等信息注册到 Eureka Server 的服务注册表中。
Eureka Server 接收到注册请求后,将该服务的信息存储在注册表中,并返回一个确认信息给服务实例。
服务发现:
当一个微服务需要调用另一个微服务时,它会向 Eureka Server 发送一个查询请求,请求获取目标服务的实例信息。
Eureka Server 根据服务名称在注册表中查找对应的服务实例信息,并返回给请求的微服务。
请求的微服务根据返回的实例信息,选择一个合适的服务实例进行调用。
心跳机制:
使用步骤
添加依赖
在需要使用 Eureka 的项目中添加以下依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
创建 Eureka Server
创建一个 Spring Boot 项目作为 Eureka Server,在启动类上添加 @EnableEurekaServer
注解:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
在 application.properties
或 application.yml
配置文件中配置 Eureka Server 的相关信息:
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka/
服务注册到 Eureka
在需要注册到 Eureka 的微服务项目中添加以下依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
在微服务的启动类上添加 @EnableDiscoveryClient
注解:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
在微服务的配置文件中配置 Eureka Server 的地址:
server:
port: 8080
spring:
application:
name: service-name
cloud:
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
注意事项:
Ribbon 简介
Ribbon 是一个基于客户端的负载均衡器,它可以与服务注册中心(如 Eureka)配合使用,在微服务架构中实现客户端对服务端的负载均衡调用。当一个微服务有多个实例时,Ribbon 可以根据一定的负载均衡策略从多个实例中选择一个进行调用,从而提高系统的可用性和性能。
工作原理
使用步骤
添加依赖
在需要使用 Ribbon 的项目中添加以下依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
dependency>
配置 Ribbon
可以在配置文件中对 Ribbon 进行配置,例如设置服务名称、负载均衡策略等。
spring:
application:
name: service-consumer
cloud:
loadbalancer:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 设置负载均衡策略为随机
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
使用 Ribbon 进行服务调用
在代码中使用 @LoadBalanced
注解修饰 RestTemplate
,使其具备负载均衡的能力。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@RestController
public class ServiceConsumerApplication {
@Autowired
private RestTemplate restTemplate;
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/callService")
public String callService() {
return restTemplate.getForObject("http://service-provider/service", String.class);
}
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
}
注意事项:
IRule
接口实现来扩展 Ribbon 的负载均衡策略。Spring Cloud Feign 是一个声明式的 HTTP 客户端,它使得在微服务架构中进行服务调用变得更加简单和高效。
主要特点
使用步骤
添加依赖
在项目的 pom.xml
文件中添加 Spring Cloud Feign 的依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
开启 Feign
在服务的启动类上添加 @EnableFeignClients
注解,开启 Feign 功能:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class YourServiceApplication {
public static void main(String[] args) {
SpringApplication.run(YourServiceApplication.class, args);
}
}
定义服务接口
定义一个接口来描述对其他服务的调用,使用 @FeignClient
注解指定要调用的服务名称:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient("other-service")
public interface OtherServiceClient {
@GetMapping("/endpoint")
String callOtherService();
}
在这个例子中,定义了一个名为 OtherServiceClient
的接口,用于调用名为 other-service
的服务的 /endpoint
端点。
使用服务接口
在服务的代码中注入服务接口,并调用其中的方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class YourService {
@Autowired
private OtherServiceClient otherServiceClient;
public String doSomething() {
return otherServiceClient.callOtherService();
}
}
注意事项
服务名称和端点路径要正确配置,确保 Feign 能够正确找到目标服务。
如果目标服务的接口发生变化,需要及时更新 Feign 接口的定义,以保证服务调用的正确性。
可以配置 Feign 的日志级别,以便在开发和调试过程中查看请求和响应信息。例如,在配置文件中添加以下配置:
logging:
level:
org.springframework.cloud.openfeign: DEBUG
当使用 Feign 与其他组件(如 Hystrix)集成时,要注意配置的正确性,以确保断路器等功能能够正常工作。
Hystrix 简介
Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在微服务架构中,它主要用于实现断路器模式,当某个服务出现故障时,能够快速熔断该服务的调用,避免故障扩散,同时提供降级机制,返回备用的响应结果。
工作原理
监控服务调用:Hystrix 会监控服务调用的情况,包括请求数量、错误率、响应时间等指标。
触发熔断:当服务调用的错误率超过一定阈值或者响应时间过长时,Hystrix 会触发熔断,将该服务的调用快速失败,不再进行实际的服务调用。
降级处理:在服务熔断后,Hystrix 会执行降级逻辑,返回一个预设的备用响应结果或者执行一个备用的本地方法,以保证系统的可用性。
使用步骤
添加依赖
在项目中添加 Hystrix 的依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
dependency>
开启 Hystrix
在服务的启动类上添加@EnableCircuitBreaker
注解,开启 Hystrix 断路器功能:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
@SpringBootApplication
@EnableCircuitBreaker
public class YourServiceApplication {
public static void main(String[] args) {
SpringApplication.run(YourServiceApplication.class, args);
}
}
使用 Hystrix 命令
在服务的方法上使用@HystrixCommand
注解来定义 Hystrix 命令,指定降级方法和熔断策略等参数:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@Service
public class YourService {
@Autowired
private RemoteService remoteService;
@HystrixCommand(fallbackMethod = "fallbackMethod")
public String callRemoteService() {
return remoteService.doSomething();
}
public String fallbackMethod() {
return "Fallback response";
}
}
在这个例子中,当callRemoteService
方法调用远程服务出现故障时,会执行fallbackMethod
方法作为降级处理。
注意事项:
Zuul 简介
Zuul 是 Netflix 开源的微服务网关,它可以作为微服务架构中的统一入口,负责请求的路由和过滤。Zuul 可以将外部请求转发到内部的各个微服务,同时可以对请求进行安全验证、日志记录、流量控制等操作。
工作原理
使用步骤
添加依赖
在项目中添加 Zuul 的依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-zuulartifactId>
dependency>
创建 Zuul 网关
创建一个 Spring Boot 项目作为 Zuul 网关,在启动类上添加 @EnableZuulProxy
注解:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ZuulGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulGatewayApplication.class, args);
}
}
配置 Zuul
在配置文件中配置 Zuul 的路由规则和其他属性:
server:
port: 8080
spring:
application:
name: zuul-gateway
cloud:
zuul:
routes:
service1:
path: /service1/**
serviceId: service-provider1
service2:
path: /service2/**
serviceId: service-provider2
在这个配置中,定义了两个路由规则,将以 /service1/
开头的请求转发到名为 service-provider1
的服务,将以 /service2/
开头的请求转发到名为 service-provider2
的服务。
使用过滤器
可以创建自定义的过滤器来对请求进行处理。例如,创建一个前置过滤器来添加请求头:
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class PreRequestFilter extends ZuulFilter {
@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("Request: {} {}", request.getMethod(), request.getRequestURL());
ctx.addZuulRequestHeader("X-Custom-Header", "Custom Value");
return null;
}
}
在启动类中注册过滤器:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy
public class ZuulGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulGatewayApplication.class, args);
}
@Bean
public PreRequestFilter preRequestFilter() {
return new PreRequestFilter();
}
}
注意事项:
Spring Cloud Config 简介
Spring Cloud Config 是一个集中式的配置管理工具,用于在微服务架构中管理各个微服务的配置文件。它可以将配置信息存储在不同的后端存储中,如 Git、SVN、本地文件系统等,并提供了客户端和服务器端的实现,使得微服务可以从配置中心获取自己的配置信息,实现配置的集中管理和动态更新。
工作原理
使用步骤
添加依赖
在配置中心服务器项目中添加以下依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-config-serverartifactId>
dependency>
在需要从配置中心获取配置的微服务项目中添加以下依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-configartifactId>
dependency>
创建配置中心服务器
创建一个 Spring Boot 项目作为配置中心服务器,在启动类上添加 @EnableConfigServer
注解:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
在配置文件中配置后端存储的位置:
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-username/your-config-repo
search-paths: config-repo
这里假设使用 Git 作为后端存储,配置了 Git 仓库的地址和搜索路径。
微服务从配置中心获取配置
在微服务的配置文件中配置配置中心的地址和应用名称:
spring:
application:
name: service-name
cloud:
config:
uri: http://localhost:8888
name: service-name
profile: dev
这里指定了配置中心的地址为 http://localhost:8888
,应用名称为 service-name
,环境为 dev
。
微服务可以通过 @Value
注解或 Environment
对象来获取配置信息:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class ServiceApplication {
@Value("${custom.property}")
private String customProperty;
@GetMapping("/getProperty")
public String getProperty() {
return customProperty;
}
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
注意事项:
Spring Cloud Bus 简介
Spring Cloud Bus 是 Spring Cloud 中的一个消息总线,用于在分布式系统中传播状态变化,实现配置的动态更新和服务的自动发现等功能。它基于消息代理(如 RabbitMQ、Kafka 等)实现,可以将配置中心的配置变化通知到各个微服务,使微服务能够及时获取最新的配置信息。
工作原理
使用步骤
添加依赖
在需要使用 Spring Cloud Bus 的项目中添加以下依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-bus-amqpartifactId>
dependency>
这里假设使用 RabbitMQ 作为消息代理,如果使用其他消息代理,可以相应地调整依赖。
配置消息代理
在配置文件中配置消息代理的连接信息:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
cloud:
bus:
enabled: true
触发配置更新
可以通过向 /actuator/bus-refresh
端点发送 POST 请求来触发配置更新。例如,可以使用以下命令通过 curl 触发配置更新:
curl -X POST http://localhost:8080/actuator/bus-refresh
这里假设微服务运行在端口 8080 上。
注意事项:
Spring Cloud Alibaba 是一套开源的微服务解决方案,它基于 Spring Cloud 规范,并整合了阿里巴巴的开源组件。主要的组件有:
一、服务注册与发现
Nacos:
二、负载均衡
Ribbon(与 Spring Cloud 共用)或 LoadBalancer:
三、服务调用
Feign(与 Spring Cloud 共用)或 OpenFeign:
Feign 和 OpenFeign 有以下一些区别:
背景和关系
功能特性
依赖管理:
代码生成和灵活性:
性能和优化:
社区支持和更新:
总的来说,OpenFeign 在功能、性能和与 Spring Cloud 生态系统的集成方面都比传统的 Feign 更具优势,是构建微服务架构中服务调用的更优选择。
四、断路器
Sentinel:
五、网关
Spring Cloud Gateway:
六、分布式事务
Seata:
以下是 Spring Cloud Alibaba 中一些主要组件的示例代码和注意事项:
Nacos 是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
主要功能
服务注册与发现:
配置管理:
服务管理:
使用步骤
服务提供者示例:
创建一个 Maven 项目,在pom.xml
文件中添加以下依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.2.7.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
dependencies>
创建一个简单的服务提供者接口和实现类:
package com.example.provider.service;
public interface HelloService {
String sayHello();
}
package com.example.provider.service.impl;
import com.example.provider.service.HelloService;
import org.springframework.stereotype.Service;
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello() {
return "Hello from provider!";
}
}
创建一个控制器类:
package com.example.provider.controller;
import com.example.provider.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String hello() {
return helloService.sayHello();
}
}
在application.properties
文件中添加 Nacos 配置:
server.port=8081
spring.application.name=provider-service
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
服务消费者示例:
创建另一个 Maven 项目,在pom.xml
文件中添加与服务提供者相同的依赖。
创建一个服务消费者的接口和实现类:
package com.example.consumer.service;
public interface ConsumerService {
String callProvider();
}
package com.example.consumer.service.impl;
import com.example.consumer.service.ConsumerService;
import com.example.provider.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ConsumerServiceImpl implements ConsumerService {
@Autowired
private RestTemplate restTemplate;
@Override
public String callProvider() {
return restTemplate.getForObject("http://provider-service/hello", String.class);
}
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000);
factory.setReadTimeout(5000);
return new RestTemplate(factory);
}
}
}
创建一个控制器类:
package com.example.consumer.controller;
import com.example.consumer.service.ConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired
private ConsumerService consumerService;
@GetMapping("/callProvider")
public String callProvider() {
return consumerService.callProvider();
}
}
在application.properties
文件中添加 Nacos 配置:
server.port=8082
spring.application.name=consumer-service
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
配置管理示例:
在 Nacos 控制台中创建一个配置文件,命名为consumer-service.properties
,内容如下:
custom.message=Hello from Nacos config!
在服务消费者项目中添加配置管理依赖:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
在application.properties
文件中添加以下配置:
server.port=8082
spring.application.name=consumer-service
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.file-extension=properties
spring.cloud.nacos.config.prefix=consumer-service
创建一个配置类来读取配置:
package com.example.consumer.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Value("${custom.message}")
private String customMessage;
public String getCustomMessage() {
return customMessage;
}
}
在服务消费者的控制器中注入配置类并使用配置值:
package com.example.consumer.controller;
import com.example.consumer.config.AppConfig;
import com.example.consumer.service.ConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired
private ConsumerService consumerService;
@Autowired
private AppConfig appConfig;
@GetMapping("/callProvider")
public String callProvider() {
return consumerService.callProvider() + " " + appConfig.getCustomMessage();
}
}
通过以上代码示例,你可以看到如何使用 Spring Cloud Alibaba Nacos 实现服务注册与发现以及配置管理。首先,服务提供者将自己注册到 Nacos 服务注册中心,并提供一个简单的接口。服务消费者通过 Nacos 发现服务提供者,并调用其接口。同时,通过 Nacos 配置中心,服务消费者可以动态获取配置信息。
请注意,在实际使用中,你需要将 Nacos 的地址替换为你自己的实际地址,并根据需求调整配置和代码。
Spring Cloud Alibaba Sentinel 介绍
Spring Cloud Alibaba Sentinel 是一款面向分布式服务架构的流量控制组件,主要用于解决微服务架构中的流量控制、熔断降级、系统负载保护等问题。
流量控制:
熔断降级:
系统负载保护:
功能示例
流量控制示例:
pom.xml
文件中添加 Spring Cloud Alibaba Sentinel 的依赖。<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
application.properties
或application.yml
文件中添加 Sentinel 的配置信息,如控制台地址等。 spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080
@SentinelResource
注解来定义资源。import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@SentinelResource(value = "testResource", blockHandler = "handleBlock")
@GetMapping("/test")
public String test() {
return "Hello, Sentinel!";
}
public String handleBlock(BlockException ex) {
return "Too many requests, please try later.";
}
}
在这个例子中,/test
接口被定义为一个资源,当流量超过限制时,会调用handleBlock
方法返回错误响应。
熔断降级示例:
@SentinelResource
注解,并指定降级方法。import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@SentinelResource(value = "testResource", fallback = "handleFallback")
@GetMapping("/test")
public String test() {
// 模拟可能出现故障的代码
if (Math.random() < 0.5) {
throw new RuntimeException("Service is unavailable.");
}
return "Hello, Sentinel!";
}
public String handleFallback() {
return "Service is unavailable, please try later.";
}
}
在这个例子中,当/test
接口出现异常时,会调用handleFallback
方法返回降级后的响应。
通过使用 Spring Cloud Alibaba Sentinel,可以有效地保护微服务系统的稳定性和可靠性,提高系统的容错能力和可扩展性。
Seata 简介
Seata 致力于在微服务架构下提供高性能和简单易用的分布式事务服务。它通过对业务无侵入的方式,解决了分布式系统中的数据一致性问题。
Seata 主要有三个核心模块:
Transaction Coordinator (TC):事务协调器,负责管理全局事务的状态,协调各个事务参与者的提交或回滚操作。
Transaction Manager ™:事务管理器,由业务系统实现,负责开启、提交或回滚一个全局事务。
Resource Manager (RM):资源管理器,由业务系统实现,负责管理分支事务对数据库资源的操作。
使用步骤
添加依赖
在项目的 pom.xml
文件中添加 Seata 依赖:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-seataartifactId>
dependency>
配置 Seata 服务器
下载并启动 Seata 服务器,可以从 Seata 的官方仓库获取最新版本。配置文件(如 registry.conf
和 file.conf
)需要根据实际情况进行调整,主要配置包括注册中心地址、存储模式等。
业务代码集成
假设我们有两个服务 ServiceA 和 ServiceB,在 ServiceA 中调用 ServiceB 的业务方法,并且需要保证事务一致性。
ServiceA:
import com.alibaba.fastjson.JSONObject;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class ServiceAController {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private ServiceBClient serviceBClient;
@GlobalTransactional
@PostMapping("/operationA")
public JSONObject operationA() {
jdbcTemplate.update("INSERT INTO table_a (column1) VALUES ('value1')");
serviceBClient.operationB();
return new JSONObject();
}
}
ServiceB:
import com.alibaba.fastjson.JSONObject;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class ServiceBController {
@Autowired
private JdbcTemplate jdbcTemplate;
@PostMapping("/operationB")
public JSONObject operationB() {
jdbcTemplate.update("INSERT INTO table_b (column1) VALUES ('value2')");
return new JSONObject();
}
}
在 ServiceA 的 operationA
方法上添加 @GlobalTransactional
注解,开启全局事务。在这个方法中调用 ServiceB 的 operationB
方法,如果在执行过程中出现任何异常,Seata 会自动回滚全局事务,确保数据的一致性。
注意事项:
@GlobalTransactional
注解的方法中,尽量避免复杂的业务逻辑和长时间的操作,以免影响事务的性能和可靠性。Spring Cloud Gateway 是基于 Spring WebFlux 实现的 API 网关,用于为微服务架构提供统一的入口,并实现路由、过滤等功能。
引入依赖
在项目的 pom.xml
文件中添加以下依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
配置文件示例
以下是一个 application.yml
配置文件的示例:
server:
port: 8080
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
- id: service1-route
uri: lb://service1
predicates:
- Path=/service1/**
filters:
- StripPrefix=1
- id: service2-route
uri: lb://service2
predicates:
- Path=/service2/**
在这个配置中,定义了两个路由:
service1-route
:将以 /service1/
开头的请求转发到名为 service1
的服务(通过 lb://service1
使用服务发现来定位服务),并使用 StripPrefix
过滤器去除请求路径中的第一层前缀。service2-route
:类似地,将以 /service2/
开头的请求转发到 service2
服务。示例代码
假设已经有两个服务 service1
和 service2
,通过 Spring Cloud Gateway 进行路由转发。
创建一个 Spring Boot 应用作为网关服务:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
服务发现与负载均衡(如果使用服务注册中心):
假设使用 Eureka 或 Nacos 作为服务注册中心,网关可以通过服务发现和负载均衡机制将请求转发到具体的服务实例。
注意事项:
以下是一些 Spring Cloud Gateway 的其他配置示例:
添加全局过滤器
全局过滤器作用于所有的路由,可以实现一些通用的功能,比如统一的日志记录、安全验证等。
创建一个全局过滤器:
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class LoggingGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = request.getHeaders();
log.info("Request: {} {}", request.getMethod(), request.getURI());
log.info("Headers: {}", headers);
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("Response status: {}", response.getStatusCode());
}));
}
@Override
public int getOrder() {
return 0;
}
}
这个过滤器会记录请求的方法、URI 和请求头信息,以及响应的状态码。
在配置类中注册过滤器:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayConfig {
@Bean
public LoggingGlobalFilter loggingGlobalFilter() {
return new LoggingGlobalFilter();
}
}
路由权重配置
可以为同一个服务配置多个实例,并通过权重来分配请求流量。
假设服务 service1
有两个实例,一个权重为 2,另一个权重为 1。
配置文件:
spring:
cloud:
gateway:
routes:
- id: service1-route-1
uri: lb://service1/instance1
predicates:
- Path=/service1/**
filters:
- StripPrefix=1
metadata:
weight: 2
- id: service1-route-2
uri: lb://service1/instance2
predicates:
- Path=/service1/**
filters:
- StripPrefix=1
metadata:
weight: 1
这样,当有请求到达 /service1
路径时,会按照 2:1 的比例将请求分发到两个实例上。
请求超时配置
可以设置请求的超时时间,避免长时间等待响应。
配置文件:
spring:
cloud:
gateway:
routes:
- id: service1-route
uri: lb://service1
predicates:
- Path=/service1/**
filters:
- StripPrefix=1
timeouts:
connect: 5s
read: 10s
在这个配置中,设置了连接超时时间为 5 秒,读取超时时间为 10 秒。如果请求在规定时间内没有建立连接或没有收到响应,网关会中断请求并返回超时错误。
项目结构
假设我们有一个微服务架构,包含服务提供者和服务消费者。
依赖管理
在两个项目的 pom.xml
文件中添加以下依赖:
服务提供者和服务消费者共同依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
服务消费者额外依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
服务提供者(Service Provider)代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class ServiceProviderApplication {
@GetMapping("/service")
public String provideService() {
return "Hello from Service Provider!";
}
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
服务消费者(Service Consumer)代码
创建服务接口:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient("service-provider")
public interface ServiceProviderClient {
@GetMapping("/service")
String getService();
}
编写服务消费者代码:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class ServiceConsumerApplication {
@Autowired
private ServiceProviderClient serviceProviderClient;
@GetMapping("/callService")
public String callService() {
return serviceProviderClient.getService();
}
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
}
服务消费者启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class ServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
}
配置文件(假设使用了服务注册中心 Nacos,服务消费者配置):
server:
port: 8081
spring:
application:
name: service-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
注意事项:
logging:
level:
org.springframework.cloud.openfeign: DEBUG