微服务之SpringCloud-服务保护机制Hystrix

在大型复杂分布式系统中,高可用技术架构至关重要。为解决服务间调用超时、失败等可用性问题,涉及资源隔离、限流、熔断等技术。文中介绍了服务雪崩效应、降级、熔断、隔离、限流的概念,还给出了消费者和提供者服务的代码示例及调用情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

微服务高可用技术

大型复杂的分布式系统中,高可用相关的技术架构非常重要。高可用架构非常重要的一个环节,就是如何将分布式系统中的各个服务打造成高可用的服务,从而足以应对分布式系统环境中的各种各样的问题,,避免整个分布式系统被某个服务的故障给拖垮.

比如:服务间的调用超时、服务间的调用失败

要解决这些棘手的分布式系统可用性问题,就涉及到了高可用分布式系统中的很多重要的技术,包括:

资源隔离

限流与过载保护

熔断

优雅降级

容错

超时控制

监控运维

服务降级、熔断、限流概念

服务学崩效应

      服务雪崩效应产生与服务堆积在同一个线程池中,因为所有的请求都是同一个线程池进行处理,这时候如果在高并发情况下,所有的请求全部访问同一个接口,这时候可能会导致其他服务没有线程进行接受请求,这就是服务雪崩效应效应。

总结为:雪崩效应是一种因“服务提供者”的不可用导致“服务消费者”的不可用,并将不可用逐步放大的过程。

服务降级

     在高并发情况下,防止用户一直等待,使用服务降级方式(直接返回一个友好的提示给客户端,调用fallBack方法)

服务熔断

     熔断机制目的为了保护服务,在高并发的情况下,如果请求达到一定极限(可以自己设置阈值)如果流量超出了设置阈值,让后直接拒绝访问,保护当前服务。使用服务降级方式返回一个友好提示,服务熔断和服务降级一起使用

服务隔离

     因为默认情况下,只有一个线程池会维护所有的服务接口,如果大量的请求访问同一个接口,达到线程池默认极限,可能会导致其他服务无法访问。

     解决服务雪崩效应:使用服务隔离机制(线程池方式和信号量),使用线程池方式实现隔离的原理:  相当于每个接口(服务)都有自己独立的线程池,因为每个线程池互不影响,这样的话就可以解决服务雪崩效应。

  线程池隔离:

         每个服务接口,都有自己独立的线程池,每个线程池互不影响。

  信号量隔离:

         使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,当请求进来时先判断计数器的数值,若超过设置的最大线程个数则拒绝该请求,若不超过则通行,这时候计数器+1,请求返 回成功后计数器-1。

服务限流

       服务限流就是对接口访问进行限制,常用服务限流算法令牌桶、漏桶。计数器也可以进行粗暴限流实现

 

概念介绍完了,现在直接上代码!

我这边有两个服务,一个是消费者服务(consumer),另一个是提供者服务(provider),这两个服务都是注册在Eureka中,关于Eureka的使用在这不做过多的介绍,可以查看我的这篇文章springboot+springcloud+eureka实现高可用注册中心

Provider服务

application.yml

###服务启动端口号
server:
  port: 8007
###服务名称(服务注册到eureka名称)  
spring:
    application:
        name: zxf-lancoo-zxfprovider
###集群地址
eureka:
  client:
   registryFetchIntervalSeconds: 5
   service-url:
    defaultZone: http://127.0.0.1:8100/eureka,http://127.0.0.1:8200/eureka
###因为该应用为注册中心,不会注册自己
   register-with-eureka: true 
###是否需要从eureka上获取注册信息
   fetch-registry: true 

pom.xml

<dependencies>
		<!-- SpringBoot整合Web组件 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- SpringBoot整合eureka客户端 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

controller

 @RequestMapping("/getProviderInfo")
	 public String getProviderInfo() {
		// TODO Auto-generated method stub
		try {
			//会员服务产生1500毫秒的等待
			Thread.sleep(15000);  //假设处理业务所需时间为1.5秒,因为hystrix默认超时为1秒
		} catch (Exception e) {
			// TODO: handle exception
		}
		return "consumer服务调用provider服务成功...";
		//return setResultSuccess("订单服务接口调用会员服务接口成功...");
	 }

启动类AppProvider

@SpringBootApplication
@EnableEurekaClient
public class AppProvider {

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

}

consumer服务

application.yml

###服务启动端口号
server:
  port: 8005
