文章目录

  • 实现注册中心-服务发现
    • 模拟掉线
    • 远程调用
      • 1.订单和商品模块的接口
        • 商品服务
        • 订单服务
      • 2.抽取实体类
      • 3.订单服务拿到需要调用服务的ip和端口
    • 负载均衡
      • 步骤1
      • 步骤2
      • 步骤3
      • 步骤4
    • 面试题:注册中心宕机,远程调用还能成功吗?
      • 1、调用过;远程调用不在依赖注册中心,可以通过
      • 2、没调用过:(第一次发起远程调用);不能通过


在这里插入图片描述

实现注册中心-服务发现

在这里插入图片描述使用@EnableDiscoveryClient开启服务发现功能

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient//开启服务发现功能
@SpringBootApplication
public class ProductApplication {public static void main(String[] args) {SpringApplication.run(ProductApplication.class, args);}
}

导入单元测试依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><!--只在test目录下生效-->
</dependency>

执行

import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.alibaba.nacos.api.exception.NacosException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;import java.util.List;@SpringBootTest
public class DiscoveryTest {@AutowiredDiscoveryClient discoveryClient;@Testvoid discoveryClientTest(){for (String service : discoveryClient.getServices()) {System.out.println("service = " + service);//获取ip+portList<ServiceInstance> instances = discoveryClient.getInstances(service);for (ServiceInstance instance : instances) {System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());}}/*service = qf-service-orderip:192.168.109.1;port = 8080ip:192.168.109.1;port = 8081service = qf-service-productip:192.168.109.1;port = 8181ip:192.168.109.1;port = 8180ip:192.168.109.1;port = 8182*/}@AutowiredNacosServiceDiscovery nacosServiceDiscovery;@Testvoid  nacosServiceDiscoveryTest() throws NacosException {for (String service : nacosServiceDiscovery.getServices()) {System.out.println("service = " + service);List<ServiceInstance> instances = nacosServiceDiscovery.getInstances(service);for (ServiceInstance instance : instances) {System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());}}/*service = qf-service-orderip:192.168.109.1;port = 8080ip:192.168.109.1;port = 8081service = qf-service-productip:192.168.109.1;port = 8181ip:192.168.109.1;port = 8180ip:192.168.109.1;port = 8182*/}
}

DiscoveryClient是spring的规范,NacosServiceDiscovery是nacos的

模拟掉线

在这里插入图片描述
运行nacosServiceDiscoveryTest()

service = qf-service-order
ip:192.168.109.1;port = 8080
service = qf-service-product
ip:192.168.109.1;port = 8181
ip:192.168.109.1;port = 8180
ip:192.168.109.1;port = 8182

远程调用

在这里插入图片描述

这里暂时使用RestTemplate实现远程调用
在这里插入图片描述

1.订单和商品模块的接口

先完善订单和商品模块的接口,完成启动各自项目后调用各自的接口即可

商品服务
import lombok.Data;
import java.math.BigDecimal;
@Data
public class Product {private Long id;private BigDecimal price;private String productName;private int num;
}
import com.qf.entity.Product;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import java.math.BigDecimal;@RestController
public class ProductController {@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long id){Product product = new Product();product.setId(id);product.setProductName("华为手机");product.setPrice(new BigDecimal(5000));product.setNum(100);return product;}
}
订单服务
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;@Data
public class Order {private Long id;private Long userId;private BigDecimal totalAmount;private String address;private List<Product> productList;
}

Controller

import com.qf.entity.Order;
import com.qf.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class OrderController {@Autowiredprivate OrderService orderService;@GetMapping("/create")public Order createOrder(@RequestParam("userId") Long userId,@RequestParam("productId") Long productId) {return orderService.createOrder(userId, productId);}
}

服务类

import com.qf.entity.Order;
import org.springframework.web.bind.annotation.RequestParam;public interface OrderService {Order createOrder(@RequestParam("userId") Long userId, @RequestParam("productId") Long productId);
}
import com.qf.entity.Order;
import com.qf.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;import java.math.BigDecimal;
import java.util.List;@Slf4j
@Component
public class OrderServiceImpl implements OrderService {@Overridepublic Order createOrder(Long userId, Long productId) {Order order = new Order();order.setId(1L);order.setUserId(userId);order.setTotalAmount(new BigDecimal(100));order.setAddress("北京");order.setProductList(null);return order;}
}

2.抽取实体类

因为在远程调用时要使用对方的实体类,所以直接将实体类单独放在一个项目(取名model)中
在services父项目中依赖model

<dependency><groupId>com.qf</groupId><artifactId>model</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

项目结构
在这里插入图片描述

3.订单服务拿到需要调用服务的ip和端口

配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class BeanConfig {@BeanRestTemplate restTemplate(){return new RestTemplate();}
}

订单服务类

import com.qf.entity.Order;
import com.qf.entity.Product;
import com.qf.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;@Slf4j
@Component
public class OrderServiceImpl implements OrderService {@Overridepublic Order createOrder(Long userId, Long productId) {Product product = getProductFromRemote(productId);Order order = new Order();order.setId(1L);order.setUserId(userId);order.setTotalAmount(new BigDecimal(100));order.setAddress("北京");order.setProductList(Arrays.asList(product));return order;}//远程调用@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;private Product getProductFromRemote(Long productId) {//1、获取到商品服务所在的所有机器IP+portList<ServiceInstance> instances = discoveryClient.getInstances("qf-service-product");//拿取第一个地址ServiceInstance instance = instances.get(0);//拼接远程URLString url = "http://" + instance.getHost() + ":" + instance.getPort() + "/product/" + productId;log.info("远程请求:{}", url);//2、给远程发送请求,自动将json格式转为对象Product product = restTemplate.getForObject(url, Product.class);return product;}
}

订单调用接口时,通过RestTemplate实现远程调用商品服务,在nacos中下线商品服务可以看到日志调用其他端口。
现在只是从nacos拿到商品服务第一个ip和端口,接下来通过负载均衡依次调用多个商品服务的ip和端口

负载均衡

在这里插入图片描述

步骤1

order添加依赖

<!--        单元测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><!--只在test目录下生效--></dependency>
<!--        nacos负载均衡--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>

步骤2

测试类

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;import java.util.List;@SpringBootTest
public class LoadBalancerTest {@AutowiredDiscoveryClient discoveryClient;@AutowiredLoadBalancerClient loadBalancerClient;@Testvoid Test(){List<ServiceInstance> instances = discoveryClient.getInstances("qf-service-product");ServiceInstance choose = loadBalancerClient.choose("qf-service-product");System.out.println(choose.getHost()+"-"+choose.getPort());choose = loadBalancerClient.choose("qf-service-product");System.out.println(choose.getHost()+"-"+choose.getPort());choose = loadBalancerClient.choose("qf-service-product");System.out.println(choose.getHost()+"-"+choose.getPort());choose = loadBalancerClient.choose("qf-service-product");System.out.println(choose.getHost()+"-"+choose.getPort());choose = loadBalancerClient.choose("qf-service-product");System.out.println(choose.getHost()+"-"+choose.getPort());choose = loadBalancerClient.choose("qf-service-product");System.out.println(choose.getHost()+"-"+choose.getPort());System.out.println();}
}

此时商品服务在线情况
在这里插入图片描述
输出

192.168.109.1-8181
192.168.109.1-8180
192.168.109.1-8082
192.168.109.1-8181
192.168.109.1-8180
192.168.109.1-8082

步骤3

在订单服务实现类中添加负载均衡代码

@Override
public Order createOrder(Long userId, Long productId) {Product product = getProductFromRemoteWithLoadBalance(productId);Order order = new Order();order.setId(1L);order.setUserId(userId);order.setTotalAmount(new BigDecimal(100));order.setAddress("北京");order.setProductList(Arrays.asList(product));return order;
}//负载均衡
@Autowired
private LoadBalancerClient loadBalancerClient;
// 完成负载均衡发送请求
private Product getProductFromRemoteWithLoadBalance(Long productId){//1、获取到商品服务所在的所有机器IP+portServiceInstance choose = loadBalancerClient.choose("qf-service-product");//远程URLString url = "http://"+choose.getHost() +":" +choose.getPort() +"/product/"+productId;log.info("远程请求:{}",url);//2、给远程发送请求Product product = restTemplate.getForObject(url, Product.class);return product;
}

打印

2025-02-20T07:24:15.842+08:00  INFO 40732 --- [qf-service-order] [nio-8080-exec-2] com.qf.service.Impl.OrderServiceImpl     : 远程请求:http://192.168.109.1:8181/product/22
2025-02-20T07:24:16.641+08:00  INFO 40732 --- [qf-service-order] [nio-8080-exec-1] com.qf.service.Impl.OrderServiceImpl     : 远程请求:http://192.168.109.1:8180/product/22
2025-02-20T07:24:17.349+08:00  INFO 40732 --- [qf-service-order] [nio-8080-exec-3] com.qf.service.Impl.OrderServiceImpl     : 远程请求:http://192.168.109.1:8082/product/22
2025-02-20T07:24:17.823+08:00  INFO 40732 --- [qf-service-order] [nio-8080-exec-4] com.qf.service.Impl.OrderServiceImpl     : 远程请求:http://192.168.109.1:8181/product/22
2025-02-20T07:24:18.311+08:00  INFO 40732 --- [qf-service-order] [nio-8080-exec-5] com.qf.service.Impl.OrderServiceImpl     : 远程请求:http://192.168.109.1:8180/product/22
2025-02-20T07:24:18.836+08:00  INFO 40732 --- [qf-service-order] [nio-8080-exec-6] com.qf.service.Impl.OrderServiceImpl     : 远程请求:http://192.168.109.1:8082/product/22
2025-02-20T07:24:19.697+08:00  INFO 40732 --- [qf-service-order] [nio-8080-exec-7] com.qf.service.Impl.OrderServiceImpl     : 远程请求:http://192.168.109.1:8181/product/22
2025-02-20T07:24:20.328+08:00  INFO 40732 --- [qf-service-order] [nio-8080-exec-8] com.qf.service.Impl.OrderServiceImpl     : 远程请求:http://192.168.109.1:8180/product/22

可以看到在轮询访问商品服务

步骤4

基于注解的负载均衡

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class BeanConfig {@BeanRestTemplate restTemplate(){return new RestTemplate();}@Bean@LoadBalancedRestTemplate restTemplateAndLoadBalanced(){return new RestTemplate();}
}

服务类

@Slf4j
@Component
public class OrderServiceImpl implements OrderService {@Overridepublic Order createOrder(Long userId, Long productId) {Product product = getProductFromRemoteWithLoadBalanceAnnotation(productId);Order order = new Order();order.setId(1L);order.setUserId(userId);order.setTotalAmount(new BigDecimal(100));order.setAddress("北京");order.setProductList(Arrays.asList(product));return order;}//负载均衡@AutowiredRestTemplate restTemplateAndLoadBalanced;//注解方式// 基于注解的负载均衡private Product getProductFromRemoteWithLoadBalanceAnnotation(Long productId){String url = "http://qf-service-product/product/"+productId;//2、给远程发送请求; service-product 会被动态替换Product product = restTemplateAndLoadBalanced.getForObject(url, Product.class);return product;}
}

在商品服务中打断点或打印,可以发现轮询的访问每个商品服务

面试题:注册中心宕机,远程调用还能成功吗?

在这里插入图片描述
一般情况下订单服务会先从注册中心拿到地址列表,在访问商品服务。为了不每次远程调用都访问注册中心,增加了实例缓存,实例缓存实时更新在注册中心中的地址列表。

1、调用过;远程调用不在依赖注册中心,可以通过

当订单服务从注册中心中拿过商品服务的列表后,因为放在了实例缓存中,所以当注册中心(nacos)关闭时,只要商品服务未关闭,仍然是可以继续访问的。

2、没调用过:(第一次发起远程调用);不能通过

重新开启nacos,重启所有的服务,但订单服务先不访问商品服务。
关闭nacos,订单服务访问商品服务,此时发生报错

2025-02-20T07:53:38.094+08:00 ERROR 30652 --- [qf-service-order] [nio-8080-exec-1] scoveryClientServiceInstanceListSupplier : Exception occurred while retrieving instances for service qf-service-productjava.lang.RuntimeException: Can not get hosts from nacos server. serviceId: qf-service-productat com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient.getInstances(NacosDiscoveryClient.java:72) ~[spring-cloud-starter-alibaba-nacos-discovery-2023.0.3.2.jar:2023.0.3.2]at org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient.getInstances(CompositeDiscoveryClient.java:54) ~[spring-cloud-commons-4.1.4.jar:4.1.4]at org.springframework.cloud.loadbalancer.core.DiscoveryClientServiceInstanceListSupplier.lambda$new$0(DiscoveryClientServiceInstanceListSupplier.java:64) ~[spring-cloud-loadbalancer-4.1.4.jar:4.1.4]at reactor.core.publisher.MonoCallable$MonoCallableSubscription.request(MonoCallable.java:137) ~[reactor-core-3.6.10.jar:3.6.10]...

所以当订单服务没调用过商品服务时(第一次发起远程调用),,此时nacos宕机,调用失败。


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

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

相关文章

【Python】数据可视化之热力图

热力图&#xff08;Heatmap&#xff09;是一种通过颜色深浅来展示数据分布、密度和强度等信息的可视化图表。它通过对色块着色来反映数据特征&#xff0c;使用户能够直观地理解数据模式&#xff0c;发现规律&#xff0c;并作出决策。 目录 基本原理 sns.heatmap 代码实现 基…

如何 正确使用 nrm 工具 管理镜像源

目录 nrm 是啥&#xff1f; nrm 的安装 查看你当前已有的镜像源 怎么切换到目标镜像源 添加镜像源 删除镜像源 测试镜像源速度 nrm 是啥&#xff1f; 镜像源&#xff1a;可以理解为&#xff0c;你访问或下载某jar包或依赖的仓库。 nrm&#xff08;Node Registry Manag…

关于对逾期提醒的定时任务~改进完善

Spring Boot 中实现到期提醒任务的定时Job详解在金融或借贷系统中&#xff0c;到期提醒是常见的功能需求。通过定时任务&#xff0c;可以定期扫描即将到期的借款记录&#xff0c;并生成或更新提醒信息。本文基于提供的三个JobHandler类&#xff08;FarExpireRemindJob、MidExpi…

springboot配置请求日志

springboot配置请求日志 一般情况下&#xff0c;接口请求都需要日志记录&#xff0c;Java springboot中的日志记录相对复杂一点 经过实践&#xff0c;以下方案可行&#xff0c;记录一下完整过程 一、创建日志数据模型 创建实体类&#xff0c;也就是日志文件中要记录的数据格式 …

Redis(50) Redis哨兵如何与客户端进行交互?

Redis 哨兵&#xff08;Sentinel&#xff09;不仅负责监控和管理 Redis 主从复制集群的高可用性&#xff0c;还需要与客户端进行有效的交互来实现故障转移后的透明连接切换。下面详细探讨 Redis 哨兵如何与客户端进行交互&#xff0c;并结合代码示例加以说明。 哨兵与客户端的交…

【.Net技术栈梳理】04-核心框架与运行时(线程处理)

文章目录1. 线程管理1.1 线程的核心概念&#xff1a;System.Threading.Thread1.2 现代线程管理&#xff1a;System.Threading.Tasks.Task 和 Task Parallel Library (TPL)1.3 状态管理和异常处理1.4 协调任务&#xff1a;async/await 模式2. 线程间通信2.1 共享内存与竞态条件2…

(JVM)四种垃圾回收算法

在 JVM 中&#xff0c;垃圾回收&#xff08;GC&#xff09;是核心机制之一。为了提升性能与内存利用率&#xff0c;JVM 采用了多种垃圾回收算法。本文总结了 四种常见的 GC 算法&#xff0c;并结合其优缺点与应用场景进行说明。1. 标记-清除&#xff08;Mark-Sweep&#xff09;…

论文阅读:VGGT Visual Geometry Grounded Transformer

论文阅读&#xff1a;VGGT: Visual Geometry Grounded Transformer 今天介绍一篇 CVPR 2025 的 best paper&#xff0c;这篇文章是牛津大学的 VGG 团队的工作&#xff0c;主要围绕着 3D 视觉中的各种任务&#xff0c;这篇文章提出了一种多任务统一的架构&#xff0c;实现一次输…

python编程:一文掌握pypiserver的详细使用

更多内容请见: python3案例和总结-专栏介绍和目录 文章目录 一、 pypiserver 概述 1.1 pypiserver是什么? 1.2 核心特性 1.3 典型应用场景 1.4 pypiserver优缺点 二、 安装与基本使用 2.1 安装 pypiserver 2.2 快速启动(最简模式) 2.3 使用私有服务器安装包 2.4 向私有服务…

Git reset 回退版本

- 第 121 篇 - Date: 2025 - 09 - 06 Author: 郑龙浩&#xff08;仟墨&#xff09; 文章目录Git reset 回退版本1 介绍三种命令区别3 验证三种的区别3 如果不小心git reset --hard将「工作区」和「暂存区」中的内容删除&#xff0c;刚才的记录找不到了&#xff0c;怎么办呢&…

ARM 基础(2)

ARM内核工作模式及其切换条件用户模式(User Mode, usr) 权限最低&#xff0c;运行普通应用程序。只能通过异常被动切换到其他模式。快速中断模式(FIQ Mode, fiq) 处理高速外设中断&#xff0c;专用寄存器减少上下文保存时间&#xff0c;响应周期约4个时钟周期。触发条件为FIQ中…

Flutter 性能优化

Flutter 性能优化是一个系统性的工程&#xff0c;涉及多个层面。 一、性能分析工具&#xff08;Profiling Tools&#xff09; 在开始优化前&#xff0c;必须使用工具定位瓶颈。切忌盲目优化。 1. DevTools 性能视图 DevTools 性能视图 (Performance View) 作用&#xff1a;…

Spring事件监听机制(三)

为了理解EvenListener注解的底层原理&#xff0c;我们可以自己实现一个类似的注解模拟实现。1.定义MyListener注解Target({ElementType.METHOD})Retention(RetentionPolicy.RUNTIME)public interface MyListener {}2.注解使用Componentstatic class SmsService {private static…

基于Springboot + vue3实现的小区物业管理系统

项目描述本系统包含管理员和用户两个角色。管理员角色&#xff1a;用户管理&#xff1a;管理系统中所有用户的信息&#xff0c;包括添加、删除和修改用户。房屋信息管理&#xff1a;管理房屋信息&#xff0c;包括新增、查看、修改和删除房屋信息。车辆信息管理&#xff1a;管理…

交叉熵和KL散度

这个问题之前我也是傻傻分不清&#xff0c;决定整理一下&#xff0c;用更印象深刻的方式让人记住。核心联系&#xff1a;交叉熵 KL 散度 真实分布的熵 交叉熵作为 “绝对” 度量&#xff0c;会综合真实分布的熵&#xff08;固有难度&#xff09;与预测误差&#xff0c;直接体…

HTML 各种事件的使用说明书

HTML 各种事件的使用说明书 1. HTML 事件简介 HTML事件是浏览器或用户在网页上执行的动作或发生的事情。当这些事件发生时&#xff0c;可以通过JavaScript来响应和处理这些事件&#xff0c;从而实现网页的交互功能。事件处理是Web前端开发中实现动态交互的核心机制。 基本概…

Kafka面试精讲 Day 10:事务机制与幂等性保证

【Kafka面试精讲 Day 10】事务机制与幂等性保证 在分布式消息系统中&#xff0c;如何确保消息不丢失、不重复&#xff0c;是系统可靠性的核心挑战。Kafka自0.11版本起引入了幂等性Producer和事务性消息机制&#xff0c;彻底解决了“至少一次”语义下可能产生的重复消息问题&am…

时序数据库简介和安装

一、简介1. 什么是时序数据库&#xff1f;时序数据库是专门用于存储和处理时间序列数据的数据库系统。时间序列数据是指按时间顺序索引的一系列数据点。每个数据点都包含&#xff1a;一个时间戳&#xff1a;记录数据产生的时间。一个或多个指标值&#xff1a;例如温度、湿度、C…

comfyUI 暴露网络restful http接口

https://zhuanlan.zhihu.com/p/686893291 暴露websocket接口。 打开开发者选项 如图

linux系统address already in use问题解决

linux系统上某个端口被占用&#xff0c;如何解决&#xff1f;1.找到占用的进程编号&#xff1a;netstat -tulnp | grep :80002.强制杀死该进程kill -9 80603其他说明&#xff1a;1.查找占用端口的进程&#xff0c;可以用&#xff1a;lsof -i :8001 # 或者使用 netstat -tulnp |…