小蔡学Java

Spring Cloud之五大组件

2023-09-09 20:55 1395 0 SpringCloud SpringCloud

Spring Cloud的5大组件

Eureka:注册中心

Ribbon:负载均衡

Feign:远程调用

Hystrix:服务熔断

Zuul/Gateway:网关

特别地,在Spring Cloud Alibaba中

Nacos:注册中心/配置中心

Ribbon:负载均衡

Feign:服务调用

Sentinel:服务保护

Gateway:服务网关

1、注册中心

注册中心的核心作用:服务注册和发现

常见的注册中心有:Eureka、Nocas、Zookeeper

1.1、Eureka

Eureka是Netflix开发的一个用于实现服务注册和发现的服务。Eureka主要由两部分组成:Eureka服务器和Eureka客户端。

(1)服务注册

服务方需要把自己的信息注册到eureka,由eureka来保持这些信息(如服务名称、IP、端口等)。

(2)服务发现

消费者向eureka拉取服务列表信息,如果服务方有集群,则消费方会利用负载均衡算法,选择一个发起调用。

(3)服务监控

服务方会每隔30秒向eureka发送心跳,报告健康状态,如果eureka服务90秒没收到心跳,从eureka中剔除。

1.2、Nacos

Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它支持多种服务治理能力,包括服务注册与发现、动态配置管理、动态DNS服务等。

(1)注册服务

Nacos作为注册中心,接收客户端(服务实例)发起的注册请求,并将注册信息存放到注册中心进行管理。注册请求的处理包括客户端组装注册请求、随机选择集群中的一个Nacos节点发起注册、实现负载均衡、路由转发、处理请求、保证数据最终一致性等步骤。

(2)服务发现

Nacos通过维护服务实例的列表,使得服务消费者可以通过Nacos查询到可用服务的列表,进而进行服务调用。

(3)临时实例与永久实例

Nacos中区分了临时实例和永久实例。

临时实例在注册到注册中心后仅保存在服务端内部缓存中,不会持久化到磁盘。当服务实例异常或下线时,会从服务注册表中剔除。

而永久实例不仅存在于服务注册表中,还会被持久化到磁盘文件中。即使服务实例异常或下线,Nacos也不会将其从服务注册表中剔除,而是将其健康状态设置为不健康。

1.3、nacos和eureka的区别

在都作为注册中心的前提下

(1)共同点

1)都支持服务注册和服务拉取

2)都支持服务方心跳方式做健康检测

(2)不同点

1)nacos支持“服务端”主动检测“服务方”状态:临时实例采用心跳模式,非临时实例采用主动检测模式

2)临时实例心跳不正常会被剔除,非临时实例则不会被剔除

3)nacos支持服务列表变更的消息推送模式,服务列表更新更及时

4)nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;eureka采用AP方式

AP模式(Availability Priority Mode)高可用性

CP模式(Consistency Priority Mode)一致性

特别地,nacos还支持了配置中心,eureka则只有注册中心。

2、负载均衡

负载均衡ribbon,发起远程调用feign

2.1、Ribbon负载均衡策略有哪些

RoundRobinRule:简单轮询服务列表来选择服务器

WeightedResponseTimeRule:按照权重来选择服务器,响应时间越长,权重越小

RandomRule:随机选择一个可用的服务器

BestAvailableRunle:忽略那些短路的服务器,并选择并发数较低的服务器

RetryRule:重试机制的选择逻辑

AvailabilityFilteringRule:可用性敏感策略,先过滤非健康的,再选择连接数较小的实例

ZoneAvoidanceRule:以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后对Zone内的多个服务做轮询。

2.2、自定义负载均衡策略的实现

自定义负载均衡策略的实现,有两种方式

方式一:创建类实现IRule接口,可以指定负载均衡策略(全局)

方式二:在客户端的配置文件中,可以配置某一个服务调用的负载均衡策略(局部)

2.3、示例代码

自定义负载均衡策略可以通过实现com.netflix.loadbalancer.IRule接口来完成。


@Configuration
public class CustomLoadBalancerConfiguration {

    @Bean
    public IRule randomRule() {
        return new RandomRule(); // 自定义的轮询策略
    }

}


class RandomRule extends RoundRobinRule {
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // 初始化逻辑,如果需要的话
    }
 
    @Override
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;
        while (server == null) {
            // 随机从服务器列表中选择一个
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();
            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }
            int index = new Random().nextInt(serverCount);
            server = upList.get(index);
            if (server == null) {
                Thread.yield();
            }
        }
        return server;
    }
}

