负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。
单独导入
COPY <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.1.RELEASE</version> </dependency>
整合依赖spring-cloud-starter-netflix-eureka-client里面也包含了ribbon的依赖
COPY <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.1.RELEASE</version> </dependency>
书写自定义负载均衡策略类,先继承AbstractLoadBalancerRule抽象类,该类是IRule接口的一个抽象实现类,继承它,然后自定义自己的负载均衡策略,注入spring容器即可覆盖原有的轮询策略。
COPYpublic class HcodeRule extends AbstractLoadBalancerRule { //每个服务,访问5次,然后循环所有服务 private AtomicInteger total = new AtomicInteger(); //服务被调用的次数 private AtomicInteger currentIndex = new AtomicInteger(); //当前被调用服务的下标 public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } Server server = null; while (server == null) { if (Thread.interrupted()) { return null; } //获得活着的服务 List<Server> upList = lb.getReachableServers(); //获得全部服务 List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if (serverCount == ) { return null; } // //生成区间随机数 // int index = chooseRandomInt(serverCount); // server = upList.get(index); //从或者的服务中随机获取一个 /*============================================*/ if(total.get()<){ server = upList.get(currentIndex.get()); getAndIncrement(total); }else{ total.set(); getAndIncrement(currentIndex); if(currentIndex.get()>=upList.size()){ currentIndex.set(); } server = upList.get(currentIndex.get()); getAndIncrement(total); } /*==============================================*/ if (server == null) { Thread.yield(); continue; } if (server.isAlive()) { return (server); } // Shouldn't actually happen.. but must be transient or a bug. server = null; Thread.yield(); } return server; } //自旋锁防止高并发情况数据不一致性 private final int getAndIncrement(AtomicInteger atomicInteger){ int current; int next; do { current = atomicInteger.get(); next = current >= ? : current + ; }while (!atomicInteger.compareAndSet(current,next)); //第一个参数是期望值,第二个参数是修改值是 return next; } protected int chooseRandomInt(int serverCount) { return ThreadLocalRandom.current().nextInt(serverCount); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { // TODO Auto-generated method stub } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } }
再将该策略类注入IOC容器,当然如果不想写自定义策略类,那就使用原有的IRule的实现类,将其注入IOC容器即可.下面两种二选一
COPY@Configuration public class MyRule { @Bean //使用自定义的 public IRule HcodeRule(){ return new HcodeRule(); } //============================================================ //AvailabilityFilteringRule : 先过滤掉出现故障的服务器,对剩下的服务进行轮询 //RoundRobinRule 轮询 默认设置 //RandomRule 随机 //WeightedResponseTimeRule 权重 //RetryRule:先按照轮询获取,若获取服务失败,则在指定时间内进行重试 //随机访问,只要将实现类注入到ICO容器,即可覆盖 @Bean //使用原有的实现类 public IRule myRule(){ return new RandomRule(); } }
COPY@SpringBootApplication @EnableEurekaClient //在微服务启动的时候就能去加载我们自定义的负载均衡Ribbon类,name为微服务提供者注册到注册中心的服务名 @RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class) public class DeptConsumer_80 { public static void main(String[] args) { SpringApplication.run(DeptConsumer_80.class,args); } }
单独导入依赖 org.springframework.cloud:spring-cloud-starter-hystrix:2.2.1.RELEASE
COPY<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.1.RELEASE</version> </dependency>
使用eureka整合客户端pom就不用再导入单独的hystrix
COPY <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
COPY@RestController @DefaultProperties(defaultFallback = "Global_FallbackMethod") //没有配置专属熔断器方法,就走全局熔断器 public class TestController { @HystrixCommand //没加特定方法,走全局 @PostMapping("/global") public String test1(){ return "(●'◡'●)全局熔断器方法未触发"; } //全局响应Fallback方法 服务降级触发熔断 public Object Global_FallbackMethod(){ return "┭┮﹏┭┮全局熔断器方法触发了,呜呜呜!"; } //断路器 @HystrixCommand( fallbackMethod = "CircuitBreaker_fallback" , commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),// 是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 请求次数 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //时间窗口期,失败后经过多久尝试恢复 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") //失败率到达多少后跳闸 }) @GetMapping("/local") public String test2(){ return "(●'◡'●)特定断路器方法未触发~"; } public String CircuitBreaker_fallback(){ //参数可以跟原接口方法参数一致 return "┭┮﹏┭┮特定限制方法熔断器触发了,呜呜呜~"; } }
3. 微服务提供者的主启动类加上开启断路器的注解
COPY@EnableCircuitBreaker //添加对服务熔断的支持
COPY<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
然后配置yml,让feign支持hystrix
COPYfeign: hystrix: enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
然后再服务层接口加上注解。
COPY@FeignClient(value = "hystrix-test-provider",fallback = DeptFallbackService.class) //服务名,备用的响应类 @Component public interface testService { @GetMapping("/global") public String test1(); }
兜底用的备用响应类
COPY@Component // 服务降级 public class DeptFallbackService implements testService{ public String test1() { return "┭┮﹏┭┮该服务被降级了,目前无法使用"; } }
最后,主启动类添加@EnableHystrix
COPY@EnableHystrix
老样子,hystrix也是停止更新了,所以换新的才是王道~况且阿里巴巴的sentinel就是继承hystrix,两者挺像的。 - 官网下载:https://github.com/alibaba/Sentinel/releases - 特性:
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。 - 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
下载好jar包sentinel-dashboard-1.7.0.jar后,直接命令行运行即可~ 注意:该boot服务默认为8080端口号。启动后,访问http://localhost:8080,账号密码都是sentinel。
COPY <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
2. 配置yml
COPYserver: port: spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 # nacos注册中心的地址 sentinel: transport: dashboard: localhost:8080 # sentinel的地址 port: #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口 # 暴露监控 management: endpoints: web: exposure: include: '*'
3. 主启动类添加注解
COPY@EnableDiscoveryClient @SpringBootApplication
4. 控制层针对服务限流的备用方法,至于限流方式,就直接再sentinel控制台直接添加即可,@SentinelResource的value参数就是对应的资源名,里面也可以加fallback调用断路器备用响应方法,使用跟@HystrixCommand差不多。
COPY@RestController @SentinelResource(fallbackClass = "Global_FallbackMethod") public class TestController { @SentinelResource(value = "test",blockHandlerClass = CustomerBlockHandle.class,blockHandler ="deal_test") @GetMapping("/test") public String test(@RequestParam(value = "p") String p){ return "(●'◡'●)没有被限流"; } // public String test(String p,BlockException blockException){ // return "-------------deal list ┭┮﹏┭┮"; // } //全局响应Fallback方法 服务降级触发熔断 public Object Global_FallbackMethod(){ return "┭┮﹏┭┮全局熔断器方法触发了,呜呜呜!"; } }
统一处理限流的备用方法类
COPYpublic class CustomerBlockHandle { public static String deal_test(String p, BlockException blockException){ return "┭┮﹏┭┮被限流了"; } }
COPY <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
2. 配置yml
COPYserver: port: spring: application: name: nacos-test-consumer cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: service-url: nacos-user-service: http://cloudalibaba-sentinel-service #对Feign的支持 feign: sentinel: enabled: true
3. 配置接口以及接口的服务降级备用响应的实现类
COPY@FeignClient(value = "cloudalibaba-sentinel-service",fallback = DeptFallbackService.class) @Component public interface TestService { @GetMapping("/test") public String test(); }
COPY@Component // 服务降级 public class DeptFallbackService implements DeptService { public String test() { return "┭┮﹏┭┮服务被降级了,不能使用~"; } }
4. controller层服务调用
COPY@Autowired private TestService testService ; @GetMapping(value = "/consumer/test") public String test(){ return testService.test(); }
COPY@EnableDiscoveryClient @SpringBootApplication @EnableFeignClients public class test80 { public static void main(String[] args) { SpringApplication.run(test80.class, args); } }
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句