分布式架构网络通信(RPC,RMI) 03

news2025/1/11 20:04:44

文章目录

  • 1. 基本原理
  • 2. RPC 远程过程调用
  • 3. RMI 远程方法调用
  • 4. RMI代码实现
  • 4. BIO、NIO、AIO
    • 4.1 同步和异步
    • 4.2 阻塞和非阻塞
    • 4.3 BIO
    • 4.4 NIO
    • 4.5 AIO

1. 基本原理

要实现网络机器间的通讯,首先得来看看计算机系统网络通信的基本原理,在底层层面去看,网络通信需要做的就 是将流从一台计算机传输到另外一台计算机,基于传输协议和网络IO来实现,其中传输协议比较出名的有tcp、 udp等等,tcp、udp都是在基于Socket概念上为某类应用场景而扩展出的传输协议,网络IO,主要有bio、nio、 aio三种方式,所有的分布式应用通讯都基于这个原理而实现,只是为了应用的易用,各种语言通常都会提供一些更为贴近应用易用的应用层协议。

2. RPC 远程过程调用

RPC全称为remote procedure call,即远程过程调用。
借助RPC可以做到像本地调用一样调用远程服务,是一种进程间的通信方式

比如两台服务器A和B,A服务器上部署一个应用,B服务器上部署一个应用,A服务器上的应用想调用B服务器上的 应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据。

需要注意的是RPC并不是一个具体的技术,而是指整个网络远程调用过程。

RPC架构 一个完整的RPC架构里面包含了四个核心的组件,分别是ClientClient StubServer以及Server Stub,这个Stub可以理解为存根。

  1. 客户端(Client),服务的调用方。
  2. 客户端存根(Client Stub),存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远 程发送给服务方。
  3. 服务端(Server),真正的服务提供者。
  4. 服务端存根(Server Stub),接收客户端发送过来的消息,将消息解包,并调用本地的方法。
    在这里插入图片描述
    在这里插入图片描述(1)客户端(client)以本地调用方式(即以接口的方式)调用服务;
    (2) 客户端存根(client stub)接收到调用后,负责将方法、参数等组装成能够进行网络传输的消息体(将消息体对 象序列化为二进制);
    (3) 客户端通过sockets将消息发送到服务端;
    (4) 服务端存根( server stub)收到消息后进行解码(将消息对象反序列化);
    (5) 服务端存根( server stub)根据解码结果调用本地的服务;
    (6) 本地服务执行并将结果返回给服务端存根( server stub);
    (7) 服务端存根( server stub)将返回结果打包成消息(将结果消息对象序列化);
    (8) 服务端(server)通过sockets将消息发送到客户端;
    (9) 客户端存根(client stub)接收到结果消息,并进行解码(将结果消息发序列化);
    (10) 客户端(client)得到最终结果。 RPC的目标是要把2、3、4、7、8、9这些步骤都封装起来。

注意:无论是何种类型的数据,最终都需要转换成二进制流在网络上进行传输,数据的发送方需要将对象转换为二 进制流,而数据的接收方则需要把二进制流再恢复为对象。

在java中RPC框架比较多,常见的有Hessian、gRPC、Thrift、HSF (High Speed Service Framework)、Dubbo等,其实对 于RPC框架而言,核心模块 就是通讯和序列化

3. RMI 远程方法调用

Java RMI 指的是远程方法调用 (Remote Method Invocation),是java原生支持的远程调用 ,采用JRMP(Java Remote Messageing protocol)作为通信协议,可以认为是纯java版本的分布式远程调用解决方案, RMI主要用于不同虚拟机之间的通信,这些虚拟机可以在不同的主机上、也可以在同一个主机上,这里的通信可以理解为一个虚拟机上的对象调用另一个虚拟机上对象的方法。

客户端:
1)存根/桩(Stub):远程对象在客户端上
2) 远程引用层(Remote Reference Layer):解析并执行远程引用协议;
3)传输层(Transport):发送调用、传递远程方法参数、接收远程方法执行结果。

服务端:
1)骨架(Skeleton):读取客户端传递的方法参数,调用服务器方的实际对象方法, 并接收方法执行后的返回值;
2)远程引用层(Remote Reference Layer):处理远程引用后向骨架发送远程方法调用;
3)传输层(Transport):监听客户端的入站连接,接收并转发调用到远程引用层。

注册表(Registry):以URL形式注册远程对象,并向客户端回复对远程对象的引用。

在这里插入图片描述
在这里插入图片描述

4. RMI代码实现

服务端
1)定义Remote子接口,在其内部定义要发布的远程方法,并且这些方法都要Throws RemoteException
2)定义实现远程接口,并且继承:UnicastRemoteObject
3)启动服务器:依次完成注册表的启动和远程对象绑定。

