当前位置: 首页 > news >正文

微服务-网络模型与服务通信方式openfein

通信方式

网络模型

OSI的七层模型

1. 应用层
  • 作用:为应用程序提供网络服务,定义应用间通信的协议规范
  • 前后端例子:前端浏览器(如 Chrome)通过HTTP 协议向后端服务器发起接口请求(如获取用户信息的<font style="color:rgb(0, 0, 0);">GET /api/user</font>);后端通过同样的协议返回 JSON 格式的用户数据。常见协议还有 HTTPS(加密的 HTTP)、FTP(文件传输)等。
2. 表示层
  • 作用:负责数据的格式转换、加密 / 解密、压缩 / 解压缩,确保两端应用能识别相同格式的数据。
  • 前后端例子:前端将用户输入的中文姓名、密码等数据,通过JSON 格式封装(转换为标准数据格式);若涉及敏感信息(如密码),还会通过 ** 加密算法(如 MD5)** 处理后再传输;后端收到后解密、解析 JSON 格式,得到原始数据。
3. 会话层
  • 作用:建立、管理和维护应用间的通信会话(如长连接、会话同步)。
  • 前后端例子:用户登录后,后端会生成一个会话 ID(Session ID) 并通过 Cookie 传给前端;后续前端每次调用接口时,都会携带这个 Session ID,会话层负责 “识别这个用户的会话是否有效”,管理前后端的通信连接(比如超时断开后重新建立)。

在OSI五层模型中,把前三层归类为应用层

4. 传输层
  • 作用:建立端到端的可靠 / 不可靠数据传输,处理差错控制、流量控制。
  • 前后端例子:前端调用后端接口时,数据通过TCP 协议传输(确保数据完整、有序到达);若前端是移动端 App,也可能用UDP 协议(如实时聊天场景,追求速度牺牲部分可靠性)。传输层的 “端口号” 用于区分后端的不同服务(如后端 HTTP 服务监听 80 端口)。
5. 网络层
  • 作用:通过 IP 地址进行寻址,选择数据传输的路由(即 “走哪条路能到后端服务器”)。
  • 前后端例子:前端设备(如你的电脑)通过IP 地址(如后端服务器的公网 IP <font style="color:rgb(0, 0, 0);">111.222.333.444</font>)确定目标位置;网络层的路由器会根据 IP 路由表,把数据从你的网络 “转发” 到后端服务器所在的网络。

6. 数据链路层
  • 作用:负责相邻设备间的链路管理、数据帧的封装 / 解封装,使用 MAC 地址进行介质访问。
  • 前后端例子:你的电脑通过网卡(物理设备)的MAC 地址,在局域网内与路由器通信;数据链路层会把网络层的 IP 数据包封装成 “数据帧”,通过网线(或无线信号)传输到路由器,同时处理链路中的差错(如数据帧损坏重传)。
7. 物理层
  • 作用:定义物理介质的电气特性、传输速率等,负责比特流的实际传输(最底层的硬件传输)。
  • 前后端例子:你的电脑通过网线(双绞线)无线电磁波(WiFi),将数据的电信号 / 光信号传输到路由器;。常见物理设备有网线、网卡、中继器等

后端服务器也通过物理介质接收这些信号 为什么需要通过物理介质 现在的wifi不是无线的吗 比如我使用的是阿里云服务器和我的电脑

1. 物理层的核心:“比特流的物理传输” 必须依赖介质

物理层的作用是传输原始的比特流(0 和 1 的电信号、光信号等),无论 “有线” 还是 “无线”,都需要物理介质来承载这些信号:

  • 对于有线网络(如网线、光纤):通过铜导线的电信号、光纤的光信号来传输比特流,“网线、光纤” 就是物理介质。
  • 对于无线网络(WiFi):看似 “无线”,但实际上是通过电磁波(无线电波) 作为物理介质来传输信号的。你的电脑通过无线网卡发射 / 接收电磁波,路由器也通过电磁波转发信号 ——电磁波就是 WiFi 的 “物理介质”,它是客观存在的物理载体。

