【SpringCloud Alibaba】(四)使用 Feign 实现服务调用的负载均衡

在上一文中,我们实现了服务的自动注册与发现功能。但是还存在一个很明显的问题:如果用户微服务和商品微服务在服务器上部署多份的话,之前的程序无法实现服务调用的负载均衡功能。

本文就带着大家一起实现服务调用的负载均衡功能

1. 负载均衡

负载均衡:将原本由一台服务器处理的请求根据一定的规则分担到多台服务器上进行处理。目前,大部分系统都实现了负载均衡的功能

负载均衡根据发生的位置,可以分为服务端负载均衡和客户端负载均衡

服务端负载均衡

服务端负载均衡指的是在服务端处理负载均衡的逻辑,如下图所示:

在这里插入图片描述
负载均衡在服务端进行处理,当客户端访问服务端的服务 A 时,首先访问到服务端的负载均衡器,由服务端的负载均衡器将客户端的请求均匀的分发到服务端部署的两个服务 A 上

客户端负载均衡

客户端负载均衡指的是在客户端处理负载均衡的逻辑,如下图所示:
在这里插入图片描述
负载均衡逻辑在客户端一侧,客户端应用调用服务端的应用 A 时,在向服务端发送请求时,就已经经过负载均衡的逻辑处理,并直接向服务端的某个服务发送请求

2. 启动多服务

为了实现服务调用的负载均衡功能,我们在本地的 IDEA 环境中分别启动两个用户微服务进程和两个商品微服务进程

2.1 启动多个用户/商品微服务

这里,我们在IDEA开发环境中启动多个用户微服务,其实也就是在同一台机器(服务器)上启动多个用户微服务。启动用户微服务时,默认监听的端口为 8060,主要由如下配置决定:

server:port: 8060

在同一台机器(服务器)上启动多个用户微服务时,只需要保证启动的多个用户微服务监听的端口号不同即可。

IDEA 中可以通过配置不同的端口号来启动多个相同的服务,如下所示,再配置一个用户微服务,使其端口号为 8061

在这里插入图片描述
按相同方式配置多个商品微服务。

配置好后,启动两个用户/商品微服务。打开 Nacos 的服务列表,如下所示:
在这里插入图片描述

3. 实现自定义负载均衡

这里,我们通过修改订单微服务的代码来实现自定义负载均衡

由于在整个项目中,订单微服务作为客户端存在,由订单微服务调用用户微服务和商品微服务,所以,这里采用的是客户端负载均衡的模式

3.1 随机负载均衡

修改 getServiceUrl() 方法,使其能够在多个服务地址中随机获取一个服务地址,而不总是获取第一个服务地址:

private String getServiceUrl(String serviceName){List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);int index = new Random().nextInt(instances.size());ServiceInstance serviceInstance = instances.get(index);String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();log.info("负载均衡后的服务地址为:{}", url);return url;
}

getServiceUrl() 方法中,首先通过服务的名称在 Nacos 中获取到所有的服务实例列表,然后使用随机函数随机生成一个 0 到服务列表长度减1的整数,而这个随机生成的整数恰好在服务实例列表的下标范围内,然后以这个整数作为下标获取服务列表中的某个服务实例。从而以随机的方式实现了负载均衡,并从获取到的服务实例中获取到服务实例所在服务器的 IP 地址和端口号,拼接成 IP:PORT 的形式返回

启动订单微服务,多次调用下单接口。

在订单微服务输出的日志信息中会存在如下所示的日志:

在这里插入图片描述

3.2 使用 Ribbon 实现负载均衡

Ribbon 是 SpringCloud 提供的一个能够实现负载均衡的组件,使用 Ribbon 能够轻松实现微服务之间调用的负载均衡

添加 @LoadBalanced 注解

@Configuration
public class LoadBalanceConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}}

修改 saveOrder() 方法:将 userUrl 修改为 userServer

// ...
User user = restTemplate.getForObject("http://"+ userServer + "/user/get/" + orderParamVo.getUserId(), User.class);Product product = restTemplate.getForObject("http://" + productServer + "/product/get/" + orderParamVo.getProductId(), Product.class);
// ...

启动的每个用户微服务和商品微服务都会打印相关的日志,说明使用Ribbon实现了负载均衡功能

3.3 使用 Fegin 实现负载均衡

