微服务负载均衡实践

概述

本文介绍微服务的服务调用和负载均衡,使用spring cloud的loadbalancer及openfeign两种技术来实现。

本文的操作是在微服务的初步使用的基础上进行。

环境说明

jdk1.8

maven3.6.3

mysql8

spring cloud2021.0.8

spring boot2.7.12

idea2022

步骤

改造Eureka为单节点

为了方便测试,把高可用Eureka还原为单节点Eureka。

修改eureka_server的application.yml

复制代码
spring:
  application:
    name: eureka-server
server:
  port: 9000
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 4000

修改product-service服务和order-service服务的application.yml的Eureka配置如下

复制代码
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
spring-cloud-loadbalancer

spring-cloud-loadbalancer和ribbon类似,之前的spring cloud版本eureka内部继承了ribbon ,但spring cloud版本升级后,不再内置ribbon(可查看依赖关系),spring cloud提供了自己的负载均衡的实现,可查看 官方文档

Spring Cloud provides its own client-side load-balancer abstraction and implementation. For the load-balancing mechanism, ReactiveLoadBalancer interface has been added and a Round-Robin-based and Random implementations have been provided for it. In order to get instances to select from reactive ServiceInstanceListSupplier is used. Currently we support a service-discovery-based implementation of ServiceInstanceListSupplier that retrieves available instances from Service Discovery using a Discovery Client available in the classpath.

服务调用

之前服务调用时,使用host:ip拼接成URL的方式进行调用,较为麻烦,使用@LoadBalanced注解后,可以使用微服务的服务名称来进行调用,更加方便。

在创建RestTemplate的时候,申明@LoadBalanced

使用restTemplate调用远程微服务:不需要拼接微服务的URL,用服务名称替换IP地址

修改OrderController.java,使用服务名称代替host:port的形式,避免了之前的使用实例元数据进行拼接。

修改前

复制代码
product  = restTemplate.getForObject("http://"+host+":"+port+"/product/1", Product.class);

修改后

复制代码
product  = restTemplate.getForObject("http://service-product/product/1", Product.class);

启动测试

启动eureka、product、order服务

浏览器访问

能访问到数据,说明服务调用成功了。

负载均衡

使用@LoadBalanced注解后,除了方便使用服务名称进行调用之外,更重要的是也实现了服务调用的负载均衡功能。准备两个商品服务,端口号分别为9001、9011,两个商品服务的作用:1.增加系统吞吐率 2.商品服务高可用。

服务架构及流程如下图:

修改product-service的controller

java 复制代码
    @Value("${spring.cloud.client.ip-address}") //springcloud自动获取应用的ip地址
    private String ip;

启动product服务(9001端口)

修改product服务的yml,修改服务端口为9011

复制运行配置得到另一个proudct服务

启动product2服务(9011端口)

查看Eureka Web页面

http://localhost:9000/

看到SERVICE-PRODUCT,有2个在线状态的实例,端口分别是:9001和9011

启动order服务

分别访问9001和9011

http://localhost:9001/product/1

http://localhost:9011/product/1

两个商品服务均正常

测试负载均衡

访问如下链接2次

http://localhost:9002/order/buy/1

发现实现 第一次访问9001商品服务,第二次访问了9011商品服务,说明实现了客户端的负载均衡

多次刷新访问http://localhost:9002/order/buy/1,发现9001和9011是交替出现,说明默认使用的负载均衡是轮询策略。

OpenFeign

此前的服务调用代码如下:

java 复制代码
restTemplate.getForObject("http://service-product/product/1", Product.class);

如果请求参数过多是,拼接URL的方式显得麻烦,可以使用OpenFeign来解决。

OpenFeign 全称 Spring Cloud OpenFeign,它是 Spring 官方推出的一种声明式服务调用与负载均衡组件,它的出现就是为了替代进入停更维护状态的 Feign。

OpenFeign 是 Spring Cloud 对 Feign 的二次封装,它具有 Feign 的所有功能,并在 Feign 的基础上增加了对 Spring MVC 注解的支持。

OpenFeign的使用

order-service操作

