Java 客户端负载均衡
- 客户端侧负载均衡
在下图中,负载均衡能力算法是由内容中心提供,内容中心相对于用户中心来说,是用户中心的客户端,所以又被称为客户端侧负载均衡
自定义实现Client Random负载均衡
- 获取所有的服务list
- 随机获取需要访问的服务信息
// 自定义客户端负载均衡能力
// 获取所有用户中心服务的实例列表
List<String> targetUris = instances.stream().map(i -> i.getUri().toString() + "/users/{id}").collect(Collectors.toList());
//获取随机实例
int i = ThreadLocalRandom.current().nextInt(targetUris.size());
//调用用户微服务 /users/{userId}
log.info("请求的目标地址:{}", targetUris.get(i));
ResponseEntity<UserDTO> userEntity = restTemplate.getForEntity(
targetUris.get(i),
UserDTO.class, userId
);
Ribbon
什么是Ribbon
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法。
Github: Ribbon 源码
组成接口

内置负载均衡规则

配置方式
- Java 代码配置
/**
* RibbonConfiguration for TODO
*
* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>
* @since 2019/7/13
*/
@Configuration
public class RibbonConfiguration {
@Bean
public IRule ribbonRule(){
return new RandomRule();
}
}
/*------------------------------------------------------------*/
/**
* UserCenterRibbonConfiguration for 自定义实现User-center service ribbon client
*
* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>
* @since 2019/7/13
*/
@Configuration
@RibbonClient(name = "user-center", configuration = RibbonConfiguration.class)
public class UserCenterRibbonConfiguration {
}
/*------------------------------------------------------------*/
@Configuration
//@RibbonClient(name = "user-center", configuration = RibbonConfiguration.class) //作用域为 user-center
@RibbonClients(defaultConfiguration = RibbonConfiguration.class) //作用域为全局
public class UserCenterRibbonConfiguration {
}
- 使用配置文件
user-center: # service name
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 规则类的全路径名称
- 对比

- 最佳使用
- 尽量使用属性配置
- 在同一个微服务中尽量保持单一配置,不要混合使用,增加定位复杂性
Tip
在使用Ribbon的时候,配置class一定不能处于启动类的同级目录及其子目录,否则会导致父子上下文重叠问题,带来的结果就是,Ribbon规则会被配置称全局配置规则,从而被所有微服务应用。

