Spring Cloud Alibaba - 08 Ribbon 两种方式实现细粒度自定义配置控制微服务的负载均衡策略

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
EMR Serverless StarRocks,5000CU*H 48000GB*H
应用型负载均衡 ALB,每月750个小时 15LCU
简介: Spring Cloud Alibaba - 08 Ribbon 两种方式实现细粒度自定义配置控制微服务的负载均衡策略

6735aa4777de402592fbe82e8b40ee3d.png

需求


假设我们有个场景:

Order-Center 需要采用随机算法调用产品中心 , 而采用轮询算法调用其他中心微服务


工程


3d9c6c46eb4f41daa4c0cf4fb47b58f1.png


java代码实现细粒度配置 (不推荐)


注意事项: PayCenterRibbonConfig,ProductCenterRibbonConfig不能被放在我们主启动类所在包以及子包下,不然就起不到细粒度配置

【支付中心对应的Ribbon访问策略】


package com.globalconfig;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/2/2 19:42
 * @mark: show me the code , change the world
 */
@Configuration
public class PayCenterRibbonConfig {
    @Bean
    public IRule roundRobinRule() {
        return new RoundRobinRule();
    }
}

【产品中心对应的Ribbon访问策略】

package com.globalconfig;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/2/2 19:45
 * @mark: show me the code , change the world
 */
@Configuration
public class ProductCenterRibbonConfig {
    @Bean
    public IRule randomRule() {
        return new RandomRule();
    }
}


【带有@LoadBalanced的RestTemplate

package com.artisan.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/2/2 15:47
 * @mark: show me the code , change the world
 */
@Configuration
public class WebConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}


【为每个服务分配 访问策略 】

package com.artisan.config;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Configuration;
/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/2/2 19:51
 * @mark: show me the code , change the world
 */
@Configuration
@RibbonClients(value = {
        @RibbonClient(name = "artisan-product-center",configuration = com.globalconfig.ProductCenterRibbonConfig.class),
        @RibbonClient(name = "artisan-pay-center",configuration = com.globalconfig.PayCenterRibbonConfig.class)
})
public class CustomRibbonConfig {
}


【Controller 】

import com.artisan.common.entity.OrderInfo;
import com.artisan.common.entity.PayInfo;
import com.artisan.common.entity.ProductInfo;
import com.artisan.common.vo.OrderAndPayVo;
import com.artisan.common.vo.OrderVo;
import com.artisan.mapper.OrderInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
 * @author 小工匠
 * @version 1.0
 * @description: TODO
 * @date 2022/2/2 03:20
 * @mark: show me the code , change the world
 */
@RestController
@Slf4j
public class OrderInfoController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    /**
     * 调用地址, 注册中心 地址
     */
    public static final String PRODUCT_URI = "http://artisan-product-center/selectProductInfoById/";
    public static final String PAY_URI = "http://artisan-pay-center/selectPayInfoByOrderNo/";
    @RequestMapping("/v2/selectOrderInfoById/{orderNo}")
    public Object selectOrderInfoById(@PathVariable("orderNo") String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.selectOrderInfoById(orderNo);
        if (null == orderInfo) {
            return "根据orderNo:" + orderNo + "查询没有该订单";
        }
        // 发起远程Http调用
        ResponseEntity<ProductInfo> responseEntity = restTemplate.getForEntity(PRODUCT_URI + orderInfo.getProductNo(), ProductInfo.class);
        ProductInfo productInfo = responseEntity.getBody();
        if (productInfo == null) {
            return "没有对应的商品";
        }
        OrderVo orderVo = new OrderVo();
        orderVo.setOrderNo(orderInfo.getOrderNo());
        orderVo.setUserName(orderInfo.getUserName());
        orderVo.setProductName(productInfo.getProductName());
        orderVo.setProductNum(orderInfo.getProductCount());
        return orderVo;
    }
    @RequestMapping("/getOrderAndPayInfoByOrderNo/{orderNo}")
    public Object getOrderAndPayInfoByOrderNo(@PathVariable("orderNo") String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.selectOrderInfoById(orderNo);
        if (null == orderInfo) {
            return "根据orderNo:" + orderNo + "查询没有该订单";
        }
        ResponseEntity<PayInfo> responseEntity = restTemplate.getForEntity(PAY_URI + orderInfo.getProductNo(), PayInfo.class);
        PayInfo payInfo = responseEntity.getBody();
        if (payInfo == null) {
            return "没有对应的支付信息";
        }
        OrderAndPayVo orderAndPayVo = new OrderAndPayVo();
        orderAndPayVo.setOrderNo(orderNo);
        orderAndPayVo.setProductNo(orderInfo.getProductNo());
        orderAndPayVo.setProductCount(orderInfo.getProductCount());
        orderAndPayVo.setPayNo(payInfo.getPayNo());
        orderAndPayVo.setPayTime(payInfo.getPayTime());
        orderAndPayVo.setUserName(orderInfo.getUserName());
        return orderAndPayVo;
    }
}


