ribbon
- ribbon concept
- ribbon核心组件IRule
- 模仿源码重写轮询
ribbon concept
spring cloud ribbon 是基于Netflix ribbon实现的一套客户端负载均衡的工具。
简单的说, Ribbon是Netflix发布的开源项目, 主要功能是提供客户端的软件负载均衡算法和服务
完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer (简称LB), 助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。
目前进入维护模式,替代品:spring cloud loadBalance.
restTemplate api
https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html
getObject, getEntity
postObject, postEntity
负载均衡
LB负载均衡(Load Balance)是什么
简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高可用)。
常见的负载均衡有软件Nginx, LVS,硬件F5等。
Ribbon本地负载均衡客户端VS Nginx服务端负载均衡区别
Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求。即负载均衡是由服务端实现的。
Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。
负载均衡+RestTemplate调用。
ribbon核心组件IRule
ribbon客户端负载均衡接口及实现类
接口以及子类
算法实现
替换默认的轮询算法, 使用随机
package top.bitqian.rule; // 不要同mainBoot一个目录import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 自定义ribbon 负载均衡规则代替默认轮询规则* @author echo lovely* @date 2020/12/6 17:34*/@Configuration
public class SelfRule {@Beanpublic IRule getIRule() {// 随机return new RandomRule();}}
然后主启动类添加@RibbonClient注解。
模仿源码重写轮询
负载均衡算法原理: rest接口的第几次请求数%服务器集群总数量 = 实际服务调用服务器的下标。
每次重启服务后,rest接口从1开始。
接口
package top.bitqian.springcloud.lb;import org.springframework.cloud.client.ServiceInstance;import java.util.List;/*** 负载均衡 接口--> 轮询~*/
public interface LoadBalance {/*** 根据可用的服务实例列表 轮询获取某个实例~* @param serviceInstanceList 可用服务实例列表* @return 轮询后的某个服务实例~*/ServiceInstance getInstance(List<ServiceInstance> serviceInstanceList);}
实现
package top.bitqian.springcloud.lb.impl;import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import top.bitqian.springcloud.lb.LoadBalance;import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;/*** 仿照源码写轮询算法* @author echo lovely* @date 2020/12/8 20:37*/@Component
public class MyLoadBalance implements LoadBalance {// init 0private final AtomicInteger atomicInteger = new AtomicInteger(0);public final int getAndIncrease() {int current;int next;do {current = this.atomicInteger.get();next = current >= 2147483647 ? 0 : current + 1;} while (!this.atomicInteger.compareAndSet(current, next)); // 期望值,修改值System.out.println("the next value -----> " + next);return next;}@Overridepublic ServiceInstance getInstance(List<ServiceInstance> serviceInstanceList) { // 机器列表// 得到服务器的下标位置int index = getAndIncrease() % serviceInstanceList.size();return serviceInstanceList.get(index);}
}
controller
// 测试手写的轮询算法~@GetMapping("/consumer/payment/lb")public String getPaymentByLb() {// 根据服务名获取服务列表List<ServiceInstance> serviceInstanceList =discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");// 1 2, 1 2, 1 2, 获取服务~ServiceInstance instance = myLb.getInstance(serviceInstanceList);URI uri = instance.getUri();return restTemplate.getForObject(uri + "/payment/lb", String.class);}