3.1 Ribbon概述
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端(80)负载均衡的工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。
3.2 Riboon能干什么
实现服务的负载均衡:将用户的请求平摊的分配到多个服务器上,从而达到系统的HA(高可用)!
3.3 Ribbon本地负载均衡客户端(进程式) VS Nginx服务端(集中式)负载均衡区别?
Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求。即负载均衡是由服务端实现的。
Ribon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到VM本地,从而在本地实现RPC远程服务调用技术。
Ribbon:负载均衡 + RestTemplate 实现调用
3.4 Ribbon使用基本步骤
step1:先选择EurekaServer ,它优先选择在同一个区域内负载较少的server.
step2:再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址,其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。
3.5 Ribbon使用方法的区别
getForObject / getForEntity、postForObject / postForEntity
Object 和Entity 的区别:
Object 返回对象为响应体中数据转化称的对象,基本可以理解为json或者entity的.getBody()方法
Entity 返回对象为ResponseEntity对象,包含了响应中的一些重要信息,比如响应头(getHeaders()),响应状态码(getStatusCode()),响应体(getBody())
响应状态码(statusCode) 包含了 is1xx情报,is2xx成功,is3xx重定向,is4xx客户端,is5xx服务端,isError(4xxor5xx) 六个返回状态码的boolean类型以供判断
3.6 Ribbon负载均衡策略的算法
3.6.1 IRuler接口下的负载均衡策略:
3.6.2 如何替换Ribbon负载均衡策略:
1、自定义配置类,将默认轮询的规则修改为随机负载均衡
2、在主启动类上添加注解,实现注入@RibbonClient(name = “CLOUD-PAYMENT-SERVICE”,configuration = ConsumerConfig.class)
@Bean// 实现负载均衡算法的替换:将默认的轮询替换为随机randompublic IRule iRule(){return new RandomRule();}
3.7 Ribbon负载均衡算法的原理
★3.7.1 基本原理(默认规则轮询负载的基本原理)
rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始。
List
例如,当前共有8001、8002两个服务器,集群总数量为2。
第一次发送请求:1%2=1 ,index=1, instances (1) 访问下标为1的服务器位置
第二次发送请求:2%2=0,index=0,instances (0) 访问下标为0的服务器位置
第三次发送请求:3%2=1,index=1,访问下标为1的服务器位置
……
……
开始 1、0、1、0轮询
3.7.2 底层源码
step1:负载均衡开启 lb!=null;
step2: 得到服务端集群总数量 allServers
step3:调用incrementAndGetModulo() 方法,获得下一个要访问的服务器端位置的下标索引nextServerIndex。
自旋锁+CAS(Compare and set)的知识
step4: 根据下标索引,得到需要访问的服务器
3.7.3 自定义Ribbon负载均衡算法
Step1: 自定义LoadBlancer接口,初始化,得到所有的服务器集群的列表;
Step2:自定义lb实现类实现LoadBlancer接口;
Step3:创建instances( )方法,获得当前需要访问的服务器的下标;
仿照轮询的底层原理,利用自旋锁+CAS ,获得当前的 rest接口第几次请求数getAndIncrement()
public class Mylb implements LoadBalanced {private AtomicInteger nextServerCyclicCounter;public Mylb(){this.nextServerCyclicCounter=new AtomicInteger(0);}/*** 获得当前服务器位置的下标* @param serviceInstance* @return*/@Overridepublic ServiceInstance instance(List<ServiceInstance> serviceInstance) {//获得服务器的总数量int AllService = serviceInstance.size();//利用CAS和自旋锁获得当前的请求次数int current=getAndIncrement();int index=current%AllService;return serviceInstance.get(index);}private int getAndIncrement() {int current;int next;do {current=this.nextServerCyclicCounter.get();next=current>Integer.MAX_VALUE?0:current+1;}while (!this.nextServerCyclicCounter.compareAndSet(current,next));log.info("********当前为第几次访问:"+next);return next;}}