3a6b9cc05d324da9a29b563556f88c73.png2190f82799c94e0f9c0e476be59b0f4d.png

a42b1b622e3f4655b4184a0933dc7dd6.png

349b3ea0722c4a119b6dda0971e7b19c.png


可以看到,实现了我们最开始的需求 。


配置实现细粒度配置 (推荐)

接着上面的工程,首先屏蔽掉 CustomRibbonConfig

c019a2db2e9841908c268fcbc8e7a83d.png

然后再 artisan-cloud-customcfg-ribbon-order 子模块的配置文件 application.yml

增加

#自定义Ribbon的细粒度配置
artisan-pay-center:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
artisan-product-center:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule


然后启动多个Pay和Product服务进行测试

结果如下:

访问4次

cf83ebc33346468693bd8611e057d3cd.png


访问 10次

de3e250eae5647af8c6f0561ed2c6b74.png


源码

https://github.com/yangshangwei/SpringCloudAlibabMaster

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
4月前
|
安全 Java 数据安全/隐私保护
使用Spring Security实现细粒度的权限控制
使用Spring Security实现细粒度的权限控制
WXM
|
3月前
|
存储 缓存 Java
|
4月前
|
Java 微服务 Spring
SpringCloud gateway自定义请求的 httpClient
SpringCloud gateway自定义请求的 httpClient
173 3
|
4月前
|
负载均衡 监控 Kubernetes
Service Mesh 是一种用于处理服务间通信的基础设施层,它通常与微服务架构一起使用,以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。
Service Mesh 是一种用于处理服务间通信的基础设施层,它通常与微服务架构一起使用,以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。
|
4月前
|
缓存 负载均衡 算法
微服务之客户端负载均衡
微服务中的客户端负载均衡是指将负载(即工作任务或访问请求)在客户端进行分配,以决定由哪个服务实例来处理这些请求。这种负载均衡方式与服务端负载均衡相对,后者是在服务端(如服务器或负载均衡器)进行请求的分发。
67 5
|
4月前
|
安全 Java 数据安全/隐私保护
使用Spring Security实现细粒度的权限控制
使用Spring Security实现细粒度的权限控制
|
5月前
|
负载均衡 算法 Java
Spring Cloud Netflix 之 Ribbon
Spring Cloud Netflix Ribbon是客户端负载均衡器,用于在微服务架构中分发请求。它与RestTemplate结合,自动在服务发现(如Eureka)注册的服务之间进行调用。配置包括在pom.xml中添加依赖,设置application.yml以连接Eureka服务器,并在配置类中创建@LoadBalanced的RestTemplate。通过这种方式,当调用如`/user/userInfoList`的接口时,Ribbon会自动处理到多个可用服务实例的负载均衡。
|
5月前
|
缓存 负载均衡 Java
Java一分钟之-Spring Cloud Netflix Ribbon:客户端负载均衡
【6月更文挑战第9天】Spring Cloud Netflix Ribbon是客户端负载均衡器,用于服务间的智能路由。本文介绍了Ribbon的基本概念、快速入门步骤,包括添加依赖、配置服务调用和使用RestTemplate。此外,还讨论了常见问题,如服务实例选择不均、超时和重试设置不当、服务列表更新不及时,并提供了相应的解决策略。最后,展示了如何自定义负载均衡策略。理解并正确使用Ribbon能提升微服务架构的稳定性和效率。
186 3
|
5月前
|
负载均衡 算法 Nacos
SpringCloud之LoadBalancer自定义负载均衡算法,基于nacos权重
ReactorLoadBalancer接口,实现自定义负载算法需要实现该接口,并实现choose逻辑,选取对应的节点。
406 0
|
6月前
|
缓存 负载均衡 监控
探索分布式系统演进之路:从负载均衡到微服务架构
小米分享了分布式系统的发展,从早期的负载均衡(入口级、网关和客户端)到微服务架构的演进。微服务实现服务解耦,增强系统弹性,但带来了新的挑战。为优化数据库性能,实施了主备读写分离、全文搜索引擎、缓存集群等措施。通过微服务治理,如服务注册、动态配置、灰度发布等,提升了系统稳定性和可靠性。未来将继续优化分布式系统,提供更好的服务体验。关注公众号“软件求生”了解更多。
90 6