Fegin 是 SpringCloud 提供的一个 HTTP 客户端,但只是一个声明式的伪客户端,它能够使远程调用和本地调用一样简单。阿里巴巴开源的 Nacos 能够兼容 Ribbon,而 Fegin 又集成了 Ribbon,所以,使用 Fegin也能够实现负载均衡。

修改订单微服务代码

1、在订单微服务的 pom.xml 文件中添加 Fegin 相关的依赖,如下所示:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2、在订单微服务上的主类添加 @EnableFeignClients 注解

3、添加 feign 包

用户接口:

@FeignClient("server-user")
public interface UserService {@GetMapping(value = "/user/get/{uid}")User getUser(@PathVariable("uid") Long uid);}

商品接口:

@FeignClient("server-product")
public interface ProductService {/*** 获取商品信息*/@GetMapping(value = "/product/get/{pid}")Product getProduct(@PathVariable("pid") Long pid);/*** 更新库存数量*/@GetMapping(value = "/product/update_count/{pid}/{count}")Result<Integer> updateCount(@PathVariable("pid") Long pid, @PathVariable("count") Integer count);}

4、修改下单接口

//...
User user = userService.getUser(orderParamVo.getUserId());
if (user == null){throw new RuntimeException("未获取到用户信息: " + JSONObject.toJSONString(orderParamVo));
}
// ...
Product product = productService.getProduct(orderParamVo.getProductId());
if (product == null){throw new RuntimeException("未获取到商品信息: " + JSONObject.toJSONString(orderParamVo));
}

启动订单微服务,多次调用下单接口。

启动的每个用户微服务和商品微服务都会打印相关的日志,说明使用Ribbon实现了负载均衡功能

代码地址

代码已经上传至码云,码云地址

其中,数据库文件位于 db 文件夹下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/13530.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

go常用知识点

go env -w GO111MODULEon go env -w GOPROXYhttps://goproxy.cn,direct 打包一个目录下的多个包时 go build ./… go install ./… 测试时&#xff0c;命令行&#xff1a;go test . //目录下所有单元测试都会执行 go test -v 目录 //测试覆盖率 go test -cover //使用cove…

LayUi 树形组件tree 实现懒加载模式,展开父节点时异步加载子节点数据

如题。 效果图&#xff1a; //lazy属性为true&#xff0c;点开时才加载 引用代码&#xff1a; <link href"~/Content/layui-new/css/layui.css" rel"stylesheet" /><form id"form" class"layui-form" style"margin-to…

自动驾驶和机器人学习和总结专栏汇总

汇总如下&#xff1a; 一. 器件选型心得&#xff08;系统设计&#xff09;--1_goldqiu的博客-CSDN博客 一. 器件选型心得&#xff08;系统设计&#xff09;--2_goldqiu的博客-CSDN博客 二. 多传感器时间同步方案&#xff08;时序闭环&#xff09;--1 三. 多传感器标定方案&…

AC695-按键处理-带UI

AC695-按键修改 消息发出 对应界面处理

【算法和数据结构】257、LeetCode二叉树的所有路径

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;首先看这道题的输出结果&#xff0c;是前序遍历。然后需要找到从根节点到叶子节点的所有路径&#xff…

C#设计模式之---适配器模式

适配器模式&#xff08;Adapter Pattern&#xff09; 适配器模式&#xff08;Adapter Pattern&#xff09;也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。适配器模式是一种结构型模式&#xff0c;一个适配使得因接口不兼容而不能在一起工作的类工作在一起…

【图论】树上差分(点差分)

一.题目 输入样例&#xff1a; 5 10 3 4 1 5 4 2 5 4 5 4 5 4 3 5 4 3 4 3 1 3 3 5 5 4 1 5 3 4 输出样例&#xff1a;9 二 .分析 我们可以先建一棵树 但我们发现&#xff0c;这样会超时。 所以&#xff0c;我们想到树上差分 三.代码 /* 5 10 3 4 1 5 4 2 5 4 5 4 5 4 3 5 …

IOS UICollectionView 设置cell大小不生效问题

代码设置flowLayout.itemSize 单元格并没有改变布局大小&#xff0c; 解决办法如下图&#xff1a;把View flow layout 的estimate size 设置为None&#xff0c;上面设置的itemSize 生效了。

WPF实战学习笔记29-登录数据绑定,编写登录服务

