【夯实Spring Cloud】Spring Cloud中使用Ribbon实现负载均衡详解(下)

版权声明:尊重博主原创文章,转载请注明出处 https://blog.csdn.net/eson_15/article/details/86225272

本文属于【夯实Spring Cloud】系列文章,该系列旨在用通俗易懂的语言,带大家了解和学习Spring Cloud技术,希望能给读者带来一些干货。系列目录如下:

【夯实Spring Cloud】Dubbo沉睡5年,Spring Cloud开始崛起!
【夯实Spring Cloud】Spring Cloud中基于maven的分布式项目框架的搭建
【夯实Spring Cloud】Spring Cloud中的Eureka服务注册与发现详解
【夯实Spring Cloud】Spring Cloud中如何完善Eureka中的服务信息
【夯实Spring Cloud】Spring Cloud中使用Eureka集群搭建高可用服务注册中心
【夯实Spring Cloud】Spring Cloud中的Eureka和Zookeeper的区别在哪?
【夯实Spring Cloud】Spring Cloud中使用Ribbon实现负载均衡详解(上)
【夯实Spring Cloud】Spring Cloud中使用Ribbon实现负载均衡详解(下)
【夯实Spring Cloud】Spring Cloud中自定义Ribbon负载均衡策略
【夯实Spring Cloud】Spring Cloud中使用Feign实现负载均衡详
【夯实Srping Cloud】Spring Cloud中使用Hystrix实现断路器原理详解(上)
【夯实Srping Cloud】Spring Cloud中使用Hystrix实现断路器原理详解(下)
【夯实Spring Cloud】Spring Cloud中使用Zuul实现路由网关详解
【夯实Spring Cloud】Spring Cloud分布式配置中心详解
【夯实Spring Cloud】未完待续


在上一篇文章中,我对 Ribbon 做了一个介绍,Ribbon 可以实现直接通过服务名称对服务进行访问。这一篇文章我详细分析一下如何使用 Ribbon 实现客户端的负载均衡。

1. 使用 Ribbon 实现负载均衡

要实现负载均衡,首先要有多个订单服务提供者,目前我们就一个 microservice-order-provider01,端口号 8001,我们可以仿照这个服务,再创建两个子模块,也是订单服务提供者,取名为 microservice-order-provider02,端口号 8002 和 microservice-order-provider03,端口号 8003。

我们来看一下,使用 Ribbon 之后的架构图。

Ribbon负载均衡

Ribbon 是客户端的负载均衡工具,它在服务的消费方,首先三个订单服务 8001、8002和8003都会注册到 Eureka 集群,Ribbon 会先从 Eureka 集群中查询可用的服务列表,然后根据 Ribbon 提供的负载均衡算法,负载均衡的请求可用的订单服务。

Ribbon 默认的负载均衡算法是轮询,也就是按顺序挨个的调用。我们先来搭建一下整个服务架构,上面提到了,首先要拷贝两个订单服务,端口号分别为 8002 和 8003,一起来对比看下三个订单服务的配置文件。

8001 端口的订单服务:

# 服务端口号
server:
  port: 8001

# 数据库地址
datasource:
  url: localhost:3306/microservice01

spring:
  application:
    name: microservice-order # 对外暴露的服务名称

  datasource: # 数据库配置
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${datasource.url}?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
    username: root
    password: 123456
    hikari:
      maximum-pool-size: 10 # 最大连接池数
      max-lifetime: 1770000

mybatis:
  # 指定别名设置的包为所有entity
  type-aliases-package: com.itcodai.springcloud.entity
  mapper-locations: # mapper映射文件位置
    - classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true # 驼峰命名规范

# 客户端注册进eureka服务列表里
eureka:
  client:
    service-url:
      defaultZone: http://eureka01:7001/eureka/,http://eureka02:7002/eureka/,http://eureka03:7003/eureka/,
  instance:
    instance-id: 书籍订单服务-8001  # 人性化显示出服务的信息
    prefer-ip-address: true    # 访问路径可显示ip地址

# 使用actuator来展示项目的基本信息
info:
  author.name: shengwu ni
  app.name: microservice
  server.port: ${server.port}
  application.name: ${spring.application.name}

8002 端口的订单服务:

# 服务端口号
server:
  port: 8002

# 数据库地址
datasource:
  url: localhost:3306/microservice02

spring:
  application:
    name: microservice-order # 对外暴露的服务名称

  datasource: # 数据库配置
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${datasource.url}?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
    username: root
    password: 123456
    hikari:
      maximum-pool-size: 10 # 最大连接池数
      max-lifetime: 1770000

mybatis:
  # 指定别名设置的包为所有entity
  type-aliases-package: com.itcodai.springcloud.entity
  mapper-locations: # mapper映射文件位置
    - classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true # 驼峰命名规范

# 客户端注册进eureka服务列表里
eureka:
  client:
    service-url:
      defaultZone: http://eureka01:7001/eureka/,http://eureka02:7002/eureka/,http://eureka03:7003/eureka/,
  instance:
    instance-id: 书籍订单服务-8002  # 人性化显示出服务的信息
    prefer-ip-address: true    # 访问路径可显示ip地址