在这个示例中,我们定义了一个RandomRule类,它继承自RoundRobinRule(轮询策略),并覆盖了choose方法,使其实现随机选择服务器的逻辑。这个自定义策略可以替代默认的轮询策略。通过将RandomRule作为一个Bean注册到Spring上下文中,它将会被应用到使用Ribbon进行负载均衡的服务调用中。

3、远程调用

3.1、Feign

Feign是一个声明式的Web服务客户端,用来简化HTTP远程调用。在Spring Cloud中,Feign可以用来封装HTTP调用的接口,使得调用远程服务就像调用本地方法一样简单通过创建一个接口并注解,Feign可以生成实现该接口的动态代理,从而允许调用其他服务.

(1)Feign支持HTTP的各种方法

包括GET、POST、PUT、DELETE和PATCH等。通过使用@RequestMapping注解及其变种(如@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping)来指定HTTP方法。

(2)如何配置Feign的超时时间

可以通过在Feign客户端的配置文件中设置超时时间来配置Feign的超时时间。例如,将连接超时时间和读取超时时间都设置为5000毫秒(5秒),可以在application.properties或application.yml文件中进行如下配置:

feign.client.config.default.connectTimeout=5000
feign.client.config.default.readTimeout=5000

这将确保如果请求在5秒内没有连接成功或没有返回结果,Feign将会超时。

(3)Feign如何处理服务降级

Feign可以通过集成Hystrix来实现服务降级。要启用服务降级,可以执行以下步骤:首先,添加Hystrix依赖到项目中;其次,在Feign客户端的方法上使用@HystrixCommand注解;最后,配置Hystrix的属性以实现降级逻辑,如设置回退方法等。

(4)Feign与Ribbon的关系

Feign与Ribbon结合使用可以实现客户端负载均衡。Feign本身不直接支持负载均衡策略,而是通过集成Ribbon来实现。因此,Feign可以使用Ribbon支持的各种负载均衡策略,包括轮询、随机、权重、最佳可用等。要配置Feign使用特定的负载均衡策略,可以在Feign客户端的配置文件中设置Ribbon的负载均衡策略

3.2、示例代码-Feign

(1)添加依赖(pom.xml)

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

(2)启用Feign客户端(在启动类上添加@EnableFeignClients注解)

```java

@SpringCloudApplication @EnableFeignClients public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }


(3)创建Feign客户端接口


```java
	@FeignClient(name = "remote-service", url = "http://localhost:8080")
	public interface RemoteServiceClient {
		@GetMapping("/data/{id}")
		String getData(@PathVariable("id") Long id);
	}

(4)使用Feign客户端进行调用

	@RestController
	public class MyController {

		@Autowired
		private RemoteServiceClient remoteServiceClient;

		@GetMapping("/localData/{id}")
		public String getLocalData(@PathVariable("id") Long id) {
			return remoteServiceClient.getData(id);
		}
	}

RemoteServiceClient是一个Feign客户端接口,用来定义远程服务remote-service的调用方法。在MyController中,我们通过注入RemoteServiceClient来进行远程调用,并将结果返回给客户端。

注意:上述代码中的url属性是可选的,如果需要调用多个URL,可以使用@FeignClient注解的contextId属性,然后在application.properties或application.yml中配置不同的URL。

4、服务熔断

(1)服务雪崩

一个服务失败,导致整条链路的服务都失败的情形

(2)服务降级

服务自我保护的一种方式,或者保护下游服务的一种方式,用于确保服务不会受请求突多影响变得不可用,确保服务不会崩溃,一般在实际开发中与feign接口整合,编写降级逻辑。

(3)服务熔断

默认关闭,需要手动打开,如果检测到10秒内接口失败率超过了50%,就触发熔断机制。之后每隔5秒重新尝试请求微服务,如果微服务不能响应,继续走熔断机制。如果微服务可达,则关闭熔断机制,恢复正常请求。

4.1、sentinel和hystrix区别

Sentinel和Hystrix都是用于微服务架构中的熔断降级框架,但它们在设计理念、功能实现和应用场景上存在显著差异。具体如下:

隔离策略和动态调节: Sentinel提供了基于线程池和信号量的隔离方式,并且能够根据系统负载情况动态调整资源的并发度,这使得它更加灵活且适应性强。相比之下,Hystrix主要采用线程池隔离,虽然也支持信号量隔离,但在动态调节方面相对静态,需要通过配置进行调整。

功能和适用场景: Sentinel不仅提供熔断降级功能,还包括流量控制、实时监控和动态规则配置等,使其适用于需要流量控制和系统负载保护的复杂场景。Hystrix则专注于熔断和降级功能,更适用于需要快速响应和高并发控制的场景。

实时指标统计: 两者都基于滑动窗口进行实时指标统计,但Sentinel的默认实现是基于LeapArray的高性能滑动窗口,而Hystrix在1.5版本后对实时指标统计的实现进行了重构,采用了基于RxJava的事件驱动模式。

总结来说,选择Sentinel还是Hystrix应根据项目的具体需求和技术栈来决定,如果项目需要高度的灵活性和动态调节能力,以及流量控制功能,Sentinel可能是更好的选择;如果项目主要关注快速失败和资源隔离,以及对配置的精细控制,Hystrix可能更适合。

4.2、示例代码-Sentinel

(1)添加依赖
	<dependency>
		<groupId>com.alibaba.cloud</groupId>
		<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
	</dependency>

(2)配置Sentinel控制台地址,在application.properties或application.yml中添加:

	spring.cloud.sentinel.transport.dashboard=localhost:8080
	spring.cloud.sentinel.transport.port=8719

(3)启动Sentinel控制台

(4)在服务中添加服务熔断的逻辑。例如,使用@SentinelResource注解标记需要进行服务熔断的方法:


	@RestController
	public class TestController {

		@GetMapping("/test")
		@SentinelResource(value = "test", blockHandler = "handleException")
		public String test() {
			return "Test";
		}

		public String handleException(BlockException ex) {
			return "Service is blocked, please try again later.";
		}
	}

上述,当服务熔断触发时,Sentinel会调用handleException方法来处理请求,并返回一个错误消息。

4.3、示例代码-Hystrix

在Spring Cloud中,Hystrix被整合到了Spring Cloud Netflix中,通过使用@HystrixCommand注解,可以为远程服务调用(如使用Ribbon的服务调用)定义熔断逻辑。

一个简单的使用Hystrix服务熔断的例子:

	@Service
	public class HelloService {

		@Autowired
		private RestTemplate restTemplate;

		@HystrixCommand(fallbackMethod = "fallbackMethod")
		public String getHelloMessage() {
			return restTemplate.getForObject("http://HELLO-SERVICE/hello", String.class);
		}

		public String fallbackMethod() {
			return "Hello Service is not available";
		}
	}

上述,getHelloMessage方法调用了HELLO-SERVICE服务的/hello端点。如果该服务不可用,Hystrix会执行定义的回退方法fallbackMethod,而不是抛出异常或导致线程阻塞。这样可以保证调用服务的客户端即使服务不可用,也会收到一个响应,而不是等待或者产生更多的级联错误。

5、网关

Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。

5.1、示例代码

Spring Cloud 的网关组件是 Spring Cloud Gateway。以下是一个简单的 Spring Cloud Gateway 示例配置,它使用了 Netty 作为底层通信框架,并且通过路由配置来转发请求。

(1)在 pom.xml 中添加依赖

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
		<!-- 如果想使用 consul 作为路由配置的源,还需要添加 consul 依赖 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-consul-discovery</artifactId>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Finchley.SR2</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

(2)配置 application.yml

	spring:
	  cloud:
		gateway:
		  routes:
			- id: my_route
			  uri: http://localhost:8081
			  predicates:
				- Path=/myservice/**
			- id: my_route2
			  uri: http://localhost:8082
			  predicates:
				- Path=/myservice2/**

在这个配置中,我们定义了两条路由规则:

  • 当请求路径匹配 /myservice/** 时,转发到 http://localhost:8081

  • 当请求路径匹配 /myservice2/** 时,转发到 http://localhost:8082

(3)启动类

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

这样就配置了一个简单的 Spring Cloud Gateway,它能够根据配置的路由规则转发请求。如果需要更复杂的路由逻辑,可以通过编写 Predicate 和 Filter 来实现。

评论( 0 )

  • 博主 Mr Cai
  • 坐标 河南 信阳
  • 标签 Java、SpringBoot、消息中间件、Web、Code爱好者

文章目录