添加登录绑定字段、命令、方法 修改对象&#xff1a;Mytodo.ViewModels.ViewModels using Mytodo.Service; using Prism.Commands; using Prism.Events; using Prism.Mvvm; using Prism.Services.Dialogs; using System; using System.CodeDom.Compiler; using System.Collec…

原型设计模式go实现尝试

文章目录 前言代码结果总结 前言 本文章尝试使用go实现“原型”。 代码 package mainimport ("fmt" )// 不同原型标志枚举 type Type intconst (PROTOTYPE_1 Type iotaPROTOTYPE_2 )// 原型接口 type IPrototype interface {Clone() IPrototypeMethod(value int)P…

物联网阀控水表计量准确度如何?

物联网阀控水表是一种新型的智能水表&#xff0c;它采用了先进的物联网技术&#xff0c;可以通过远程控制和监测水表的运行情况&#xff0c;实现更加精准的水量计量和费用结算。那么&#xff0c;物联网阀控水表的计量准确度如何呢&#xff1f;下面我们将从以下几个方面进行详细…

PHP 3des加解密新旧方法可对接加密

一、旧3des加解密方法 <?php class Encrypt_3DES {//加密秘钥&#xff0c;private $_key;private $_iv;public function __construct($key, $iv){$this->_key $key;$this->_iv $iv;}/*** 对字符串进行3DES加密* param string 要加密的字符串* return mixed 加密成…

地理信息系统(GIS)

地理信息系统&#xff08;GIS&#xff09; 1.1 地理信息系统1.1.1 GIS概述1.1.1.1 GIS的基本概念&#xff08;1&#xff09;地理信息。&#xff08;2&#xff09;信息系统。&#xff08;3&#xff09;地理信息系统。GIS的发展简史1.1.1.3 GIS的组成部分&#xff08;1&#xff0…

【SpringⅢ】Spring 的生命周期

目录 &#x1f96a;1 Bean 的作用域 &#x1f969;1.1 singleton&#xff1a;单例模式 &#x1f359;1.2 prototype&#xff1a;原型模式 &#x1f371;1.3 Bean 的其他作用域 &#x1f35c;2 Spring 生命周期(执行流程) &#x1f958;2.1 启动容器 &#x1f372; 2.2 读…

Logback日志输入到xxl-job日志中

前言 ​ 在xxl-job的任务中&#xff0c;如果需要把日志输入到xxl-job的日志文件里&#xff0c;需要使用XxlJobHelper.log来记录日志&#xff0c;这种方式才能在任务执行详情里面看到对应的日志。而有时候 习惯用Slf4j来记录日志&#xff0c;而通过slf4j打印的日志没办法在xxl-…

[小尘送书-第二期]《从零开始读懂量子力学》由浅入深,解释科学原理;从手机到超导,量子无处不在;从微观到宏观,遐想人生的意义!

大家好&#xff0c;我是小尘&#xff0c;欢迎关注&#xff0c;一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; 本文目录 一、前言二、作者简介三、内容简介四、抽奖方式五、名家推介写在最后 一、前…

小程序 表单验证

使用 WxValidate.js 插件来校验表单数据 常用实例方法 名称返回类型描述checkForm(e)boolean验证所有字段的规则&#xff0c;返回验证是否通过。valid()boolean返回验证是否通过。size()number返回错误信息的个数。validationErrors()array返回所有错误信息。addMethod(name…

[containerd] 在Windows上使用IDEA远程调试containerd, ctr, containerd-shim

文章目录 1. containerd安装2. 源码编译3. 验证编译的二进制文件是否含有调试需要的信息3.1. objdump工具验证3.2. file工具验证3.3. dlv工具验证 4. debug 1. containerd安装 [Ubuntu 22.04] 安装containerd 2. 源码编译 主要步骤如下&#xff1a; 1、从github下载containe…

GO学习之 通道(Channel)

GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 文章目录 GO系列前言一、Channel 简介二、初始化通道2.1 无缓冲通道2.2 有缓冲通道2.3 单向通道 三、通道操作3.1 关闭通道…

[Java] 单例设计模式详解

模式定义&#xff1a;保证一个类只有一个实例&#xff0c;并且提供一个全局访问点&#xff0c;时一种创建型模式 使用场景&#xff1a;重量级的对象&#xff0c;不需要多个实例&#xff0c;如线程池&#xff0c;数据库连接池 单例设计模式的实现 1.懒汉模式&#xff1a;延迟…