2. 以 “你用阿里云服务器和电脑” 为例,完整链路的物理介质拆解

当你在电脑上通过 WiFi 调用阿里云服务器的接口时,整个流程的物理介质是 “分段接力” 的:

  • 你的电脑 → 家里的路由器:通过电磁波(WiFi 的物理介质) 传输信号。
  • 家里的路由器 → 运营商机房:通过网线(双绞线,有线物理介质) 传输信号。
  • 运营商机房 → 阿里云服务器机房:通过光纤(有线物理介质,长距离传输用光纤更稳定) 传输信号。
  • 阿里云服务器机房内部:服务器通过网线连接到机房的交换机、路由器等设备,最终把信号传输到目标服务器的网卡上。

简言之,“无线” 只是传输方式的表象,其底层仍然依赖 “电磁波” 这种物理介质;而互联网的长距离传输(比如你到阿里云服务器),大多还是靠 “网线、光纤” 这些有线物理介质来保证稳定性和传输效率。物理层的 “物理介质” 是比特流传输的基础载体,缺一不可~

![](https://i-blog.csdnimg.cn/img_convert/4a68ac6cf4e970711cd0cde669305443.png)

问题

  • 当需要跨语言、跨平台通信,或对服务间耦合度要求低时,采用 HTTP 方式。HTTP 是应用层协议,不限制语言和技术栈,适合多语言异构系统或对外暴露 API 的场景。
  • 当服务间是同语言技术栈,且对通信性能、调用体验(如像本地方法调用)要求高时,采用 RPC 方式。RPC 更贴近 “进程间调用” 的体验,性能损耗小,适合内部服务的高频、低延迟通信。
  • Spring Cloud 倾向于 HTTP 方式(基于 RESTful 风格的 HTTP 通信,如 Feign 组件),因为它能很好地支持 Spring 生态的微服务架构,且兼容多语言场景的扩展性需求。

RestTemplate

RestTemplate 是 Spring 框架提供的HTTP 请求工具类,从 Spring 3.0 开始支持,用于简化 Java 代码中对 RESTful 服务的调用。它封装了 Apache HttpClient 等底层 HTTP 客户端的繁琐操作,提供了 GET、POST、PUT、DELETE 等 REST 风格请求的模板方法,让开发者能更便捷地发起 HTTP 通信(方便调用其他服务)。

作用

  • 简化 HTTP 请求流程:无需手动处理连接、请求头、响应解析等细节,通过简洁的 API 即可完成 RESTful 接口调用。
  • 统一 REST 操作模板:封装了 REST 风格的常用操作(如资源查询、新增、修改、删除),让代码更规范、易维护。

使用场景

  • 微服务间 HTTP 通信:在 Spring 生态的微服务架构中,服务间通过 RESTful 接口交互时,用 RestTemplate 可快速实现跨服务调用(如订单服务调用用户服务的接口)。
  • 调用外部 REST 接口:当需要调用第三方平台的 RESTful API(如支付接口、天气接口)时,RestTemplate 能便捷地发起请求并解析响应。
  • 内部系统的 REST 交互:企业内部系统间基于 REST 风格的接口通信,可通过 RestTemplate 简化开发,提升效率。

缺点:单独的RestTemplate 不能负载均衡,得手写配置,麻烦且不便于服务切换。

Ribbon

对服务之间发起请求做负载均衡

使用场景

  1. 服务注册:订单服务、库存服务(多实例)把自己的 IP 和端口注册到注册中心。
  2. 服务发现:订单服务 A 从注册中心获取 “库存服务” 的所有实例列表,本地缓存一份。
  3. 负载均衡:Ribbon 从库存服务实例列表中,按策略(如轮询、随机)选一个实例。
  4. 服务调用:通过 RestTemplate/openfein 向选中的库存服务实例发起 HTTP 请求。

实战

一、方式1:DiscoveryClient + 自实现负载均衡
流程
  1. 服务注册到Nacos
  2. 消费者通过DiscoveryClient获取服务实例列表
  3. 手动实现负载均衡选择实例
  4. 调用选中实例接口
YAML配置(消费者)
server:port: 8080  # 消费者端口spring:application:name: ribbon-consumer  # 消费者服务名cloud:nacos:discovery:server-addr: localhost:8848  # Nacos注册中心地址
核心代码
@RestController
public class ConsumerController {// 注入服务发现客户端,用于从注册中心获取服务实例信息@Autowiredprivate DiscoveryClient discoveryClient;// 注入普通的RestTemplate(未添加@LoadBalanced注解)// 仅用于发送HTTP请求,不具备自动负载均衡能力@Autowiredprivate RestTemplate restTemplate;@GetMapping("/call")public String callService() {// 1. 通过服务名从注册中心获取所有可用实例列表// 服务名"ribbon-producer"对应所有application.name为该值的服务实例// 返回结果例如:[192.168.1.10:9001, 192.168.1.11:9002, 127.0.0.1:9003]List<ServiceInstance> instances = discoveryClient.getInstances("ribbon-producer");// 2. 手动实现随机负载均衡策略// 创建随机数生成器,范围是实例列表的大小(0到列表长度-1)int randomIndex = new Random().nextInt(instances.size());// 根据随机索引从列表中选择一个服务实例ServiceInstance selectedInstance = instances.get(randomIndex);// 3. 拼接完整请求地址并调用服务// getUri()方法返回实例的基础地址(如http://192.168.1.10:9001)// 拼接具体接口路径(如/provider/hello)形成完整URLString requestUrl = selectedInstance.getUri() + "/provider/hello";// 使用RestTemplate发送GET请求,接收返回的字符串结果// 这里实际调用的是选中实例的接口(如http://192.168.1.10:9001/provider/hello)String result = restTemplate.getForObject(requestUrl, String.class);return "调用结果:" + result + "(来自实例:" + selectedInstance.getHost() + ":" + selectedInstance.getPort() + ")";}
}// RestTemplate配置类:用于创建并注册RestTemplate实例到Spring容器
@Configuration
public class RestTemplateConfig {// 注册一个普通的RestTemplate Bean// 不添加@LoadBalanced注解,因此不具备自动负载均衡能力// 只能通过完整URL(包含IP和端口)调用服务@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}
二、方式2:LoadBalancerClient + RestTemplate
流程
  1. 服务注册到Nacos
  2. 消费者通过LoadBalancerClient自动获取并选择实例(内置策略)
  3. 调用选中实例接口
YAML配置(消费者)
server:port: 8080spring:application:name: ribbon-consumercloud:nacos:discovery:server-addr: localhost:8848# 可选:配置负载均衡策略(默认轮询)loadbalancer:ribbon:enabled: true  # 启用Ribbon负载均衡(旧版Spring Cloud)
核心代码
@RestController
public class ConsumerController {// 注入负载均衡客户端,用于自动获取服务实例并实现负载均衡// 内部集成了Ribbon的负载均衡策略(默认轮询)@Autowiredprivate LoadBalancerClient loadBalancerClient;// 注入普通的RestTemplate(未添加@LoadBalanced注解)// 仅负责发送HTTP请求,不处理负载均衡逻辑@Autowiredprivate RestTemplate restTemplate;@GetMapping("/call")public String callService() {// 1. 通过服务名自动选择一个服务实例(内置负载均衡策略)// 方法内部会查询注册中心获取"ribbon-producer"的所有实例// 并根据默认的轮询策略(可配置)选择一个健康实例ServiceInstance selectedInstance = loadBalancerClient.choose("ribbon-producer");// 2. 拼接完整请求地址并调用服务// 从选中实例中获取基础URL(如http://192.168.1.11:9002)String baseUrl = selectedInstance.getUri().toString();// 拼接接口路径,形成完整请求地址String requestUrl = baseUrl + "/provider/hello";// 使用RestTemplate发送GET请求,获取接口返回结果String result = restTemplate.getForObject(requestUrl, String.class);return "调用结果:" + result + "(来自实例:" + selectedInstance.getHost() + ":" + selectedInstance.getPort() + ")";}
}// RestTemplate配置类
@Configuration
public class RestTemplateConfig {// 注册普通RestTemplate Bean(无@LoadBalanced注解)// 负载均衡逻辑由LoadBalancerClient单独处理,与RestTemplate解耦@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}
三、方式3:@LoadBalanced + RestTemplate
流程
  1. 服务注册到Nacos
  2. 消费者使用带@LoadBalancedRestTemplate
  3. 直接通过服务名调用,框架自动完成负载均衡和实例选择
YAML配置(消费者)
server:port: 8080spring:application:name: ribbon-consumercloud:nacos:discovery:server-addr: localhost:8848# 配置负载均衡策略(针对特定服务)loadbalancer:client:config:ribbon-producer:  # 服务名# 可选策略:RandomLoadBalancer(随机)、RoundRobinLoadBalancer(轮询)type: RandomLoadBalancer
核心代码
@RestController
public class ConsumerController {// 注入带有@LoadBalanced注解的RestTemplate// 该实例已被增强,具备自动负载均衡能力@Autowiredprivate RestTemplate loadBalancedRestTemplate;@GetMapping("/call")public String callService() {// 1. 直接使用服务名拼接请求路径// "ribbon-producer"是目标服务的application.name// RestTemplate会自动将服务名转换为具体实例的IP:端口String requestUrl = "http://ribbon-producer/provider/hello";// 2. 发起请求并获取结果(内部自动完成负载均衡)// 底层流程:// - 解析服务名"ribbon-producer"// - 从注册中心获取该服务的所有实例// - 根据配置的负载均衡策略(如随机、轮询)选择一个实例// - 替换服务名为实例的实际IP:端口,发起HTTP请求String result = loadBalancedRestTemplate.getForObject(requestUrl, String.class);return "调用结果:" + result;}
}// RestTemplate配置类
@Configuration
public class RestTemplateConfig {// 注册带有@LoadBalanced注解的RestTemplate// 该注解会触发Spring的自动配置,为RestTemplate添加负载均衡拦截器// 使得RestTemplate能够识别服务名并自动完成实例选择@LoadBalanced@Beanpublic RestTemplate loadBalancedRestTemplate() {return new RestTemplate();}
}
服务提供者provider的配置
# 服务提供者YAML(多实例启动时修改port后继续启动即可得到同一服务的多个实例(即可以去做负载均衡))
server:port: 9001  # 实例1端口,另一实例可设为9002spring:application:name: ribbon-producer  # 服务名,所有实例保持一致cloud:nacos:discovery:server-addr: localhost:8848

不同的负载均衡策略

OpenFeign-服务之间调用

OpenFeign 是 Spring Cloud 的声明式伪 HTTP 客户端,基于注解简化微服务间 HTTP 调用,默认集成 Ribbon 实现负载均衡,让开发者能像调用本地方法一样调用远程服务接口。

实战

一、服务端(Producer):暴露可被调用的接口

:::color4

  1. 服务端流程:启动服务端,暴露<font style="color:rgba(0, 0, 0, 0.85) !important;">/api/param/xxx</font>系列接口,若配置了 Nacos 则注册到注册中心。

:::

1. 依赖配置(pom.xml)

xml

<dependencies><!-- Spring Boot 基础依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Nacos 服务注册(可选,若需要注册到注册中心) --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
</dependencies>
2. YAML 配置(application.yml)

yaml

server:port: 8001  # 服务端端口
spring:application:name: openfeign-producer  # 服务名,消费端通过该名称调用cloud:nacos:discovery:server-addr: localhost:8848  # Nacos 注册中心地址(若使用)
3. Controller:定义可被调用的接口

java

运行

import org.springframework.web.bind.annotation.*;@RestController
public class ProducerController {// ① 基本类型参数:接收单个ID@GetMapping("/api/param/basic/{id}")public String basicParam(@PathVariable Long id) {return "基本类型参数:ID = " + id;}// ② 对象类型参数:接收User对象@PostMapping("/api/param/object")public String objectParam(@RequestBody User user) {return "对象类型参数:User = " + user;}// ③ 数组类型参数:接收ID数组@GetMapping("/api/param/array")public String arrayParam(@RequestParam Long[] ids) {StringBuilder sb = new StringBuilder("数组类型参数:");for (Long id : ids) {sb.append(id).append(", ");}return sb.toString();}// ④ 集合类型参数:接收ID列表@GetMapping("/api/param/list")public String listParam(@RequestParam List<Long> ids) {StringBuilder sb = new StringBuilder("集合类型参数:");for (Long id : ids) {sb.append(id).append(", ");}return sb.toString();}// 用于对象参数的实体类static class User {private Long id;private String name;// 省略getter/setter@Overridepublic String toString() {return "User{id=" + id + ", name='" + name + "'}";}}
}
二、消费端(Consumer):通过 OpenFeign 调用服务端

:::color4

  1. 消费端流程
    • 启动消费端,通过<font style="color:rgb(0, 0, 0);">@EnableFeignClients</font>开启 OpenFeign 功能;
    • 定义<font style="color:rgb(0, 0, 0);">ProducerFeignClient</font>接口,声明要调用的服务端接口及参数规则;
    • 在 Controller 中注入<font style="color:rgb(0, 0, 0);">ProducerFeignClient</font>,像调用本地方法一样发起远程请求;
    • OpenFeign 自动完成 “服务发现(若用 Nacos)、负载均衡、HTTP 请求发送、响应解析” 等操作。
  2. 参数传递与返回值
    • 基本类型、对象、数组、集合等参数通过 SpringMVC 注解(<font style="color:rgb(0, 0, 0);">@PathVariable</font><font style="color:rgb(0, 0, 0);">@RequestBody</font><font style="color:rgb(0, 0, 0);">@RequestParam</font>)声明,与服务端接口一一对应;
    • 返回值由 OpenFeign 自动解析为字符串或自定义对象。
  3. 超时配置:在<font style="color:rgba(0, 0, 0, 0.85) !important;">application.yml</font>中通过<font style="color:rgba(0, 0, 0, 0.85) !important;">feign.client.config</font>配置指定服务的超时时间,避免因服务端响应慢导致请求卡住。

:::

1. 依赖配置(pom.xml)

xml

<dependencies><!-- Spring Boot 基础依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- OpenFeign 核心依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- Nacos 服务发现(可选,若服务端注册到Nacos) --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
</dependencies>
2. YAML 配置(application.yml)

yaml

server:port: 8002  # 消费端端口
spring:application:name: openfeign-consumercloud:nacos:discovery:server-addr: localhost:8848  # Nacos 地址(若使用)
# OpenFeign 超时配置
feign:client:config:openfeign-producer:  # 针对服务端服务名的配置connectTimeout: 5000  # 连接超时(毫秒)readTimeout: 5000     # 读取超时(毫秒)
3. OpenFeign 客户端接口:方便controller直接调用
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;// 指定要调用的服务名:即这里会根据服务名去nacos找对应的实例ip地址
@FeignClient(name = "openfeign-producer")
public interface ProducerFeignClient {// ① 调用基本类型参数接口@GetMapping("/api/param/basic/{id}")String basicParam(@PathVariable("id") Long id);// 使用springmvc的相关注解,使得跟http调用方式类似,即这里会去// 组装成 http://openfeign-producer/api/param/basic/{id} 去调用另一个服务// ② 调用对象类型参数接口@PostMapping("/api/param/object")String objectParam(@RequestBody ProducerController.User user);// ③ 调用数组类型参数接口@GetMapping("/api/param/array")String arrayParam(@RequestParam("ids") Long[] ids);// ④ 调用集合类型参数接口@GetMapping("/api/param/list")String listParam(@RequestParam("ids") List<Long> ids);
}
4. 消费端 Controller:触发 OpenFeign 调用

java

运行

import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;@RestController
public class ConsumerController {private final ProducerFeignClient producerFeignClient;public ConsumerController(ProducerFeignClient producerFeignClient) {this.producerFeignClient = producerFeignClient;}// 测试基本类型参数传递@GetMapping("/call/basic/{id}")public String callBasic(@PathVariable Long id) {// 直接调用Feign接口,像本地方法一样,实际调用另一个服务的流程已经在ProducerFeignClient接口定义好了return producerFeignClient.basicParam(id);// 这里如果是写成:String result=producerFeignClient.basicParam(id); 则会得到返回结果}// 测试对象类型参数传递@PostMapping("/call/object")public String callObject(@RequestBody ProducerController.User user) {return producerFeignClient.objectParam(user);}// 测试数组类型参数传递@GetMapping("/call/array")public String callArray() {Long[] ids = {1L, 2L, 3L};return producerFeignClient.arrayParam(ids);}// 测试集合类型参数传递@GetMapping("/call/list")public String callList() {List<Long> ids = Arrays.asList(4L, 5L, 6L);return producerFeignClient.listParam(ids);}
}
5. 启动类:开启 OpenFeign 功能
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableFeignClients  // 开启OpenFeign客户端功能
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}
}
http://www.dtcms.com/a/392596.html

相关文章:

  • 如何快速定位局域网丢包设备?
  • 算法<java>——排序(冒泡、插入、选择、归并、快速、计数、堆、桶、基数)
  • 深入浅出CMMI:从混乱到卓越的研发管理体系化之路
  • Docker一键部署prometheus并实现飞书告警详解
  • 基于“开源AI大模型AI智能名片S2B2C商城小程序”的多平台资源位传播对直播营销流量转化的影响研究
  • 【设计模式】适配器模式 在java中的应用
  • 2013/07 JLPT听力原文 问题四
  • MyBatis 缓存体系剖析
  • MySQL 主从复制 + MyCat 读写分离 — 原理详解与实战
  • Vmake AI:美图推出的AI电商商品图编辑器,快速生成AI时装模特和商品图
  • Debian13 钉钉无法打开问题解决
  • 02.容器架构
  • Diffusion Model与视频超分(1):解读淘宝开源的视频增强模型Vivid-VR
  • 通过提示词工程(Prompt Engineering)方法重新生成从Ollama下载的模型
  • 有没有可以检测反爬虫机制的工具?
  • 大模型为什么需要自注意力机制?
  • 长度为K子数组中的最大和-定长滑动窗口
  • Linux安装Kafka(无Zookeeper模式)保姆级教程,云服务器安装部署,Windows内存不够可以看看
  • WEEX编译|续写加密市场叙事
  • 为 Element UI 表格增添排序功能
  • 点评项目(Redis中间件)第四部分缓存常见问题
  • 动态水印也能去除?ProPainter一键视频抠图整合包下载
  • DevSecOps 意识不足会导致哪些问题
  • LeetCode:27.合并两个有序链表
  • 适用于双节锂电池的充电管理IC选型参考
  • 格式说明符
  • 层数最深叶子节点的和(深度优先搜索)
  • 【git】安装和基本指令
  • 如何利用AI技术快速生成专业级的PPT和视频内容
  • Linux系统之----线程互斥与同步