文章目录
一、负载均衡的两种方式
- 服务器端负载均衡
- 客户端侧负载均衡
二、手写一个客户端侧负载均衡器
修改内容中心代码
在用户中心启动两个实例
访问并多次刷新浏览器http://localhost:8010/shares/1,实现随机负载均衡算法
三、使用Ribbon实现负载均衡
引入Ribbon后架构的演进
添加@LoadBalanced
注解
修改ShareService
启动相关服务,测试访问
四、Ribbon的组成
五、Ribbon内置负载均衡规则
六、细粒度配置自定义
1、Java代码配置
2、配置属性配置
3、两种方式的比较
4、总结
尽量使用属性配置,属性方式实现不了的情况下在考虑使用代码配置
在同一个微服务内尽量保持单一性,比如统一使用属性配置,不要两种方式混用,增加定位代码的复杂性。
七、全局配置
八、支持的配置项
九、Ribbon的饥饿加载
解决第一次访问http://localhost:8010/shares/1地址加载缓慢的问题十、扩展Ribbon支持Nacos权重
在configuration包下新建NacosWeightedRule类@Slf4j
public class NacosWeightedRule extends AbstractLoadBalancerRule {
@Autowired
NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
// 读取配置文件并初始化NacosWeightedRule
}
@Override
public Server choose(Object o) {
try {
BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
// log.info("lb = {}",loadBalancer);
// 想要请求的微服务的名称
String name = loadBalancer.getName();
// 拿到服务发现相关的API
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
// nacos client自动通过基于权重的负载均衡算法,给我们选择一个实例
Instance instance = namingService.selectOneHealthyInstance(name);
log.info("选择的实例是:port = {},instance = {}",instance.getPort(),instance);
return new NacosServer(instance);
} catch (NacosException e) {
return null;
}
}
}
修改RibbonConfiguration类
将8081的端口的实例的权重值置为0
测试结果
十一、扩展Ribbon同集群优先
在configuration包下新建NacosSameClusterWeightedRule类
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {
@Autowired
NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object o) {
try {
// 拿到配置文件中集群的名称 BJ
String clusterName = nacosDiscoveryProperties.getClusterName();
BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
// 想要请求的微服务的名称
String name = loadBalancer.getName();
// 拿到服务发现相关的API
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
// 1.找到指定服务的所有实例 A
List<Instance> instances = namingService.selectInstances(name, true);
// 2.过滤出相同集群下的所有实例 B
List<Instance> sameClusterInstances = instances.stream()
.filter(instance -> {
return Objects.equals(instance.getClusterName(),clusterName);
})
.collect(Collectors.toList());
// 3.如果B为空,就使用A
List<Instance> instancesToBeChosen = new ArrayList<>();
if (CollectionUtils.isEmpty(sameClusterInstances)){
instancesToBeChosen = instances;
log.warn("发生跨集群的调用,name = {}, clusterName = {}, instances = {}",name,clusterName,instances);
}
else {
instancesToBeChosen = sameClusterInstances;
}
// 4.基于权重的负载均衡算法,返回一个实例
Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToBeChosen);
log.info("选择的实例是 port = {}, instance = {}",instance.getPort(),instance);
return new NacosServer(instance);
} catch (NacosException e) {
log.error("发生异常了",e);
return null;
}
}
}
class ExtendBalancer extends Balancer{
public static Instance getHostByRandomWeight2(List<Instance> hosts) {
return getHostByRandomWeight(hosts);
}
}
修改RibbonConfiguration
修改application.yml
测试结果
十二、扩展Ribbon基于元数据的版本控制
详情请参考 手记
十三、深入理解Nacos的namespace
在user-center下指定namespace,而content-center未指定
说明服务之间不能跨namespace调用,namespace实现了隔离。