###服务名称(服务注册到eureka名称)  
spring:
 application:
  name: lancoo-zxf-zxfconsumer
#单个服务注册
# boot: 
#  admin:
#   client: 
#    url: "http://localhost:8000"
###服务注册到eureka集群
eureka:
  client:
   registryFetchIntervalSeconds: 5
   service-url:
    defaultZone: http://127.0.0.1:8100/eureka,http://127.0.0.1:8200/eureka
###因为该应用为注册中心,不会注册自己
   register-with-eureka: true
###是否需要从eureka上获取注册信息
   fetch-registry: true
#开启Hystrix断路器 20190620  
feign:
  hystrix:
    enabled: true

pom.xml

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- SpringBoot整合eureka客户端 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<!-- hystrix断路器 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>
</dependencies>

controller

//没有解决服务雪崩效应
	@RequestMapping("/consumeToProvider")
	public String consumeToProvider() {
		// TODO Auto-generated method stub
		System.out.println("RPC远程服务地址:"+getProviderServer());
		String providerUrl = getProviderServer()+"/getProviderInfo";// 生产端getProviderInfo地址
		System.out.println("访问远程服务getProviderInfo地址:"+providerUrl);
		//ServiceInstance serviceInstance = loadBalancerClient.choose("zxf-lancoo-zxfprovider");
		RestTemplate restTemplate = getRestTemplate();
		String result = restTemplate.getForObject(providerUrl, String.class);
		//String result = restTemplate.getForObject(serviceInstance.getUri()+"/getProviderInfo", String.class);
		System.out.println("访问远程服务结果:"+result);
		System.out.println("consumeToProvider:"+"线程池名字:"+Thread.currentThread().getName());
		return result+"-------"+"线程池名字:"+Thread.currentThread().getName();
	}
	//解决雪崩效应
	/**
	 * 解决服务雪崩效应  第一种方式:直接写
	 * fallbackMethod   服务降级执行
	 * hystrix:  
	 * @HystrixCommand 默认开启线程池隔离方式、服务降级、服务熔断
	 * 设置禁止hystrix超时时间  command.default.execution.timeout.enabled: false  业务逻辑能执行,浏览器响应,所以走服务降级
	 * @return
	 */
	@HystrixCommand(fallbackMethod = "consumeToProviderHystrixFallBack")
	@RequestMapping("/consumeToProviderHystrix")
	public String orderToMemberUserInfoHystrix() {
		// TODO Auto-generated method stub
		String providerUrl = getProviderServer()+"/getProviderInfo";// 生产端getProviderInfo地址
		System.out.println("访问远程服务getProviderInfo地址:"+providerUrl);
		RestTemplate restTemplate = getRestTemplate();
		String result = restTemplate.getForObject(providerUrl, String.class);
		System.out.println("consumeToProviderHystrix:"+"线程池名字:"+Thread.currentThread().getName());
		return result+"-------"+"线程池名字:"+Thread.currentThread().getName();
	}
	public String consumeToProviderHystrixFallBack() {
			
		return "返回一个友好的提示:服务降级,服务器忙,请稍后重试!";
	}

启动类AppConsumer

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix//开启Hystrix
public class AppConsumer {

	public static void main(String[] args) {
		SpringApplication.run(AppConsumer.class, args);
	}
	@Bean
	@LoadBalanced    //@LoadBalanced就能让这个RestTemplate在请求时拥有客户端负载均衡的能力
	RestTemplate restTemplate() {
		
		return new RestTemplate();
	}

}

访问:http://127.0.0.1:8005/consumeToProvider   模仿consumer调用provider中的 consumeToProvider 方法  等15秒之后才响应

访问:http://127.0.0.1:8005/consumeToProviderHystrix

之所以出现这样的情况是因为,在consumer服务调用provider服务中的consumeToProviderHystrix方法时用了Hystrix,而provider服务中的consumeToProviderHystrix休眠了15后才能返回结果,但是Hystrix默认超时时间为1秒钟,所以consumer启动了服务降级。可以将consumeToProviderHystrix的休眠时间改为1秒以内或者是在consumer的yml中加入如下配置等待15秒过后出现结果。

### hystrix禁止服务超时时间
hystrix:  
 command: 
   default: 
      execution: 
       timeout: 
        enabled: false

 从两个线程名可以看得出Hystrix默认开启用线程池隔离来解决服务雪崩效应的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值