1.ribbon是什么?
1.1 两种负载均衡方案{
集中:即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,软件 F5,nginx)
由该设施负责把访问请求通过某种策略转发至服务的提供方(服务端负载均衡)
集成到服务中:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器(客户端负载均衡)
}
1.2 ribbon简介
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
2.ribbon如何应用到spirngCloud项目中?
1.配置jar,需要在父项目gradle.build中引入负载均衡和springCloud的整合jar
2.我们只需要修改配置文件就可以实现ribbon组件的应用了(如果不配置他会使用默认的配置)
(1)配置方式,对所有的微服务起作用.(配置自己的yml文件)
点击进入naocs–>进入配置管理–>选择xscyl-dev空间–>进入xscyl-common.yml给所有的项目添加配置.
(2)对单独的微服务起作用.
点击进入nacos–>进入配置管理–>选择xscyl-dev空间–>进入xscy-product.yml
3.我们启动一个gateWay作为负载均衡消费者,启动两个用户实例去负载访问用户服务者
至此我们可以确认ribbon已经去到默认作用了,所以我们可以进行详细的配置了.
3.ribbon组件/配置重要参数讲解?
3.1riibbon的组件(重要接口)
IRule–>NFLoadBalancerRuleClassName: Should implement IRule(负载均衡算法)
功能:根据特定算法中从服务列表中选取一个要访问的服务 常用IRule实现有以下几种:
RoundRobinRule
轮询规则,默认规则。同时也是更高级rules的回退策略
AvailabilityFilteringRule
这个负载均衡器规则,会先过滤掉以下服务:
a. 由于多次访问故障而处于断路器跳闸状态,并发的连接数量超过阈值
然后对剩余的服务列表按照RoundRobinRule策略进行访问
WeightedResponseTimeRule
根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越重、被选中的概率越高。刚启动时,如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换到WeightedResponseTimeRule。
RetryRule
先按照RoundRobinRule的策略获取服务,如果获取服务失败,则在指定时间内会进行重试,获取可用的服务
BestAvailableRule
此负载均衡器会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
RandomRule:随机策略
ServerListUpdater
功能:被DynamicServerListLoadBalancer用于动态的更新服务列表。 常用的实现类:
PollingServerListUpdater–>?有问题
默认的实现策略。此对象会启动一个定时线程池,定时执行更新策略
IClientConfig 功能:定义各种配置信息,用来初始化ribbon客户端和负载均衡器 DefaultClientConfigImpl
IPing(暂不介绍)—>NFLoadBalancerPingClassName: Should implement IPing(服务可用性检查)
功能在后台运行的一个组件,用于检查服务列表是否都活 NIWSDiscoveryPing,不执行真正的ping。如果Discovery Client认为是在线,则程序认为本次心跳成功,服务活着 ,PingUrl 此组件会使用HttpClient调用服务的一个URL,如果调用成功,则认为本次心跳成功,表示此服务活着。
NoOpPing ,永远返回true,即认为服务永远活着,DummyPing 默认实现,默认返回true,即认为服务永远活着
ServerList(暂不介绍),—>NIWSServerListClassName: Should implement ServerList(服务列表获取)
功能:存储服务列表。分为静态和动态。如果是动态的,后台有个线程会定时刷新和过滤服务列表,常用ServerList 实现有以下几种:
ConfigurationBasedServerList
DomainExtractingServerList
代理类,根据ServerList的值实现具体的逻辑
ServerListFilter(暂不介绍)—>NIWSServerListFilterClassName: Should implement ServerListFilter(服务列表的过滤)
该接口允许过滤配置或动态获取的具有所需特性的服务器列表。ServerListFilter是DynamicServerListLoadBalancer用于过滤从ServerList实现返回的服务器的组件。
常用ServerListFilter 实现有以下几种:
ZoneAffinityServerListFilter(暂不介绍)
过滤掉所有的不和客户端在相同zone的服务,如果和客户端相同的zone不存在,才不过滤不同zone有服务。
启用此配置使用以下配置
.ribbon.EnableZoneAffinity=true
ZonePreferenceServerListFilter
ZoneAffinityServerListFilter的子类。和ZoneAffinityServerListFilter相似,但是比较的zone是发布环境里面的zone。过滤掉所有和客户端环境里的配置的zone的不同的服务,如果和客户端相同的zone不存在,才不进行过滤。
ServerListSubsetFilter
ZoneAffinityServerListFilter的子类。此过滤器确保客户端仅看到由ServerList实现返回的整个服务器的固定子集。 它还可以定期用新服务器替代可用性差的子集中的服务器。
3.2riibbon的重要参数(负载均衡功能和超时重试功能参数)
公共配置
独自配置
重试次数:MaxAutoRetries + MaxAutoRetriesNextServer + (MaxAutoRetries * MaxAutoRetriesNextServer )
同时配置采用的是***就近原则***
4.ribbon集成nacos遇到的问题?
4.1***超时访问问题***?
因为Ribbon进行客户端负载均衡的Client并不是在服务启动的时候就初始化好的,而是在调用的时候才会去创建相应的Client>导致访问服务的.
解决方案:
1.访问超时解决方案添加参数配置:
懒加载,启动时创建
Ribbon:
eager-load:
clients: 需要访问的服务名
enabled: true
4.1***ribbon不能实时的感知服务下线情况***?
因为我们更新ribbon本地缓存的服务列表默认是通过定时任务轮训来实现的,默认时时间是30秒轮训一次?导致服务下线并不能立刻感知.
解决方案:
1.方案一: 缩小定时刷新的时间(只要要时间间隔就无法实时感知,并且耗费服务器资源)
.ribbon.ServerListRefreshInterval:服务列表刷新频率基于定时任务拉取默认30s
ribbon:
ServerListRefreshInterval: 2000 全局配置(两秒)
2.方案二:方案二:注册监听器–监听nacos服务列表的变化,实时更新(问题网络震荡出现不会更新的情况){
参考类:com.netflix.loadbalancer.EurekaNotificationServerListUpdater的实现
3.方案3:两者结合即使用监听器同时有使用轮询的方式核心代码如下.{
/**
* 以定时任务的方式进行服务列表的更新
*/
@Override
public synchronized void start(final UpdateAction updateAction) {
if (isActive.compareAndSet(false, true)) {
final Runnable wrapperRunnable = new Runnable() {
@Override
public void run() {
if (!isActive.get()) {
if (scheduledFuture != null) {
scheduledFuture.cancel(true);
}
return;
}
try {
updateAction.doUpdate();
lastUpdated = System.currentTimeMillis();
} catch (Exception e) {
logger.warn(“Failed one update cycle”, e);
}
}
};
//
try {
// 如果并发执行也没有问题
for (String serviceName : serviceNames) {
naming.subscribe(serviceName, new EventListener() {
@Override
public void onEvent(Event event) {
System.out.println("%%%%%%%%%%");
getRefreshExecutor().execute(wrapperRunnable);
}
});
}
} catch (Exception e) {
logger.warn(“Failed one update cycle”, e);
}
scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
wrapperRunnable,
// 1秒
initialDelayMs,
// 30秒
refreshIntervalMs,
TimeUnit.MILLISECONDS
);
} else {
logger.info(“Already active, no-op”);
}
}
}
5.ribbion原理简单理解?
5.1 ribbon选择实例图解?
5.2 LoadBalancer 选择服务实例的流程
1.通过ServerList获取当前可用的服务实例列表;
2.通过ServerListFilter将步骤1 得到的服务列表进行一次过滤,
返回满足过滤器条件的服务实例列表;
3.应用Rule规则,结合服务实例的统计信息(连续连接失败计数,连接时间等),返回满足规则的
某一个服务实例;
4.ribbon会当LoadBalancer在选择合适的Server提供给应用后,应用会向该Server发送服务请求,则在请求的过程中,应用会根据请求的相应时间或者网络连接情况等进行统计;当应用后续从LoadBalancer选择合适的Server时,LoadBalancer 会根据每个服务的统计信息,结合Rule来判定哪个服务是最合适的
4.1补充–>(例如发生了当有某个服务存在多个实例时,在请求的过程中,负载均衡器会统计每次请求的情况(请求相应时间,是否发生网络异常等),当出现了请求出现累计重试时,负载均衡器会标识当前服务实例,设置当前服务实例的断路的时间区间,在此区间内,当请求过来时,负载均衡器会将此服务实例从可用服务实例列表中暂时剔除,优先选择其他服务实例)