背景介绍
1. 服务雪崩
分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。
一个服务失败,导致整条链路的服务都失败的情形,我们称之为服务雪崩
2.引起服务雪崩和服务雪崩的三个阶段
原因大致有四:
硬件故障
程序bug
缓存击穿(用户大量访问缓存中没有键值,导致大量请求数据库,使数据库压力过大)
用户大量请求
服务雪崩的第一阶段:
服务不可用
调用端重试加大流量
服务调用者不可用
3.解决方案
应用扩容(加机器;升级硬件)
流量控制(限流;关闭重试)
缓存(将用户可能大量访问的数据放入缓存,减少数据库压力)
服务降级
服务熔断
入门
Hystrix是一个用于处理分布式系统延期和容错的开源库,Hystrix能保证在一个依赖出问题的情况下,不会导致整体服务失败,提高分布式弹性。
服务降级: 假设对方系统不可用了,向调用方返回一个符合预期的,可处理的备选响应,而不是长时间等待或者抛出无处理的异常。这样就保证了服务方的线程不会被长时间不必要的占用,从而避免故障在分布式系统中蔓延,乃至雪崩。
服务熔断:达到最大访问后直接拒绝访问
服务限流:秒杀高并发等操作,排队有序进行
代码
1.没有引入hystrix的准备工作
建这三个工程模拟Hystrix服务降级
EurekaMain7001代码:
pom:
<!--Eureka server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
yml:
server: port: 7001 eureka: instance: hostname: eureka7001.com client: #表示不往注册中心注册自己 register-with-eureka: false #表示自己端就是注册中心,我的职责就是维护实例 fetch-registry: false #设置地址 service-url: defaultZone: http://eureka7001.com:7001/eureka/
主启动类:
@SpringBootApplication @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class, args); } }
HystrixPaymentMain8001代码:
pom:
<!--Eureka server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
yml:
server: port: 8001 spring: application: name: cloud-payment-hystrix-service eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:7001/eureka/ instance: instance-id: hystrix-payment8001 prefer-ip-address: true
service层:
@Service public class HystrixPaymentService { public String getPaymentInfoSuccess() { return "thread poor: " + Thread.currentThread().getName() + " success"; } public String getPaymentInfoTimeout() { try { int spendTime = 3000; TimeUnit.MILLISECONDS.sleep(spendTime); } catch (InterruptedException e) { e.printStackTrace(); } return "thread poor: " + Thread.currentThread().getName() + " timeout"; } }
controller:
@RestController @Slf4j public class HystrixPaymentController { @Resource HystrixPaymentService service; @GetMapping("/payment/hystrix/ok") public String getPaymentInfoSuccess() { return service.getPaymentInfoSuccess(); } @GetMapping("/payment/hystrix/timeout") public String getPaymentInfoTimeout() { return service.getPaymentInfoTimeout(); } }
主启动类:
@SpringBootApplication @EnableEurekaClient public class HystrixPaymentMain8001 { public static void main(String[] args) { SpringApplication.run(HystrixPaymentMain8001.class, args); } }
HystrixOrderMain80代码:
pom:
<!-- open feign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--eureka client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
yml:
server: port: 80 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/ ribbon: ReadTimeout: 5000 ConnectTimeout: 5000
service接口:
@Component @FeignClient(value = "CLOUD-PAYMENT-HYSTRIX-SERVICE") public interface HystrixService { @GetMapping("/payment/hystrix/ok") public String getPaymentInfoSuccess(); @GetMapping("/payment/hystrix/timeout") public String getPaymentInfoTimeout(); }
controller:
@RestController public class HystrixController { @Resource private HystrixService hystrixService; @GetMapping("/consumer/payment/hystrix/ok") public String getPaymentInfoSuccess() { return hystrixService.getPaymentInfoSuccess(); } @GetMapping("/consumer/payment/hystrix/timeout") public String getPaymentInfoFail() { return hystrixService.getPaymentInfoTimeout(); } }
主启动类:
@SpringBootApplication @EnableFeignClients public class HystrixOrderMain80 { public static void main(String[] args) { SpringApplication.run(HystrixOrderMain80.class, args); } }
到此,payment注册到eureka, order用openFeign调用payment过程已经完成。
2.压力测试
用jmeter两万个线程调用timeout接口,再通过chrome访问ok接口,会发现chrome访问的ok接口也会响应过慢。
ok过慢
解决:
原文:https://www.cnblogs.com/dayanjing/p/14814589.html