• 客户端侧负载均衡

在下图中,负载均衡能力算法是由内容中心提供,内容中心相对于用户中心来说,是用户中心的客户端,所以又被称为客户端侧负载均衡

自定义实现Client Random负载均衡

  1. 获取所有的服务list
  2. 随机获取需要访问的服务信息
				// 自定义客户端负载均衡能力
// 获取所有用户中心服务的实例列表
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 替代自定义实现

  1. 添加依赖(Spring-Cloud-Alibaba-Nacos-Discovery已经依赖了Ribbon,因此不需要额外依赖)

  2. 添加注解(只需要在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();
    }
  3. 添加配置,直接使用

            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 客户端负载均衡的更多相关文章

  1. 笔记:Spring Cloud Ribbon 客户端负载均衡

    Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,基于 Netflix Ribbon 实现,通过Spring Cloud 的封装,可以让我们轻松的将面向服 ...

  2. 基于Spring cloud Ribbon和Eureka实现客户端负载均衡

    前言 本案例将基于Spring cloud Ribbon和Eureka实现客户端负载均衡,其中Ribbon用于实现客户端负载均衡,Eureka主要是用于服务注册及发现: 传统的服务端负载均衡 常见的服 ...

  3. Spring Cloud 2-Ribbon 客户端负载均衡(二)

    Spring Cloud Eureka  1.Hello-Service服务端配置 pom.xml application.yml 启动两个service 2.Ribbon客户端配置 pom.xml ...

  4. spring cloud 使用ribbon简单处理客户端负载均衡

    假如我们的multiple服务的访问量剧增,用一个服务已经无法承载, 我们可以把Hello World服务做成一个集群. 很简单,我们只需要复制Hello world服务,同时将原来的端口8762修改 ...

  5. 第四章 客户端负载均衡:Spring Cloud Ribbon

    spring cloud ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于Netflix Ribbon 实现.通过Spring Cloud 的封装,可以轻松的将面向服务的R ...

  6. Spring Cloud Ribbon——客户端负载均衡

    一.负载均衡负载均衡(Load Balance): 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性.其意思 ...

  7. 【SpringCloud微服务实战学习系列】客户端负载均衡Spring Cloud Ribbon

    Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现.通过Spring Cloud的封装,可以让我们轻松地将面向服务的RES模板 ...

  8. 【Dalston】【第二章】客户端负载均衡(Ribbon)

    对于大型应用系统负载均衡(LB:Load Balancing)是首要被解决一个问题.在微服务之前LB方案主要是集中式负载均衡方案,在服务消费者和服务提供者之间又一个独立的LB,LB通常是专门的硬件,如 ...

  9. 客户端负载均衡Feign之一:申明式服务调用Feign入门示例

    Spring Cloud提供了Ribbon和Feign作为客户端的负载均衡. 前面使用了Ribbon做客户端负载均衡,使用Hystrix做容错保护,这两者被作为基础工具类框架被广泛地应用在各个微服务的 ...

随机推荐

  1. Linux命令执行顺序与管道命令

    命令执行顺序控制 顺序执行多条命令:command1;command2;command3... 有选择执行命令:which command1 && command2 || comman ...

  2. 漫步Facebook开源C++库Folly之string类设计(散列、字符串、向量、内存分配、位处理等,小部分是对现有标准库和Boost库功能上的补充,大部分都是基于性能的需求而“重新制造轮子”)

    就在近日,Facebook宣布开源了内部使用的C++底层库,总称folly,包括散列.字符串.向量.内存分配.位处理等,以满足大规模高性能的需求. 这里是folly的github地址:https:// ...

  3. 记录一次PHP项目报502的问题

    问题描述 最近有台服务器偶尔会报502错误,虽然量不多,每天就几十个,但是也必须得找到原因,避免让小问题变成大问题. 排查过程 502错误的原因,一般是对用户访问请求的响应超时造成的,一开始以为是请求 ...

  4. C++界面库(十几种,很全)

    刚开始用C++做界面的时候,根本不知道怎么用简陋的MFC控件做出比较美观的界面,后来就开始逐渐接触到BCG  Xtreme ToolkitPro v15.0.1,Skin++,等界面库,以及一些网友自 ...

  5. 三个臭皮匠,顶上一个诸葛亮——在Google Ideathon上Design Thinking分享

    4月26日很荣幸的被邀请参加Google Ideathon做Design Thinking的分享. 这次主要分享了Design Thinking的基本方法流程,以及在真实项目的运用.现在整理一下当时选 ...

  6. MYSQL的全局变量和会话变量

    系统变量又分为全局变量与会话变量. 全局变量在MYSQL启动的时候由服务器自动将它们初始化为默认值,这些默认值可以通过更改my.ini这个文件来更改. 会话变量在每次建立一个新的连接的时候,由MYSQ ...

  7. 深入理解计算机系统 BombLab 实验报告

    又快有一个月没写博客了,最近在看<深入理解计算机系统>这本书,目前看完了第三章,看完这章,对程序的机器级表示算是有了一个入门,也对 C 语言里函数栈帧有了一个初步的理解. 为了加深对书本内 ...

  8. 编写loadrunner的ftp脚本(详细步骤)

    大家好,主要给大家讲解编写loadrunner的ftp脚本详细步骤,及FTP函数注释,及FTP脚本两种编写方式,手动和录制.亲测 No problem!^_^ 1.首先要了解loadrunner中几个 ...

  9. C++标准库(体系结构与内核分析)(侯捷第二讲)

    一.OOP和GP的区别(video7) OOP:面向对象编程(Object-Oriented programming) GP:泛化编程(Generic programming) 对于OOP来说,我们要 ...

  10. memcached--add使用

    memcached是一种管理内存的软件,来动态的分配机器的内存,将需要存储的数据以key-value(键值对)的形式存储在内存中. 1.memcached使用的存储算法是hash算法在内存中存储字符串 ...