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做容错保护,这两者被作为基础工具类框架被广泛地应用在各个微服务的 ...
随机推荐
- Linux命令执行顺序与管道命令
命令执行顺序控制 顺序执行多条命令:command1;command2;command3... 有选择执行命令:which command1 && command2 || comman ...
- 漫步Facebook开源C++库Folly之string类设计(散列、字符串、向量、内存分配、位处理等,小部分是对现有标准库和Boost库功能上的补充,大部分都是基于性能的需求而“重新制造轮子”)
就在近日,Facebook宣布开源了内部使用的C++底层库,总称folly,包括散列.字符串.向量.内存分配.位处理等,以满足大规模高性能的需求. 这里是folly的github地址:https:// ...
- 记录一次PHP项目报502的问题
问题描述 最近有台服务器偶尔会报502错误,虽然量不多,每天就几十个,但是也必须得找到原因,避免让小问题变成大问题. 排查过程 502错误的原因,一般是对用户访问请求的响应超时造成的,一开始以为是请求 ...
- C++界面库(十几种,很全)
刚开始用C++做界面的时候,根本不知道怎么用简陋的MFC控件做出比较美观的界面,后来就开始逐渐接触到BCG Xtreme ToolkitPro v15.0.1,Skin++,等界面库,以及一些网友自 ...
- 三个臭皮匠,顶上一个诸葛亮——在Google Ideathon上Design Thinking分享
4月26日很荣幸的被邀请参加Google Ideathon做Design Thinking的分享. 这次主要分享了Design Thinking的基本方法流程,以及在真实项目的运用.现在整理一下当时选 ...
- MYSQL的全局变量和会话变量
系统变量又分为全局变量与会话变量. 全局变量在MYSQL启动的时候由服务器自动将它们初始化为默认值,这些默认值可以通过更改my.ini这个文件来更改. 会话变量在每次建立一个新的连接的时候,由MYSQ ...
- 深入理解计算机系统 BombLab 实验报告
又快有一个月没写博客了,最近在看<深入理解计算机系统>这本书,目前看完了第三章,看完这章,对程序的机器级表示算是有了一个入门,也对 C 语言里函数栈帧有了一个初步的理解. 为了加深对书本内 ...
- 编写loadrunner的ftp脚本(详细步骤)
大家好,主要给大家讲解编写loadrunner的ftp脚本详细步骤,及FTP函数注释,及FTP脚本两种编写方式,手动和录制.亲测 No problem!^_^ 1.首先要了解loadrunner中几个 ...
- C++标准库(体系结构与内核分析)(侯捷第二讲)
一.OOP和GP的区别(video7) OOP:面向对象编程(Object-Oriented programming) GP:泛化编程(Generic programming) 对于OOP来说,我们要 ...
- memcached--add使用
memcached是一种管理内存的软件,来动态的分配机器的内存,将需要存储的数据以key-value(键值对)的形式存储在内存中. 1.memcached使用的存储算法是hash算法在内存中存储字符串 ...