SpringCloud之Ribbon负载均衡

本文介绍了SpringCloud中的Ribbon组件如何实现客户端负载均衡。通过详细步骤展示了从服务提供方到服务消费方的配置,包括依赖、配置文件设置、主要代码实现,并通过测试验证了默认的轮询策略以及如何配置和测试自定义的负载均衡策略。
摘要由CSDN通过智能技术生成

1. 前言

RibbonNetflix 开发的一个负载均衡组件,它在服务体系中起着重要作用,与其他 SpringCloud 组件结合可以发挥出强大作用,它的负载策略有多种,默认轮询

说到负载均衡,ribbonlvs、nginx 不一样,nginx 是服务端负载均衡,ribbon 是客户端负载均衡,具体表现为客户端从注册中心拿到服务的所有实例,然后以负载均衡方式去调用服务,默认以轮询的方式去调用服务实例

ribboneureka 配合使用的大致架构如下

在这里插入图片描述

2. ribbon 实现负载均衡

上一篇 文章中,已实现 eureka 客户端的注册行为,本篇文章将实现 eureka 客户端的调用,即服务提供方提供接口供服务消费方来消费,调用,并实现 ribbon 的客户端负载均衡

依然使用上一篇文章的项目,如下

在这里插入图片描述

2.1. Maven 主要依赖

eureka-client-consumer 服务消费方项目添加如下依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>  
  • spring-cloud-starter-netflix-eureka-client:如果已经引入了这个 eureka 客户端的依赖,此时可以不需要引入上述 spring-cloud-starter-netflix-ribbon 依赖了,因为 eureka 客户端的依赖已经包含了
    spring-cloud-starter-netflix-ribbon 依赖
  • eureka-client-producer:作为服务的提供方,需要提供接口供消费方使用。这里我们可以连接数据库,至于连接数据库,以及 ORM 持久层框架的依赖,这里不再赘述,自己引入即可

2.2. application.properties 配置文件

2.2.1. eureka-client-producer 服务提供方

server.port=8080

#注册进eureka的名称
spring.application.name=eureka-client-producer

#JDBC 配置
spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=UTC
spring.datasource.druid.username=root
spring.datasource.druid.password=123456
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

#druid 连接池配置
spring.datasource.druid.initial-size=3
spring.datasource.druid.min-idle=3
spring.datasource.druid.max-active=10
spring.datasource.druid.max-wait=60000

#指定 mapper 文件路径
mybatis.mapper-locations=classpath:org/example/mapper/*.xml
mybatis.configuration.cache-enabled=true
#开启驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true
#打印 SQL 语句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

eureka.client.service-url.defaultZone=http://eureka7001:8761/eureka/
eureka.instance.prefer-ip-address=true

2.2.2. eureka-client-consumer 服务消费方

server.port=8090

#注册进eureka的名称
spring.application.name=eureka-client-consumer

eureka.client.service-url.defaultZone=http://eureka7001:8761/eureka/
eureka.instance.prefer-ip-address=true

2.3. eureka-client-producer 服务提供方的主要代码

2.3.1. service

查询数据库

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Value(value = "${server.port}")
    private Integer port;

    @Autowired
    private UserMapper userMapper;

    @Override
    public ResultVo selectOne(Integer id) {
        log.info("服务提供方的端口为:" + port);
        User user = userMapper.selectByPrimaryKey(id);
        ResultVo resultVo = new ResultVo();
        BeanUtils.copyProperties(user, resultVo);
        resultVo.setPort(port);
        return resultVo;
    }
}

2.3.2. controller

对外提供的接口

@Slf4j
@Controller
@RequestMapping(path = "/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping(path = "/selectUserById")
    @ResponseBody
    public ResultVo selectUserById(Integer id) {
        return userService.selectOne(id);
    }
}

2.3.3. 启动类

@EnableEurekaClient
@Slf4j
@SpringBootApplication
public class AppProducer {

    public static void main(String[] args) {
        SpringApplication.run(AppProducer.class, args);
        log.info("------AppProducer Running------");
    }
}

2.4. eureka-client-consumer 服务消费方的主要代码

2.4.1. config 配置类

@Configuration
public class UserConsumerConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

2.4.2. service

@Slf4j
@Service
public class UserConsumerServiceImpl implements UserConsumerService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    /**
     * ribbon 实现负载均衡
     */
    @Override
    public ResultVo findOneById(Integer id) {
        // eureka-client-producer:是生产者端服务名称
        ResponseEntity<ResultVo> responseEntity = restTemplate.getForEntity("http://eureka-client-producer/user/selectUserById?id=" + id, ResultVo.class);
        ResultVo resultVo = responseEntity.getBody();
        assert resultVo != null;
        log.info("User为:" + resultVo.toString());
        log.info("调用服务提供方的端口为:" + resultVo.getPort());
        return resultVo;
    }
}
  • eureka-client-producer:就是配置文件 application.properties 配置的 spring.application.name 的值

