关于前端:SpringCloud微服务实战搭建企业级开发框架十二OpenFeignRibbon实现负载均衡

4次阅读

共计 6562 个字符,预计需要花费 17 分钟才能阅读完成。

  Ribbon 是 Netflix 下的负载平衡我的项目,它次要实现中间层应用程序的负载平衡。为 Ribbon 配置服务提供者地址列表后,Ribbon 就会基于某种负载平衡算法,主动帮忙服务调用者去申请。Ribbon 默认提供的负载平衡算法有多种,例如轮询、随即、加权轮训等,也能够为 Ribbon 实现自定义的负载平衡算法。

Ribbon 有以下个性:

  • 负载均衡器,可反对插拔式的负载平衡规定
  • 对多种协定提供反对,如 HTTP、TCP、UDP
  • 集成了负载平衡性能的客户端

Feign 利用 Ribbon 实现负载平衡的过程:

  • 通过在启动类加 @EnableFeignCleints 注解开启 FeignCleint
  • 依据 Feign 的规定实现接口,并加在接口定义处增加 @FeignCleint 注解
  • 服务启动后,扫描带有 @ FeignCleint 的注解的类,并将这些信息注入到 ioc 容器中
  • 当接口的办法被调用,通过 jdk 的代理,来生成具体的 RequesTemplate
  • RequesTemplate 再生成 Request
  • Request 交给 Client 去解决,其中 Client 能够是 HttpUrlConnection、HttpClient 也能够是 Okhttp
    最初 Client 被封装到 LoadBalanceClient 类,这个类联合类 Ribbon 做到了负载平衡。

  OpenFeign 中应用 Ribbon 进行负载平衡,所以 OpenFeign 间接内置了 Ribbon。在导入 OpenFeign 依赖后,无需再专门导入 Ribbon 依赖。接下来,咱们把 gitegg-service-base 作为服务的调用方,启动两个不同端口的 gitegg-service-system 作为服务的被调用方,测试 Ribbon 的负载平衡。
1、首先在 gitegg-service-system 工程中,新建被调用的 controller 办法,返回系统配置的端口号以辨别是哪个服务被调用了。

package com.gitegg.service.system.controller;

import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.dto.SystemDTO;
import com.gitegg.service.system.service.ISystemService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping(value = "system")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Api(tags = "gitegg-system")
@RefreshScope
public class SystemController {

    private final ISystemService systemService;

    @Value("${spring.datasource.maxActive}")
    private String nacosMaxActiveType;

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

    @GetMapping(value = "list")
    @ApiOperation(value = "system list 接口")
    public Object list() {return systemService.list();
    }


    @GetMapping(value = "page")
    @ApiOperation(value = "system page 接口")
    public Object page() {return systemService.page();
    }

    @GetMapping(value = "exception")
    @ApiOperation(value = "自定义异样及返回测试接口")
    public Result<String> exception() {return Result.data(systemService.exception());
    }

    @PostMapping(value = "valid")
    @ApiOperation(value = "参数校验测试接口")
    public Result<SystemDTO> valid(@Valid @RequestBody SystemDTO systemDTO) {return Result.data(systemDTO);
    }

    @PostMapping(value = "nacos")
    @ApiOperation(value = "Nacos 读取配置文件测试接口")
    public Result<String> nacos() {return Result.data(nacosMaxActiveType);
    }

    @GetMapping(value = "api/by/id")
    @ApiOperation(value = "Fegin Get 调用测试接口")
    public Result<Object> feginById(@RequestParam("id") String id) {return Result.data(systemService.list());
    }

    @PostMapping(value = "api/by/dto")
    @ApiOperation(value = "Fegin Post 调用测试接口")
    public Result<Object> feginByDto(@Valid @RequestBody SystemDTO systemDTO) {return Result.data(systemDTO);
    }

    @GetMapping("/api/ribbon")
    @ApiOperation(value = "Ribbon 调用测试接口")
    public Result<String> testRibbon() {return Result.data("当初拜访的服务端口是:" + serverPort);
    }
}

2、在 gitegg-service-system-api 工程中,编写应用 OpenFeign 调用 testRibbon 的公共办法

package com.gitegg.service.system.api.feign;

import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.api.dto.ApiSystemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "gitegg-service-system")
public interface ISystemFeign {

    /**
     * OpenFeign 测试 Get
     *
     * @param id
     * @return
     */
    @GetMapping("/system/api/by/id")
    Result<Object> querySystemById(@RequestParam("id") Long id);