# 使用actuator来展示项目的基本信息
info:
  author.name: shengwu ni
  app.name: microservice
  server.port: ${server.port}
  application.name: ${spring.application.name}

8003 端口的订单服务:

# 服务端口号
server:
  port: 8003

# 数据库地址
datasource:
  url: localhost:3306/microservice03

spring:
  application:
    name: microservice-order # 对外暴露的服务名称

  datasource: # 数据库配置
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://${datasource.url}?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
    username: root
    password: 123456
    hikari:
      maximum-pool-size: 10 # 最大连接池数
      max-lifetime: 1770000

mybatis:
  # 指定别名设置的包为所有entity
  type-aliases-package: com.itcodai.springcloud.entity
  mapper-locations: # mapper映射文件位置
    - classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true # 驼峰命名规范

# 客户端注册进eureka服务列表里
eureka:
  client:
    service-url:
      defaultZone: http://eureka01:7001/eureka/,http://eureka02:7002/eureka/,http://eureka03:7003/eureka/,
  instance:
    instance-id: 书籍订单服务-8003  # 人性化显示出服务的信息
    prefer-ip-address: true    # 访问路径可显示ip地址

# 使用actuator来展示项目的基本信息
info:
  author.name: shengwu ni
  app.name: microservice
  server.port: ${server.port}
  application.name: ${spring.application.name}

对比后发现,有几个地方需要注意:

  1. 对外暴露的服务名称必须要相同,因为都是同一个服务,只不过有多个而已,因为接下来Ribbon是通过服务名来调用服务的;
  2. 每个服务连接了不同的数据库,这样用来区分不同的服务,便于测试,实际中也可能是便于维护;
  3. 每个服务的个性化名称展示可以区分一下,这样在eureka里可以很好的辨别出来

Eureka 集群还是使用前面的 7001、7002 和 7003,首先我们启动 Eureka 集群,然后分别启动 8001、8002 和 8003 三个订单服务。(友情提示:这里已经启动了6个工程了,如果电脑的性能跟不上的话,可能已经开始卡顿了)

启动了之后,可以访问下 eureka01:7001,看下三个订单服务是否正常注册到 eureka 集群里。如下图,说明集群和订单服务均正常。
eureka集群

OK,接下来就是重点了,我们启动服务消费方,也就是上一节中的订单消费服务,然后在浏览器输入 http://localhost:9001/consumer/order/get/1 即可查询到对应的订单服务:

{"id":1,"name":"跟武哥一起学 Spring Boot","price":39.99,"dbSource":"microservice03"}

刷新页面,可以看到,结果如下:

{"id":1,"name":"跟武哥一起学 Spring Boot","price":39.99,"dbSource":"microservice01"}

再刷新页面,可以看到,结果如下:

{"id":1,"name":"跟武哥一起学 Spring Boot","price":39.99,"dbSource":"microservice02"}

可以看到,dbsource的值一在 microservice01、microservice02 和 microservice03 之间轮询切换(这个值是我在三个数据库中设置的不同的值,就是为了在这展示,方便看到效果),这就说明了,Ribbon 的负载均衡已经起作用了,客户端会轮询的根据服务名,从 8001、8002 和 8003 之间切换访问,从而达到负载均衡的效果。

同时,也可以看到,Ribbon 的默认负载均衡算法是轮询。

2. 如何指定 Ribbon 的负载均衡策略

由上面的结果可知,Ribbon 默认的策略是轮询,那么 Ribbon 除了轮询,还有哪些负载均衡的策略呢?我们如何去设置自己想要的策略呢?

Ribbon 自带的负载均衡策略有如下几个:

  1. RoundRibbonRule:轮询。人人有份,一个个来!
  2. RandomRule:随机。拼人品了!
  3. AvailabilityFilteringRule:先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,以及并发连接数超过阈值的服务,剩下的服务,使用轮询策略。
  4. WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应越快的服务权重越高,越容易被选中。一开始启动时,统计信息不足的情况下,使用轮询。
  5. RetryRule:先轮询,如果获取失败则在指定时间内重试,重新轮询可用的服务。
  6. BestAvailableRule:先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。
  7. ZoneAvoidanceRule:复合判断 server 所在区域的性能和 server 的可用性选择服务器

如何指定 Ribbon 自带的负载均衡策略呢?我们需要在配置类中指定一下即可,如下:

/**
 * 配置RestTemplate
 * @author shengwu ni
 */
@Configuration
public class RestTemplateConfig {

    /**
     * '@LoadBalanced'注解表示使用Ribbon实现客户端负载均衡
     * @return RestTemplate
     */
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    /**
     * 指定其他负载均衡策略
     * @return IRule
     */
    @Bean
    public IRule myRule() {
        // 指定重试策略:随机策略
        return new RandomRule();
    }
}

我们可以 new 出以上对应的策略,来实现对应的负载均衡,读者可以 new RandomRule() 测试一下随机策略,然后重复刷新上面的测试地址,可以发现是随机请求三个服务。其他的策略,读者可以自行尝试一下。

源码下载地址:https://gitee.com/eson15/springcloud_study
更多优质文章请关注我的微信公众号【程序员私房菜】,回复“资源”和“架构”可以领取优质的视频学习资源。
程序员私房菜

没有更多推荐了,返回首页