1.导入依赖

XML 复制代码
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.配置调用接口

业务需求:order服务调用product服务

java 复制代码
@FeignClient(name = "service-product")
public interface ProductFeignClient {

    /**
     * 配置需要调用的微服务接口
     * @return
     */
    @RequestMapping(value = "/product/{id}", method = RequestMethod.GET)
    Product findById(@PathVariable("id") Long id);
}

3.在启动类上激活feign

java 复制代码
//激活feign
@EnableFeignClients
public class OrderApplication {

4.通过自动注入的接口调用远程微服务

修改之前的Controller代码

java 复制代码
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id){
        Product product = null;

        product  = restTemplate.getForObject("http://service-product/product/1", Product.class);

        return product;
    }

}

修改之后的代码

java 复制代码
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private ProductFeignClient productFeignClient;

    @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id){
        Product product = null;

        //调用微服务
        product = productFeignClient.findById(id);

        return product;
    }

}

可以看出,OrderController通过注入ProductFeignClient接口实例,并调用接口方法实现了调用。 可以看出不需要自己构建http请求,就像是调用自身工程的方法调用。如果有多个参数可以传递对象参数,避免了拼接url的麻烦。

测试

启动服务

启动eureka、启动product(启动两个实例:9000和9011)、启动order

浏览器访问

分别访问,确保product服务能正常访问

http://localhost:9001/product/1

http://localhost:9011/product/1

访问order两次

http://localhost:9002/order/buy/1

多次访问,发现9001和9011交替出现,说明实现了负载均衡。

OpenFeign的配置

如果需要配置OpenFeign,在application.yml添加相关配置

配置案例如下:

复制代码
feign:
  client:
    config:
      feignName: #FeginClient的名称
        connectTimeout: 5000 #建立链接的超时时长
        readTimeout: 5000 #读取超时时长
        loggerLevel: full #Fegin的日志级别
        errorDecoder: com.example.SimpleErrorDecoder #Feign的错误解码器
        retryer: com.example.SimpleRetryer #配置重试
        requestInterceptors: #添加请求拦截器
          - com.example.FooRequestInterceptor
          - com.example.BarRequestInterceptor
        decode404: false #配置熔断不处理404异常
      #日志配置  
      #NONE : 不输出日志(高)   
      #BASIC: 适用于生产环境追踪问题
      #HEADERS : 在BASIC的基础上,记录请求和响应头信息   
      #FULL : 记录所有
      service-product:
        logger-level: FULL #配置商品服务日志
  compression:
    request:
      enabled: true #开启请求压缩
      mime-types: text/html,application/xml,application/json #设置压缩的数据类型
      min-request-size: 2048 #设置触发压缩的大小下限
    response:
      enabled: true #开启相应压缩
logging:
  level:
    org.example.order.feign.ProductFeignClient: debug #配置具体接口的日志级别
总结

两种服务调用及负载均衡技术:@LoadBalanced方式和OpenFeign的方式。

1.@LoadBalanced方式是借助于RestTemplate方式进行,可以直接使用服务名称来调用,但需要拼接URL。

2.OpenFeign的方式是通过声明接口并注入接口进行调用,避免了拼接URL的麻烦。

完成!enjoy it!

相关推荐
KYGALYX16 小时前
服务异步通信
开发语言·后端·微服务·ruby
yunteng52117 小时前
通用架构(同城双活)(单点接入)
架构·同城双活·单点接入
麦聪聊数据17 小时前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
程序员侠客行18 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
主机哥哥18 小时前
阿里云OpenClaw部署全攻略,五种方案助你快速部署!
服务器·阿里云·负载均衡
bobuddy20 小时前
射频收发机架构简介
架构·射频工程
桌面运维家20 小时前
vDisk考试环境IO性能怎么优化?VOI架构实战指南
架构
一个骇客1 天前
让你的数据成为“操作日志”和“模型饲料”:事件溯源、CQRS与DataFrame漫谈
架构
鹏北海-RemHusband1 天前
从零到一:基于 micro-app 的企业级微前端模板完整实现指南
前端·微服务·架构