2.4.3. controller

@Slf4j
@Controller
@RequestMapping(path = "/UserConsumer")
public class UserConsumerController {

    @Autowired
    private UserConsumerService userConsumerService;

    /**
     * ribbon 实现负载均衡
     */
    @GetMapping(path = "/findOneById")
    @ResponseBody
    public ResultVo findOneById(Integer id) {
        return userConsumerService.findOneById(id);
    }
}

2.4.4. 启动类

@EnableEurekaClient
@Slf4j
@SpringBootApplication
public class AppConsumer {

    public static void main(String[] args) {
        SpringApplication.run(AppConsumer.class, args);
        log.info("------AppConsumer Running------");
    }
}

3. 启动测试

3.1. eureka 集群改单机

由于机器资源有限,服务启动太多有点卡,所以将 eureka 集群模式改为单机模式,以节省机器资源,配置文件 application.properties 改为如下

server.port=8761

#false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
eureka.client.fetch-registry=false
#false表示不向注册中心注册自己
eureka.client.register-with-eureka=false
#集群版
#eureka.client.service-url.defaultZone=http://eureka7002:8762/eureka/,http://eureka7003:8763/eureka/
#单机版
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
#注册进对方注册中心展示的实例名称
eureka.instance.hostname=eureka7001

3.2. 启动各个服务测试

分别启动 eureka-client-producereureka-client-consumereureka-server-one,这 3 个服务项目,首先查看 eureka 注册中心的服务注册情况,浏览器输入:http://eureka7001:8761/ 如下

  • 为了测试负载均衡,对 eureka-client-producer 服务要启动两个实例,即启动两个端口不同的实例服务;一个端口为 8080,一个为 8070

在这里插入图片描述

3.3. 测试

使用 postman 测试接口,也就是接口 http://127.0.0.1:8090/UserConsumer/findOneById?id=1

在这里插入图片描述
我们发送 5 次请求,查看控制台日志情况,如下

在这里插入图片描述
观察日志,可以看到服务提供方 eureka-client-producer分别以 8080,8070 端口被调用,并且是轮询的方式,这也印证了 ribboon 是默认以轮询的方式去调用服务实例

4. Ribbon 配置负载均衡策略

4.1. ribbon 支持的策略

ribbon 支持 7 种负载均衡策略

策略类命名描述
RandomRule随机策略随机选择 server
RoundRobinRule轮询策略按照顺序选择 server ( 默认策略)
RetryRule重试策略在一个配置时间段内,当选择 server 不成功,则一直尝试选择一个可用的 server
BestAvailableRule最低并发策略逐个考察 server,如果 server 断路器打开,则忽略,再选择其中并发链接最低的 server
AvailabilityFilteringRule可用过滤策略过滤掉一直失败并被标记为 circuit tripped 的 server,过滤掉那些高并发链接的 server(active connections 超过配置的阈值)
ResponseTimeWeightedRule响应时间加权重策略根据 server 的响应时间分配权重,响应时间越长,权重越低,被选择到的概率也就越低。响应时间越短,权重越高,被选中的概率越高,这个策略很贴切,综合了各种因素,比如:网络,磁盘,io 等,都直接影响响应时间
ZoneAvoidanceRule区域权重策略综合判断 server 所在区域的性能,和 server 的可用性,轮询选择 server 并且判断一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 server

4.2. 对某个服务配置启用某种策略

在服务消费方 eureka-client-consumer 的配置类 UserConsumerConfig 中添加如下配置

/**
 * 配置随机负载均衡策略
 */
@Bean
public IRule ribbonRule() {
	return new RandomRule();
}

4.3. 启动服务测试

postman 测试接口如下

在这里插入图片描述
我们发送 9 次请求,查看控制台日志情况,如下

在这里插入图片描述
可以看到,我们配置的随机负载均衡策略已经生效

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值