|com.netflix.loadbalancer.RoundRobinRule|默认规则,轮询|
Feign和OpenFeign集成了Ribbon默认具有负载均衡的能力
客户端负载均衡;
使用什么“负载均衡算法”去负载“一个服务的多个实例”
一个服务可以有多个实例,进而负载均衡
负载均衡:将请求合理分配到多个服务上,实现系统的高可用
IRule接口下多种负载均衡算法
| 算法类 | 介绍 |
|---|---|
| com.netflix.loadbalancer.RoundRobinRule | 默认规则,轮询 |
| com.netflix.loadbalancer.ZoneAvoidanceRule | 区域内的服务性能 |
| com.netflix.loadbalancer.NacosRule | 同集群中挑选服务实例进行负载均衡 |
| com.netflix.loadbalancer.RandomRule | 随机 |
| com.netflix.loadbalancer.RetryRule | 重试,先RoundRobinRule再RetryRule |
| com.netflix.loadbalancer.WeightedResponseTimeRule | 响应时间 |
| com.netflix.loadbalancer.BestAvailableRule | 最可用,先过滤故障服务,再选择并发量最小的 |
| com.netflix.loadbalancer.AvailableFilteringRule | 先过滤故障服务,再选择并发量较小的 |
|com.netflix.loadbalancer.RoundRobinRule|默认规则,轮询|
pom.xml
Feign集成了ribbon
application.yaml
main
package com.xcrj.springcloud;
import com.xcrj.rule.MyRuleConfiguration ;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
代码
package com.xcrj.springcloud.rule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRuleConfiguration {
@Bean
public IRule myRule() {
return new RandomRule();
}
}
package com.xcrj.springcloud.configuration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppContextConfiguration {
@Bean
// 因为restTemplate没有负载均衡的能力,所以加这个注解让restTemplate具有负载均衡的能力。因为Feign和OpenFeign具有负载均衡的能力,所以不用这个注解
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
使用/部分服务更换默认负载均衡规则
com.netflix.loadbalancer.ZoneAvoidanceRule是默认规则,区域内的服务性能
pom.xml
Feign集成了ribbon
application.yaml
main
package com.xcrj.springcloud;
import com.xcrj.rule.MyRuleConfiguration ;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
// 针对PAYMENT-SERVICE服务的实例采取MyRuleConfiguration配置的负载均衡规则
// @RibbonClients多个
@RibbonClient(name = "PAYMENT-SERVICE", configuration = MyRuleConfiguration .class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
代码
// 因为仅仅针对PAYMENT-SERVICE服务实例定制化负载均衡规则,所以MyRuleConfiguration 不能在启动类所在包下,否则所有服务的实例都将使用这个定制的负载均衡规则
package com.xcrj.rule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRuleConfiguration {
@Bean
public IRule myRule() {
return new RandomRule();
}
}
package com.xcrj.springcloud.configuration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppContextConfiguration {
@Bean
// 因为restTemplate没有负载均衡的能力,所以加这个注解让restTemplate具有负载均衡的能力。因为Feign和OpenFeign具有负载均衡的能力,所以不用这个注解
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
使用/自定义负载均衡器
pom.xml
Feign集成了ribbon
application.yaml
main
package com.xcrj.springcloud;
import com.xcrj.rule.MyRuleConfiguration ;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
package com.xcrj.springcloud.configuration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppContextConfiguration {
@Bean
// 因为restTemplate没有负载均衡的能力,所以加这个注解让restTemplate具有负载均衡的能力。因为Feign和OpenFeign具有负载均衡的能力,所以不用这个注解
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
MyLoadBalancer
package com.xcrj.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MyLoadBalancer {
@Resource
private DiscoveryClient discoveryClient;
private AtomicInteger atomicInteger = new AtomicInteger(0);
private final int getAndIncrement() {
int current;
int next;
do {
current = this.atomicInteger.get();
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
} while (!this.atomicInteger.compareAndSet(current, next));
return next;
}
public ServiceInstance instances(String appName) {
// discoveryClient获取服务实例
List instances = discoveryClient.getInstances(appName);
// 无可用服务实例 直接返回
if (CollectionUtils.isEmpty(instances)) {
return null;
}
// 获取将要访问的服务下标
int index = getAndIncrement() % instances.size();
// 从list中获取将要访问的服务
return instances.get(index);
}
}
package com.xcrj.springcloud.controller;
import com.xcrj.springcloud.lb.MyLoadBalancer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URI;
@RestController
@Slf4j
public class OrderController {
private static final String PAYMENT_URL = "http://PAYMENT-SERVICE";
@Resource
private RestTemplate restTemplate;
@Resource
private MyLoadBalancer myLoadBalancer;
@GetMapping(value = "/consumer/payment/mylb")
public String getPaymentLB() {
// 使用自定义负载均衡器决定调用的服务实例
ServiceInstance instance = myLoadBalancer.instances("PAYMENT-SERVICE");
// 获取服务实例的uri
URI uri = instance.getUri();
return restTemplate.getForObject(uri + "/payment/lb", String.class);
}
}
源码
com.netflix.loadbalancer.RoundRobinRule轮询
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.netflix.loadbalancer;
import com.netflix.client.config.IClientConfig;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RoundRobinRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter;
private static final boolean AVAILABLE_ONLY_SERVERS = true;
private static final boolean ALL_SERVERS = false;
private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
public RoundRobinRule() {
this.nextServerCyclicCounter = new AtomicInteger(0);
}
public RoundRobinRule(ILoadBalancer lb) {
this();
this.setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
while(true) {
if (server == null && count++ < 10) {
List reachableServers = lb.getReachableServers();
// allServers list存储了所有的服务
List allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
// 服务实例的索引,线程安全的+1
int nextServerIndex = this.incrementAndGetModulo(serverCount);
// allServers list中根据索引获取访问的服务实例
server = (Server)allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
private int incrementAndGetModulo(int modulo) {
int current;
int next;
do {
current = this.nextServerCyclicCounter.get();
next = (current + 1) % modulo;
} while(!this.nextServerCyclicCounter.compareAndSet(current, next));
return next;
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
暑期编程PK赛
得CSDN机械键盘等精美礼品!


