微服务负载均衡实践

news2024/11/16 17:32:49

概述

本文介绍微服务的服务调用和负载均衡,使用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

    @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

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

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.导入依赖

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

2.配置调用接口

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

@FeignClient(name = "service-product")
public interface ProductFeignClient {

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

 3.在启动类上激活feign

//激活feign
@EnableFeignClients
public class OrderApplication {

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

修改之前的Controller代码

@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;
    }

}

修改之后的代码

@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!

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

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

相关文章

华为Atlas 200I DK A2开发者套件--基础使用配置

文章目录 前言一、快速开始二、通过路由器联网三、USB相机总结 前言 Atlas 200I DK A2基础使用配置方法。准备好键鼠、显示器、网线、USB拓展器。 一、快速开始 下载最新官方Windows版本昇腾开发者套件一键制卡工具&#xff1a; https://ascend-repo.obs.cn-east-2.myhuaweic…

消除隐患 防患未然|AIRIOT智慧消防管理解决方案

随着科技的飞速发展和城市化进程的不断推进&#xff0c;消防安全问题逐渐凸显。传统消防手段在应对现代复杂多变的火灾事故时显得力不从心&#xff0c;面临着许多挑战和弊端&#xff1a; 监控能力不足&#xff1a;传统消防手段通常依赖于人力监控和报警系统&#xff0c;如消防员…

SpringBoot前后端分离jar包nginx配置https访问

背景&#xff1a;做微信支付回调需要用到https域名&#xff0c;服务器是linux系统&#xff0c;用nginx做反向代理 准备&#xff1a;阿里云、腾讯云或者自己生成的SSL证书&#xff0c;java是8086端口 一&#xff1a;安装nginx&#xff0c;以前博客有记录 二&#xff1a;安装SS…

MySQL学习路线

1 学习路线图 2 参考的文档&#xff1a; 民工哥技术之路菜鸟教程

ScaleButton缩放按钮的实现基于javascript,typescript的代码-复制即用

调用方法 newChestInstance(sp:cc.SpriteFrame,pos:cc.Vec3){var node = new cc.Node("New Sprite");var sprite = node.addComponent(cc.Sprite);node.parent = this.canvasRoot;sprite.spriteFrame = sp;sprite.node.position = pos;node.addComponent(ChestView);…

极客笔记-消息队列

rocketMq 如果nameserver都挂了&#xff0c;sdk缓存了topic信息&#xff0c;依旧可用&#xff0c;所有它是AP,即保证可用性跟分区容错性 Bzhan https://www.bilibili.com/video/BV1cf4y157sz?p30&spm_id_frompageDriver&vd_sourceb2ecb56ea9b8dabcf65d10396ff…

WPF实现签名拍照功能

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

低代码:时代的选择

低代码&#xff0c;作为一种快速开发应用的软件&#xff0c;将通用、可重复利用的代码形成组件化的模块&#xff0c;通过图形化的界面来拖拽组件并形成应用。低代码能够实现只写少量代码或不写代码&#xff0c;类似用“乐高积木”的方式来开发。 既减少了不必要的工作量&#x…

【硬件+软件】示波器的自动化控制

有没有这样一种情况&#xff0c;就是通过脚本控制你的测量设备&#xff0c;比如示波器&#xff0c;那是不是就可以不用人为的去分析数据&#xff0c;直接由脚本就可以完成整个操作了。 是的&#xff0c;有这样一种方式就可以&#xff0c;就是利用python中的pyvisa库&#xff0c…

TODO Vue typescript forEach的bug,需要再核實

forEach 一個string[]&#xff0c;只有最後一個匹配條件有效&#xff0c;其它條件無效。 所以&#xff0c;只能替換成普通的for循環。 console.log(taskList)// for (const _task of taskList.value) {// if (_task invoiceSendEmail) {// form.value.invoiceSendEmail…

license授权方案

文章目录 概要license文件内容架构流程图实现 概要 当我们的商业软件售卖给客户后&#xff0c;往往需要对分发出去的软件进行限制&#xff0c;比如指定使用者&#xff0c;限制软件使用有效时间&#xff0c;声明版权信息、限制软件使用磁盘大小等。很多场景又是离线使用&#x…

JMeter 随机数生成器简介:使用 Random 和 UUID 算法

在压力测试中&#xff0c;经常需要生成随机值来模拟用户行为。JMeter 提供了多种方式来生成随机值&#xff0c;本文来具体介绍一下。 随机数函数 JMeter 提供了多个用于生成随机数的函数&#xff0c;其中最常用的是 __Random 函数。该函数可以生成一个指定范围内的随机整数或…

Python名侦探柯南

文章目录 系列文章前言Turtle入门名侦探柯南尾声 系列文章 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want595.blog.csdn.net/…

Java中的日期类整理

文章目录 第一代日期Date类第二代日期Calendar类第三代日期LocalDateTime类4. Instant类 时间戳 第一代日期Date类 jdk1.0引入 1.第一代日期类 包含两个构造器&#xff0c;Date()和Date(long)&#xff1b; new Date()&#xff1b;精确到毫秒 Date(time)如果time是Long类型的会将…

数据库安全运维是什么意思?数据库安全运维系统用哪家好?

我们大家都直到数据在某些情况下容易丢失或被破坏&#xff0c;攻击者可能通过对数据库进行破坏或勒索等手段获取利益。所以保障数据库安全至关重要。今天我们就来聊聊数据库安全运维是什么意思&#xff1f;数据库安全运维系统用哪家好&#xff1f; 数据库安全运维是什么意思&…

如何使用Python实现发送邮件功能

目录 代码示例&#xff1a; 代码解释 注意事项&#xff1a; 总结&#xff1a; 在Python中&#xff0c;可以使用内置的smtplib库和email库来发送电子邮件。 代码示例&#xff1a; 下面是一个使用smtplib和email库来发送电子邮件的示例&#xff1a; import smtplib from …

一文带你快速掌握爬虫开发中的一些高级调试技巧

文章目录 1. 写在前面2. Reply XHR&#xff08;重新发起请求&#xff09;3. copy as fecth&#xff08;修改参数请求&#xff09;4. copy()复制变量5. Web网页全屏截图6. 控制台安装使用npm7. 控制台中引用上次执行结果8. 控制台表展示对象数组 1. 写在前面 做过爬虫开发的人都…

视频模板SDK,为企业带来无限创意与效率

在当今的数字化时代&#xff0c;视频已经成为了信息传播的主流方式之一&#xff0c;对于企业来说&#xff0c;制作高质量的视频已经成为了一项重要的业务需求。然而&#xff0c;制作一部高质量的企业视频需要耗费大量时间和金钱&#xff0c;对于许多企业来说是一个不小的负担。…

web漏洞挖掘指南-前端跨域漏洞

web漏洞挖掘指南 前端跨域漏洞 如果你对网络安全入门感兴趣&#xff0c;那么你需要的话可以点击这里&#x1f449;【入门&进阶全套282G学习资源包免费分享&#xff01;】 一、何为跨域 1.设想一种场景&#xff0c;一个恶意网站上嵌入了一个iframe标签去加载银行的登陆页…

求臻医学:重磅 共识发布

共识发布 近日&#xff0c;我国首个《胃癌分子残留病灶检测与临床应用中国专家共识&#xff08;2023版&#xff09;》[1]&#xff08;以下简称“共识”&#xff09;正式发表于《中华消化外科杂志》。 该共识由中国医师协会外科医师分会上消化道外科医师专家工作组发起&#xf…