The
CustomConfigurationclass must be a@Configurationclass, but take care that it is not in a@ComponentScanfor the main application context. Otherwise, it is shared by all the@RibbonClients. If you use@ComponentScan(or@SpringBootApplication), you need to take steps to avoid it being included (for instance, you can put it in a separate, non-overlapping package or specify the packages to scan explicitly in the@ComponentScan).
Ribbon 饥饿加载
默认情况下,Ribbon是懒加载,在第一次请求的时候才会创建客户端。
ribbon:
eager-load:
enabled: true # 饥饿加载激活
clients: user-center,xxx,xxx # 为哪些clients开启
使用Ribbon 替代自定义实现
添加依赖(Spring-Cloud-Alibaba-Nacos-Discovery已经依赖了Ribbon,因此不需要额外依赖)
添加注解(只需要在RestTemplate IOC添加
@LoadBalance)/**
* 在Spring 容器中,创建一个对象,类型是{@link RestTemplate}
* 名称/ID 为 restTemplate
* <bean id ="restTemplate" class="XXX.RestTemplate" />
* {@link LoadBalanced} 为RestTemplate整合Ribbon调用
*
* @return restTemplate
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
添加配置,直接使用
ResponseEntity<UserDTO> userEntity = restTemplate.getForEntity(
"http://user-center/users/{userId}",
UserDTO.class, userId
);
扩展Ribbon - 支持Nacos权重
- 实现接口
com.netflix.loadbalancer.IRule - 实现抽象类
com.netflix.loadbalancer.AbstractLoadBalancerRule

@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class NacosWeightRule4Ribbon extends AbstractLoadBalancerRule {
private final NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// 读取配置文件,并初始化 NacosWeightRule4Ribbon
}
@Override
public Server choose(Object key) {
try {
// ILoadBalancer 是Ribbon的入口,基本上我们想要的元素都可以在这个对象中找到
BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
log.info("NacosWeightRule4Ribbon lb = {}", loadBalancer);
// 想要请求的微服务名称
String name = loadBalancer.getName();
// 实现负载均衡算法
// 可得到服务发现相关的API(nacos内部实现)
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
// nacos client 通过基于权重的负载均衡算法,选择一个实例
Instance instance = namingService.selectOneHealthyInstance(name);
log.info("port = {}, weight = {}, instance = {}", instance.getPort(), instance.getWeight(), instance);
return new NacosServer(instance);
} catch (NacosException e) {
log.error("NacosWeightRule4Ribbon {}", e.getMessage());
}
return null;
}
}
@Configuration
@RibbonClients(defaultConfiguration = NacosWeightRule4Ribbon.class) //全局配置
public class UserCenterRibbonConfiguration {
}
拓展Ribbon - 同集群优先
public Server choose(Object key) {
try {
// 获取到配置文件中的集群名称 BJ
String clusterName = nacosDiscoveryProperties.getClusterName();
BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
String serviceName = loadBalancer.getName();
//获取服务发现的相关API
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
// 1. 找到指定服务的所有实例 A
List<Instance> instances = namingService.selectInstances(serviceName, true);
// 2. 过滤出相同集群下的所有实例 B
List<Instance> sameClusterInstances = instances.stream()
.filter(instance -> Objects.equals(instance.getClusterName(), clusterName))
.collect(Collectors.toList());
// 3. 如果B为空,则使用 A
List<Instance> instancesChoosen = new ArrayList<>();
if (CollectionUtils.isEmpty(sameClusterInstances)) {
instancesChoosen = instances;
log.warn("发生跨集群调用,name = {},clusterName = {}", serviceName, clusterName);
} else {
instancesChoosen = sameClusterInstances;
}
// 4. 基于权重的负载均衡算法,返回一个实例 A
Instance instance = ExtendBalancer.getHostByRandomWeightOverride(instancesChoosen);
log.info("choose instance is : port = {}, instance = {}", instance.getPort(), instance);
return new NacosServer(instance);
} catch (NacosException e) {
e.printStackTrace();
log.error(e.getErrMsg());
}
return null;
}
/**
* 调用Nacos内部方法,进行一次包装
*/
class ExtendBalancer extends Balancer {
public static Instance getHostByRandomWeightOverride(List<Instance> hosts) {
return getHostByRandomWeight(hosts);
}
}
扩展Ribbon - 基于元数据的版本控制
Java 客户端负载均衡的更多相关文章
- 笔记:Spring Cloud Ribbon 客户端负载均衡
Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,基于 Netflix Ribbon 实现,通过Spring Cloud 的封装,可以让我们轻松的将面向服 ...
- 基于Spring cloud Ribbon和Eureka实现客户端负载均衡
前言 本案例将基于Spring cloud Ribbon和Eureka实现客户端负载均衡,其中Ribbon用于实现客户端负载均衡,Eureka主要是用于服务注册及发现: 传统的服务端负载均衡 常见的服 ...
- Spring Cloud 2-Ribbon 客户端负载均衡(二)
Spring Cloud Eureka 1.Hello-Service服务端配置 pom.xml application.yml 启动两个service 2.Ribbon客户端配置 pom.xml ...
- spring cloud 使用ribbon简单处理客户端负载均衡
假如我们的multiple服务的访问量剧增,用一个服务已经无法承载, 我们可以把Hello World服务做成一个集群. 很简单,我们只需要复制Hello world服务,同时将原来的端口8762修改 ...
- 第四章 客户端负载均衡:Spring Cloud Ribbon
spring cloud ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于Netflix Ribbon 实现.通过Spring Cloud 的封装,可以轻松的将面向服务的R ...
- Spring Cloud Ribbon——客户端负载均衡
一.负载均衡负载均衡(Load Balance): 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性.其意思 ...
- 【SpringCloud微服务实战学习系列】客户端负载均衡Spring Cloud Ribbon
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现.通过Spring Cloud的封装,可以让我们轻松地将面向服务的RES模板 ...
- 【Dalston】【第二章】客户端负载均衡(Ribbon)
对于大型应用系统负载均衡(LB:Load Balancing)是首要被解决一个问题.在微服务之前LB方案主要是集中式负载均衡方案,在服务消费者和服务提供者之间又一个独立的LB,LB通常是专门的硬件,如 ...
- 客户端负载均衡Feign之一:申明式服务调用Feign入门示例
Spring Cloud提供了Ribbon和Feign作为客户端的负载均衡. 前面使用了Ribbon做客户端负载均衡,使用Hystrix做容错保护,这两者被作为基础工具类框架被广泛地应用在各个微服务的 ...
随机推荐
- SignalR---DOTNET客户端
原文:SignalR---DOTNET客户端 这里面有用到异步的相关知识,本人前几篇文章也简单的提到. SignalR客户端要寄宿在.NET的客户端,必须安装Microsoft.AspNet.Sign ...
- Oracle 存储过程创建及调用
--------创建存储过程------- create or replace procedure TestSPas begin update table_name set CREATE_TIMEST ...
- LINUX基础内容
在Linux中,有三种基本的文件类型: 1) 普通文件 普通文件是以字节为单位的数据流,包括文本文件.源码文件.可执行文件等.文本和二进制对Linux来说并无区别,对普通文件的解释由处理该文件的应用程 ...
- 开启Qt Lite Project
发布: http://blog.qt.io/blog/2017/01/23/qt-5-8-released/ 说法一:Qt Lite” is not a tool, but a concept tha ...
- 使用MSYS2环境中编译Qt5.5.0的补丁
Qt的configure脚本对MinGW静态编译支持不太完善,总有这样那样的问题.如果你不嫌麻烦,而且可以接受高版本的Qt的话,可以考虑使用我做的补丁在MSYS2环境中编译.Qt5.4.2的补丁 Qt ...
- 判断当前进程是否以管理员权限运行(AllocateAndInitializeSid后,用CheckTokenMembership与AdministratorsGroup进行比较,和Delphi的那个例子还有点不一样)
在Win7下(Vista以上的...)有时某些操作就是会让人郁闷 开启了UAC的话,得以管理员权限运行才不会出现Access is denied... 但是,程序又不是非得什么时候都用那破管理员权限的 ...
- Struts2 学习笔记(概述)
Struts2 学习笔记 2015年3月7日11:02:55 MVC思想 Strust2的MVC对应关系如下: 在MVC三个模块当中,struts2对应关系如下: Model: 负责封装应用的状态,并 ...
- Maven依赖范围<scope>
1.Maven因为执行一系列编译.测试和部署运行等操作,在不同的操作下使用的classpath不同,依赖范围就是用来控制依赖与三种 classpath(编译classpath.测试classpath. ...
- python实现常用查找算法
http://www.cnblogs.com/feixuelove1009/p/6148357.html
- Linux系统下解锁Oracle的Scott用户
1).在Oracle用户下面输入命令:lsnrctl status查看监听是否开启,如果未开启则需要开启监听,输入命令:lsnrctl start; 2).如果没有设置监听的话需要先建立一个监听,然后 ...