客户端:
1)通过符合JRMP规范的URL字符串在注册表中获取并强转成Remote子接口对象;
2)调用这个Remote子接口对象中的某个方法就是为一次远程方法调用行为。

1.创建远程接口

import java.rmi.Remote; 
import java.rmi.RemoteException; /** * 远程服务对象接口必须继承Remote接口;同时方法必须抛出RemoteExceptino异常 */ 

public interface Hello extends Remote { 
	public String sayHello(User user) throws RemoteException;
}

2. 创建引用对象User实体类

import java.io.Serializable; 
/** * 引用对象应该是可序列化对象,这样才能在远程调用的时候:1. 序列化对象 2. 拷贝 3. 在网络中传输 * 4. 服务端反序列化 5. 获取参数进行方法调用; 这种方式其实是将远程对象引用传递的方式转化为值传递的方式 */ 
@Data
public class User implements Serializable {
	private String name; 
	private int age; 

3. 实现远程服务对象

import java.rmi.RemoteException; 
import java.rmi.server.UnicastRemoteObject; 
/** * 远程服务对象实现类写在服务端;必须继承UnicastRemoteObject或其子类 **/ 

public class HelloImpl extends UnicastRemoteObject implements Hello {
/** * 因为UnicastRemoteObject的构造方法抛出了RemoteException异常,因此这里默认的构造方法必须写,必须声明抛出RemoteException异常 * * @throws RemoteException */

private static final long serialVersionUID = 3638546195897885959L;

protected HelloImpl() throws RemoteException { 
	super(); // TODO Auto-generated constructor stub
	}
	
@Override public String sayHello(User user) throws RemoteException { System.out.println("this is server, hello:" + user.getName()); return "success";
}
}

4. 服务端程序

import java.net.MalformedURLException; 
import java.rmi.Naming; 
import java.rmi.RemoteException; 
import java.rmi.registry.LocateRegistry; /** * 服务端程序 **/ 

public class Server {
public static void main(String[] args) {
	try { 
	Hello hello = new HelloImpl(); 
	LocateRegistry.createRegistry(8080); 
	try {
		Naming.bind("//127.0.0.1:8080/zm", hello); 
	} catch (MalformedURLException e) { 
	e.printStackTrace();
}
	System.out.println("service bind already!!");
	} catch (RemoteException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
  1. 客户端程序
import java.net.MalformedURLException; 
import java.rmi.Naming; import 
java.rmi.NotBoundException; 
import java.rmi.RemoteException; /** * 客户端程序 * @author zm * */

public class Client { public static void main(String[] args) { 
try {
//在RMI服务注册表中查找名称为RHello的对象,并调用其上的方法 
	Hello hello = (Hello) Naming.lookup("//127.0.0.1:8080/zm");//获取远程对象 
	User user = new User(); user.setName("james");
	System.out.println(hello.sayHello(user));
} catch (MalformedURLException e) { // TODO Auto-generated catch block 	
    e.printStackTrace();
} catch (RemoteException e) { // TODO Auto-generated catch block 
	e.printStackTrace();
} catch (NotBoundException e) { // TODO Auto-generated catch block 	
  	e.printStackTrace();
}
}

启动服务端程序
客户端调用

4. BIO、NIO、AIO

4.1 同步和异步

同步(synchronize)、异步(asychronize)是指应用程序和内核的交互而言的.

同步: 指用户进程触发IO操作等待或者轮训的方式查看IO操作是否就绪。
同步举例: 银行取钱,我自己去取钱,取钱的过程中等待.

异步:当一个异步进程调用发出之后,调用者不会立刻得到结果。而是在调用发出之后,被调用者通过状态、通知来通知 调用者,或者通过回调函数来处理这个调用。

异步举例: 我请朋友帮我取钱,他取到钱后返回给我. (委托给操作系统OS, OS需要支持IO异步API)

4.2 阻塞和非阻塞

阻塞和非阻塞是针对于进程访问数据的时候,根据IO操作的就绪状态来采取不同的方式.
简单点说就是一种读写操作方法的实现方式. 阻塞方式下读取和写入将一直等待, 而非阻塞方式下,读取和写入方法会理解返回一个状态值.

阻塞:
ATM机排队取款,你只能等待排队取款(使用阻塞IO的时候,Java调用会一直阻塞到读写完成才返回。)

非阻塞:
柜台取款,取个号,然后坐在椅子上做其他事,等广播通知,没到你的号你就不能去,但你可以不断的问大堂经理 排到了没有。(使用非阻塞IO时,如果不能读写Java调用会马上返回,当IO事件分发器会通知可读写时再继续进行
读写,不断循环直到读写完成)

4.3 BIO

同步阻塞IO。B代表blocking

服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连 接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
适用场景:Java1.4之前唯一的选择,简单易用但资源开销太高

在这里插入图片描述

4.4 NIO

同步非阻塞IO (non-blocking IO / new io)是指JDK 1.4 及以上版本。 服务器实现模式为一个请求一个通道,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接 有IO请求时才启动一个线程进行处理。

通道(Channels)
NIO 新引入的最重要的抽象是通道的概念。Channel 数据连接的通道。 数据可以从Channel读到Buffer中,也可以 从Buffer 写到Channel中

缓冲区(Buffers)
通道channel可以向缓冲区Buffer中写数据,也可以像buffer中存数据。

选择器(Selector)
使用选择器,借助单一线程,就可对数量庞大的活动 I/O 通道实时监控和维护

当一个连接创建后,不会需要对应一个线程,这个连接会被注册到多路复用器,所以一个连接只需要一个线程即 可,所有的连接需要一个线程就可以操作,该线程的多路复用器会轮训,发现连接有请求时,才开启一个线程处
理。

4.5 AIO

异步非阻塞IO。A代表asynchronize 当有流可以读时,操作系统会将可以读的流传入read方法的缓冲区,并通知应用程序,对于写操作,OS将write方法的流 写入完毕是操作系统会主动通知应用程序。因此read和write都是异步 的,完成后会调用回调函数。

使用场景:连接数目多且连接比较长(重操作)的架构,比如相册服务器。重点调用了OS参与并发操作,编程比较复杂。Java7开始支持

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

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

相关文章

WSL桥接网络配置

仅做记录与分享,平台版本等不同无法指导更多。 一、需求 ubuntu虚拟机(WSL)桥接win11并且能联通外网(百度之类) 二、环境: 版本 Windows 11 专业版 版本号 23H2 安装日期 ‎2024/‎6/‎20 操作系统版本…

Mysql 集群搭建 05

文章目录 1. Mysql主从复制集群搭建1.1 主库配置1.2 从库配置 2. 分库分表2.1 拆分策略2.2 实现技术2.2.1 MyCat概述2.2.2 MyCat入门2.2.3 配置 schema.xml 3. 双主双从4. 双主双从读写分离 1. Mysql主从复制集群搭建 主从复制是指将主数据库的 DDL 和 DML 操作通过二进制日志…

有什么开放式耳机比较好用?耳机选购指南附赠五款开放式耳机推荐!

现在的耳机市场真的越来越多元了,最近的开放式耳机也是越来越火了,很多小伙伴都在后台开始问我,到底要怎么样才能选到一款比较合适自己的开放式耳机呢?开放式耳机现在这么多品牌,这么多的型号,真的很难选择…

如何评估自动化测试的效益

目录 自动化测试实施成本 自动化前期开发成本包括: 后期维护成本包括: 自动化测试执行次数 自动化测试实施成本比 其中“自动化测试收益”可能包括: “自动化测试成本”包括但不限于: 测试稳定性 可扩展性和可维护性 自动…

java拼接字符串的四种方法StringBuilder、StringBuffer、StringJoiner、String.join(x,x )

1.直接复制以下代码运行查看运行结果 import java.util.ArrayList; import java.util.List; import java.util.StringJoiner;public class Test {public static void main(String[] args) throws Exception {List<String> strs new ArrayList<>();strs.add("…

“等保测评:如何进行有效的安全漏洞管理与网络安全法规遵从“

随着网络环境的复杂性增加&#xff0c;安全漏洞管理成为企业信息安全管理体系中的关键环节。等保测评要求企业具备发现、评估、修复和监控安全漏洞的能力&#xff0c;以保障信息系统的安全稳定运行。本文将围绕“等保测评&#xff1a;如何进行有效的安全漏洞管理”这一主题&…

qrcode生成二维码并下载【带logo图标】【带文字描述】

qrcode官网地址&#xff1a;http://jeromeetienne.github.io/jquery-qrcode/ 结果图&#xff1a; 不带文字 带文字 遇到问题&#xff1a; 1、中文乱码&#xff1a;需要先将中文字体转码。 2、qrcode.js生成的二维码是没有白边的&#xff0c;需要重新绘制边框logo文字 3、将生成…

IoTDB 入门教程 实战篇④——C#示例(开源)

文章目录 一、前文二、新建C#项目三、NuGet安装四、示例源码五、查询数据六、参考 一、前文 IoTDB入门教程——导读 本文详细阐述了如何通过一个C#项目成功连接到IoTDB时序数据库&#xff0c;进而展示了如何向该数据库高效地写入数据以及执行精确的数据查询操作。 此示例旨在为…

ImportError: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20‘ 报错解决办法

1.查找 libstdc.so.6* find / -name libstdc.so.6*2.copy一个libstdc.so.6.0.19到/usr/lib64/下 cp /usr/lib64/libstdc.so.6 /usr/lib64/3.创建软连接 ln -sf /usr/lib64/libstdc.so.6.0.31 /usr/lib64/libstdc.so.6完毕&#xff01;

RISC-V (四)内存管理

本章目的&#xff1a; 对内存进一步的管理&#xff0c;实现动态的分配和释放。 实现page级别的内存分配和释放。 内存管理分类 -自动管理内存-栈&#xff08;stack&#xff09; -静态内存-全局变量/静态变量。放在数据段里面。 -动态管理内存-堆&#xff08;heap&#xff09;…

【Docker】LXC 容器操作实战

一、实战目的 通过 lxc 来完成容器的创建&#xff0c;体会容器并了解 docker 并不是容器的唯一实现。 自 docker 0.9 版本起&#xff0c;docker 除了继续支持 LXC 外&#xff0c;还开始引入自家的 libcontainer&#xff0c;试图打造更通用的底层容器虚拟化库。如今的 docker…

【EI稳定检索】第二届能源与化学工程国际会议(EACE 2024)

第二届能源与化学工程国际会议 2024 International Conference on Energy and Chemical Engineering 【1】会议简介 第二届能源与化学工程国际会议是一个旨在促进能源科学与化学工程领域学术交流与合作的重要平台。会议汇集了全球范围内的专家学者、研究人员及行业代表&#xf…

77.SAP ME - 数据库架构

目录 1.SAP ME的数据库 2.SAPMEINT的数据库 3.SAPMII的数据库 4.基于MSSQLSERVER或ORACLE的架构 5.基于HANA的架构 - 无ODS 1.SAP ME的数据库 WIP&#xff1a;在实时事务期间&#xff0c;SAP ME 在“在制品” (WIP) 数据库表中存储数据。ODS&#xff1a;可操作数据存储 (…

树莓派笔记22_小车:小车电机开环运动与opencv摄像头巡线

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: ​ Opencv 版本是4.5.1&#xff1a; ​ Python 版本3.7.3&#xff1a; 今日尝试搭建一台小…

车车科技合纵连横:股价今年以来跌超八成,公司看好未来市场份额

《港湾商业观察》黄懿 6月27日&#xff0c;Cheche Group Inc. (NASDAQ: CCG&#xff0c;下称“车车科技”)宣布&#xff0c;公司已与北京安鹏保险经纪有限公司&#xff08;“北京安鹏”&#xff09;建立战略合作伙伴关系。其中&#xff0c;北京安鹏是北京汽车集团有限公司&…

vllm部署的一些思考

vllm号称利用ray支持多机多卡的方式,链接如下 Distributed Inference and Serving — vLLMhttps://docs.vllm.ai/en/stable/serving/distributed_serving.html但是这种方式只是把非常大的模型如lamma 3.1 ,这个模型有405b,需要用多机多卡的方式进行分布式。 事实上,生产中…

C语言:扫雷游戏实现

一、扫雷游戏的分析和设计 扫雷游戏想必大家都玩过吧&#xff0c;初级的玩法是在一个9*9的棋盘上找到没有雷的格子&#xff0c;而今天我们就要做的就是9*9扫雷游戏的实现。 1、游戏功能和规则 使用控制台实现经典的扫雷游戏游戏可以通过菜单实现继续玩或者退出游戏扫雷的棋盘…

Git 安装教程

1、登录git 官方网站&#xff1a;https://git-scm.com/ 点击左边的 Downloads 或者 右边标识的下载标志&#xff0c;它根据电脑操作系统自动匹配版本 Downloads for Windows 2、以 windows 为例下载对应版本 网络有时可能不大好&#xff0c;阿里镜像下载超快。 下载好以后&a…

传统物流机械锁控的痛点与难点深度剖析

在当今全球化和高度竞争的商业环境中&#xff0c;物流行业作为经济发展的重要支撑&#xff0c;其高效、安全的运营至关重要。而物流锁控&#xff0c;作为保障货物在运输和存储过程中安全的关键环节&#xff0c;传统机械物流锁控方式却面临着诸多严峻的挑战&#xff0c;这些问题…

Linux系统服务——【web,http协议,apache服务和nginx服务】(sixteen day)

一、web基础以及http协议 1、web基本概念和常识 前端开发一般用uniapp. 1、Web:为用户提供的一种在互联网上浏览信息的服务&#xff0c;Web 服务是动态的、可交互的、跨平台的和图形化的。 2、Web 服务为用户提供各种互联网服务&#xff0c;这些服务包括信息浏览服务&#xf…