负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。
导入pom依赖单独导入
<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的依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.1.RELEASE</version> </dependency> 在主启动类所在包的上一级创建一个包,用来创建自定义负载均衡策略类 书写自定义负载均衡策略类,先继承AbstractLoadBalancerRule抽象类,该类是IRule接口的一个抽象实现类,继承它,然后自定义自己的负载均衡策略,注入spring容器即可覆盖原有的轮询策略。 public class HcodeRule extends AbstractLoadBalancerRule { //每个服务,访问5次,然后循环所有服务 private AtomicInteger total = new AtomicInteger(0); //服务被调用的次数 private AtomicInteger currentIndex = new AtomicInteger(0); //当前被调用服务的下标 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 == 0) { return null; } // //生成区间随机数 // int index = chooseRandomInt(serverCount); // server = upList.get(index); //从或者的服务中随机获取一个 /*============================================*/ if(total.get()<5){ server = upList.get(currentIndex.get()); getAndIncrement(total); }else{ total.set(0); getAndIncrement(currentIndex); if(currentIndex.get()>=upList.size()){ currentIndex.set(0); } 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 >= 2147483647 ? 0 : current + 1; }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容器即可.下面两种二选一
@Configuration public class MyRule { @Bean //使用自定义的 public IRule HcodeRule(){ return new HcodeRule(); } //============================================================ //AvailabilityFilteringRule : 先过滤掉出现故障的服务器,对剩下的服务进行轮询 //RoundRobinRule 轮询 默认设置 //RandomRule 随机 //WeightedResponseTimeRule 权重 //RetryRule:先按照轮询获取,若获取服务失败,则在指定时间内进行重试 //随机访问,只要将实现类注入到ICO容器,即可覆盖 @Bean //使用原有的实现类 public IRule myRule(){ return new RandomRule(); } } 主启动类上加上注解,让消费端服务能去使用自定义的负载均衡策略 @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
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.2.1.RELEASE</version> </dependency>使用eureka整合客户端pom就不用再导入单独的hystrix
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> 微服务提供者的controller层 @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 "┭┮﹏┭┮特定限制方法熔断器触发了,呜呜呜~"; } } 微服务提供者的主启动类加上开启断路器的注解 @EnableCircuitBreaker //添加对服务熔断的支持 客户端导入的所需依赖跟提供者差不多,使用openfeign进行服务调用通信。 <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
feign: hystrix: enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。然后再服务层接口加上注解。
@FeignClient(value = "hystrix-test-provider",fallback = DeptFallbackService.class) //服务名,备用的响应类 @Component public interface testService { @GetMapping("/global") public String test1(); }兜底用的备用响应类
@Component // 服务降级 public class DeptFallbackService implements testService{ public String test1() { return "┭┮﹏┭┮该服务被降级了,目前无法使用"; } }最后,主启动类添加@EnableHystrix
@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。
统一处理限流的备用方法类
public class CustomerBlockHandle { public static String deal_test(String p, BlockException blockException){ return "┭┮﹏┭┮被限流了"; } } 启动后,再sentinel控制台并没有发现该服务,但是nacos却已经发现该服务成功注册了,是因为需要发送一次请求,网页访问该服务,sentinel才能监控到(Sentinel采用的是懒加载)。