    /**
     * OpenFeign 测试 Post
     *
     * @param apiSystemDTO
     * @return ApiSystemDTO
     */
    @PostMapping("/system/api/by/dto")
    Result<ApiSystemDTO> querySystemByDto(@RequestBody ApiSystemDTO apiSystemDTO);

    /**
     * OpenFeign 测试 Ribbon 负载平衡性能
     * @return
     */
    @GetMapping("/system/api/ribbon")
    Result<String> testRibbon();}

3、在 gitegg-service-base 中增加测试 Ribbon 负载平衡的 Feign 调用办法

package com.gitegg.service.base.controller;

import com.gitegg.platform.boot.common.base.Result;
import com.gitegg.service.system.api.dto.ApiSystemDTO;
import com.gitegg.service.system.api.feign.ISystemFeign;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping(value = "base")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Api(tags = "gitegg-base")
@RefreshScope
public class BaseController {

    private final ISystemFeign systemFeign;

    @GetMapping(value = "api/by/id")
    @ApiOperation(value = "Fegin Get 调用测试接口")
    public Result<Object> feginById(@RequestParam("id") Long id) {return Result.data(systemFeign.querySystemById(id));
    }

    @PostMapping(value = "api/by/dto")
    @ApiOperation(value = "Fegin Post 调用测试接口")
    public Result<Object> feginByDto(@Valid @RequestBody ApiSystemDTO systemDTO) {return Result.data(systemFeign.querySystemByDto(systemDTO));
    }

    @PostMapping(value = "api/ribbon")
    @ApiOperation(value = "Ribbon 调用测试接口")
    public Result<Object> testRibbon() {return Result.data(systemFeign.testRibbon());
    }
}

4、先启动 gitegg-service-base 服务,再启动 gitegg-service-system 服务,服务启动胜利之后,将 gitegg-service-system 下 bootstrap.yml 外面 server.port 改为 8011,而后再点击启动,这样就启动了两个 gitegg-service-system 服务(如果运行两个服务时提醒:gitegg-service-system is not allowed to run in parallel. Would you like to stop the running one?,这时,在 IDEA 中点击 Run-Edit configurations- 勾选 Allow parallel run 即可),服务全副启动结束之后,能够在 Console 窗口外面看到三个服务的 Console

三个服务:

5、关上浏览器拜访:http://127.0.0.1:8001/doc.html,点击 Ribbon 调用测试接口
菜单,进行测试,点击申请,咱们能够看到每次返回的端口都是变动的,一会儿是 8001 一会儿是 8011,因为 Ribbon 负载平衡默认是应用的轮询策略

6、如果咱们须要批改负载平衡策略或者自定义负载平衡策略,依据咱们的架构设计,咱们在 GitEgg-Platform 的子工程 gitegg-platform-cloud 中设置公共的负载平衡策略,而后每个微服务须要不同的策略的话,能够在本人的工程中增加配置文件。接下来,在 gitegg-platform-cloud 中新建 Ribbon 配置类

package com.gitegg.platform.cloud.ribbon.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description Ribbon 公共负载平衡策略配置
 */
@Configuration
public class RibbonConfig {

    /**
     * 负载平衡策略配置
     * @return
     */
    @Bean
    public IRule rule(){
        // 随机策略  从所有可用的提供者中随机抉择一个
        return new RandomRule();}

}

7、批改实现之后,GitEgg_Platform 工程从新执行 install,GitEgg_Cloud 刷新导入的包,参照步骤 5 再执行测试,这时咱们发现微服务返回的端口,不再是有法则的切换,而是随机不确定的呈现。

留神:

这里 RibbonConfig 只用于测试负载平衡策略,请不要在生产环境中这样应用,否则会呈现问题:在微服务 A 中调用微服务 B 和微服务 C,而后再调用微服务 B,这是 RibbonLoadBalancerClient 在获取微服务时,渠到的 serviceId 为 null,就会获取到上次的微服务,进而导致 404 谬误。因为 OpenFeign 默认应用的是 Ribbon 提供的负载平衡策略,咱们在理论利用中能够抉择 Nacos 提供的 NacosRule 策略,利用 Nacos 权重进行负载平衡:
  #负载平衡策略
  NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

本文源码在 https://gitee.com/wmz1930/GitEgg 的 chapter-12 分支。

正文完
 0