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 源码
组成接口
![image-20190713132523310](/Users/zhangpan/Library/Application Support/typora-user-images/image-20190713132523310.png)
内置负载均衡规则
![image-20190713133911384](/Users/zhangpan/Library/Application Support/typora-user-images/image-20190713133911384.png)
配置方式
- 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 # 规则类的全路径名称
- 对比
![image-20190713142916635](/Users/zhangpan/Library/Application Support/typora-user-images/image-20190713142916635.png)
- 最佳使用
- 尽量使用属性配置
- 在同一个微服务中尽量保持单一配置,不要混合使用,增加定位复杂性
Tip
在使用Ribbon的时候,配置class一定不能处于启动类的同级目录及其子目录,否则会导致父子上下文重叠问题,带来的结果就是,Ribbon规则会被配置称全局配置规则,从而被所有微服务应用。
![image-20190713141743025](/Users/zhangpan/Library/Application Support/typora-user-images/image-20190713141743025.png)
The
CustomConfiguration
class must be a@Configuration
class, but take care that it is not in a@ComponentScan
for 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
![image-20190713150041397](/Users/zhangpan/Library/Application Support/typora-user-images/image-20190713150041397.png)
@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做容错保护,这两者被作为基础工具类框架被广泛地应用在各个微服务的 ...
随机推荐
- Android零基础入门第5节:善用ADT Bundle,轻松邂逅女神
原文:Android零基础入门第5节:善用ADT Bundle,轻松邂逅女神 在前几期中总结分享了Android的前世今生.Android 系统架构和应用组件那些事.带你一起来聊一聊Android开发 ...
- mysql 更改root密码
mysql 更改root密码,有很多种,网上也有很多记录,这里只是做个记录,以后可以看看,只记录两种自己常用的方法. 1.改表法,登录到数据库,切换到:mysql数据库,update user set ...
- QT5.6,5.7,5.8的新特征以及展望(Qt5.7首次正式支持Qt3D,以前都是预览版)
https://wiki.qt.io/New_Features_in_Qt_5.6 (跨平台High-DPI,改进WebEngine到45,支持WIN 10,Canvas3D,3D) https:// ...
- http 报错码对应的错误原因
转:http://blog.csdn.net/cutbug/article/details/4024818 1xx - 信息提示这些状态代码表示临时的响应.客户端在收到常规响应之前,应准备接收一个或多 ...
- python爬虫之PyQuery
# -*- coding: UTF-8 -*- from pyquery import PyQuery as pq import re from datetime import datetime,ti ...
- 基于Google Earth Engine的全国地表温度反演
国内研究landsat8温度反演的人员很多,但是现有算法一般都是一景为例子,进行开展. 这有一个局限性,当研究的尺度很大时,就需要比较大的运算量了,例如全省温度,全国温度,全球温度,当然大家可能会说, ...
- 使用wireshark捕获SSL/TLS包并分析
原创博客,转载请注出处! TLS运作方式如下图:
- IM推送保障及网络优化详解(二):如何做长连接加推送组合方案
对于移动APP来说,IM功能正变得越来越重要,它能够创建起人与人之间的连接.社交类产品中,用户与用户之间的沟通可以产生出更好的用户粘性. 在复杂的 Android 生态环境下,多种因素都会造成消息推送 ...
- 攻防世界 web进阶练习 NewsCenter
攻防世界 web进阶练习 NewsCenter 题目是NewsCenter,没有提示信息.打开题目,有一处搜索框,搜索新闻.考虑xss或sql注入,随便输入一个abc,没有任何搜索结果,页面也没有 ...
- linux 下 设置 MySQL8 表名大小写不敏感方法,解决设置后无法启动 MySQL 服务的问题
在安装完成之后,初始化数据库之前,修改 my.cnf 打开mysql配置文件 vim /etc/my.cnf 在尾部追加一行 lower_case_table_names=1 并保存,然后再初始化数据 ...