微服务 springcloud Ribbon客户端负载均衡
微服务 springcloud Ribbon客户端负载均衡
- 微服务 springcloud Ribbon客户端负载均衡
- 一、概述
- 1、Ribbon是什么
- 2、Ribbon作用
- 3、Ribbon与nginx负载均衡原理
- 4、Ribbon工作模式
- 5、引入依赖坐标
- 二、Ribbon核心组件IRule
- 1、IRule:根据特定算法从服务列表中选取一个要访问的服务
- 三、Ribbon修改访问策略
- 1、Ribbon配置注意事项
- 2、新建配置类
- 3、指定配置
- 三、Ribbon负载均衡算法
- 1、原理
- 2、RoundRobinRule源码
- 3、重写负载均衡算法
微服务 springcloud Ribbon客户端负载均衡
一、概述
1、Ribbon是什么
SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡组件。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端负载均衡算法和服务调用的组件。
Ribbon客户端组件提供一系列完善的配置如连接超时,重试等简单地说就是在配置文件中列出LoadBalancer后面所以的机器,Ribbon会自动的帮助你基于某种规则(如简单轮训,随机连接等)去连接这些机器。而且我们很容易使用Ribbon实现自定义的负载均衡算法。
在实际使用中,Ribbon实质就是在客户端实现负载均衡,通过RestTemplate实现远程调用。
官网地址:https://github.com/Netflix/ribbon/wiki/Getting-Started
目前进入维护模式,未来SpringCloud LoadBalancer替代。
2、Ribbon作用
Ribbon=负载均衡+RestTemplate调用
3、Ribbon与nginx负载均衡原理
nginx负载原理Ribbon负载原理
4、Ribbon工作模式
5、引入依赖坐标
新版的Eureka已经整合了Ribbon
二、Ribbon核心组件IRule
1、IRule:根据特定算法从服务列表中选取一个要访问的服务
三、Ribbon修改访问策略
Ribbon默认轮训机制,那么如何修改默认访问机制?由于Ribbon是客户端负载所以需要配置客户端。
1、Ribbon配置注意事项
官方文档明确给出警告:
这个自定义配置类不能放在@ComponentScan所扫描的当前包下及其子包下。
否则我们自定义的这个配置类就会被所以的Ribbon客户端所共享,达不到特殊化定制的目的。
注意:在springboot中@ComponentScan可以扫描到的包默认是主程序Application.java类所在包及其子包。
2、新建配置类
git地址:https://github.com/zrj-coder/cloudboot3
/** * 配置ribbon策略 * 注意:不要放在主程序所在宝及其子包等能被ComponentScan扫描到的包下面 * * @author zrj * @date 2021/1/23 * @since V1.0 **/
@Configuration
public class MySelfRule {
/** * 定义为随机 */
@Bean
public IRule myRule() {
return new RandomRule();
}
}
3、指定配置
/** * 订单主程序 * 指定Ribbon配置类 * * @author zrj * @date 2021/1/23 * @since V1.0 **/
@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run( OrderApplication.class, args );
}
}
三、Ribbon负载均衡算法
1、原理
负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 =实际调用服务器位置小标。
每次服务器重启后rest接口技术从1开始。
2、RoundRobinRule源码
idea生成的IRule的UML类图,具体方式参考:idea Diagrams生成UML类图负载均衡算法源码分析
/** * 负载均衡调用算法 * The most well known and basic load balancing strategy, i.e. Round Robin Rule. * * @author stonse * @author Nikos Michalakis <nikos@netflix.com> * */
public class RoundRobinRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter; // 服务器调用次数,默认是0
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() { // 服务器调用次数,默认是0
nextServerCyclicCounter = new AtomicInteger(0);
}
public RoundRobinRule(ILoadBalancer lb) {
this();
setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
while (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
// 所有服务集合
List<Server> allServers = lb.getAllServers();
// 缓存本地服务器数量
int upCount = reachableServers.size();
// 获取当前服务器数量
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
// 负载均衡具体调用算法
int nextServerIndex = incrementAndGetModulo(serverCount);
server = allServers.get(nextServerIndex);
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
/** * 负载均衡具体调用算法 * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}. * * @param modulo The modulo to bound the value of the counter. * 调用次数 * * @return The next value. * 下一次调用服务器下标 */
private int incrementAndGetModulo(int modulo) {
for (;;) {
// 获得当前调用算法
int current = nextServerCyclicCounter.get();
// 当前调用次数加1 取余 服务器数量
int next = (current + 1) % modulo;
// CAS 自旋 返回
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
3、重写负载均衡算法
/** * 自定义负载均衡算法 * * @author zrj * @date 2021/1/31 * @since V1.0 **/
public interface LoadBalancer {
/** * 服务实例 * * @param serviceInstances * @return */
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
/** * 自定义负载均衡算法 * * @author zrj * @date 2021/1/31 * @since V1.0 **/
@Component
public class NewLoadBalancer implements LoadBalancer {
private AtomicInteger atomicInteger = new AtomicInteger( 0 );
/** * 自定义负载均衡算法 * * @return */
public 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 ));
System.out.println( "*****第几次访问,次数next: " + next );
return next;
}
/** * 负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 * 每次服务重启动后rest接口计数从1开始。 * * @param serviceInstances * @return */
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get( index );
}
}
还没有评论,来说两句吧...