JAVA通訊(2)--實現簡單的RPC框架
一、RPC簡介
RPC,全稱為Remote Procedure Call,即遠端過程呼叫,它是一個計算機通訊協議。它允許像呼叫本地服務一樣呼叫遠端服務。它可以有不同的實現方式。如RMI(遠端方法呼叫)、Hessian、Http invoker等。另外,RPC是與語言無關的。 RPC示意圖
如上圖所示,假設Computer1在呼叫sayHi()方法,對於Computer1而言呼叫sayHi()方法就像呼叫本地方法一樣,呼叫 –>返回。但從後續呼叫可以看出Computer1呼叫的是Computer2中的sayHi()方法,RPC遮蔽了底層的實現細節,讓呼叫者無需關注網路通訊,資料傳輸等細節。
二、RPC框架的實現
上面介紹了RPC的核心原理:RPC能夠讓本地應用簡單、高效地呼叫伺服器中的過程(服務)。它主要應用在分散式系統。如Hadoop中的IPC元件。但怎樣實現一個RPC框架呢?
從下面幾個方面思考,僅供參考:
1.通訊模型:假設通訊的為A機器與B機器,A與B之間有通訊模型,在Java中一般基於BIO或NIO;。
2.過程(服務)定位:使用給定的通訊方式,與確定IP與埠及方法名稱確定具體的過程或方法;
3.遠端代理物件:本地呼叫的方法(服務)其實是遠端方法的本地代理,因此可能需要一個遠端代理物件,對於Java而言,遠端代理物件可以使用Java的動態物件實現,封裝了呼叫遠端方法呼叫;
4.序列化,將物件名稱、方法名稱、引數等物件資訊進行網路傳輸需要轉換成二進位制傳輸,這裡可能需要不同的序列化技術方案。如:protobuf,Arvo等。
三、Java實現RPC框架
1、實現技術方案
下面使用比較原始的方案實現RPC框架,採用Socket通訊、動態代理與反射與Java原生的序列化。
2、RPC框架架構
RPC架構分為三部分:
1)服務提供者,執行在伺服器端,提供服務介面定義與服務實現類。
2)服務中心,執行在伺服器端,負責將本地服務釋出成遠端服務,管理遠端服務,提供給服務消費者使用。
3)服務消費者,執行在客戶端,通過遠端代理物件呼叫遠端服務。
3、 具體實現
服務提供者介面定義與實現,程式碼如下:
public interface HelloService {
String sayHi(String name);
}
HelloServices介面實現類:
public class HelloServiceImpl implements HelloService {
public String sayHi(String name) {
return "Hi, " + name;
}
}
服務中心程式碼實現,程式碼如下:
public interface Server {
public void stop();
public void start() throws IOException;
public void register(Class serviceInterface, Class impl);
public boolean isRunning();
public int getPort();
}
服務中心實現類:
public class ServiceCenter implements Server {
private static ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static final HashMap<String, Class> serviceRegistry = new HashMap<String, Class>();
private static boolean isRunning = false;
private static int port;
public ServiceCenter(int port) {
this.port = port;
}
public void stop() {
isRunning = false;
executor.shutdown();
}
public void start() throws IOException {
ServerSocket server = new ServerSocket();
server.bind(new InetSocketAddress(port));
System.out.println("start server");
try {
while (true) {
// 1.監聽客戶端的TCP連線,接到TCP連線後將其封裝成task,由執行緒池執行
executor.execute(new ServiceTask(server.accept()));
}
} finally {
server.close();
}
}
public void register(Class serviceInterface, Class impl) {
serviceRegistry.put(serviceInterface.getName(), impl);
}
public boolean isRunning() {
return isRunning;
}
public int getPort() {
return port;
}
private static class ServiceTask implements Runnable {
Socket clent = null;
public ServiceTask(Socket client) {
this.clent = client;
}
public void run() {
ObjectInputStream input = null;
ObjectOutputStream output = null;
try {
// 2.將客戶端傳送的碼流反序列化成物件,反射呼叫服務實現者,獲取執行結果
input = new ObjectInputStream(clent.getInputStream());
String serviceName = input.readUTF();
String methodName = input.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
Object[] arguments = (Object[]) input.readObject();
Class serviceClass = serviceRegistry.get(serviceName);
if (serviceClass == null) {
throw new ClassNotFoundException(serviceName + " not found");
}
Method method = serviceClass.getMethod(methodName, parameterTypes);
Object result = method.invoke(serviceClass.newInstance(), arguments);
// 3.將執行結果反序列化,通過socket傳送給客戶端
output = new ObjectOutputStream(clent.getOutputStream());
output.writeObject(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (clent != null) {
try {
clent.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
客戶端的遠端代理物件:
public class RPCClient<T> {
public static <T> T getRemoteProxyObj(final Class<?> serviceInterface, final InetSocketAddress addr) {
// 1.將本地的介面呼叫轉換成JDK的動態代理,在動態代理中實現介面的遠端呼叫
return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[]{serviceInterface},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectOutputStream output = null;
ObjectInputStream input = null;
try {
// 2.建立Socket客戶端,根據指定地址連線遠端服務提供者
socket = new Socket();
socket.connect(addr);
// 3.將遠端服務呼叫所需的介面類、方法名、引數列表等編碼後傳送給服務提供者
output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(serviceInterface.getName());
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(args);
// 4.同步阻塞等待伺服器返回應答,獲取應答後返回
input = new ObjectInputStream(socket.getInputStream());
return input.readObject();
} finally {
if (socket != null) socket.close();
if (output != null) output.close();
if (input != null) input.close();
}
}
});
}
}
最後為測試類:
public class RPCTest {
public static void main(String[] args) throws IOException {
new Thread(new Runnable() {
public void run() {
try {
Server serviceServer = new ServiceCenter(8088);
serviceServer.register(HelloService.class, HelloServiceImpl.class);
serviceServer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
HelloService service = RPCClient.getRemoteProxyObj(HelloService.class, new InetSocketAddress("localhost", 8088));
System.out.println(service.sayHi("test"));
}
}
執行結果:
regeist service HelloService
start server
Hi, test
四、總結
RPC本質為訊息處理模型,RPC遮蔽了底層不同主機間的通訊細節,讓程序呼叫遠端的服務就像是本地的服務一樣。
五、可以改進的地方
這裡實現的簡單RPC框架是使用Java語言開發,與Java語言高度耦合,並且通訊方式採用的Socket是基於BIO實現的,IO效率不高,還有Java原生的序列化機制佔記憶體太多,執行效率也不高。可以考慮從下面幾種方法改進。
可以採用基於JSON資料傳輸的RPC框架;
可以使用NIO或直接使用Netty替代BIO實現;
使用開源的序列化機制,如Hadoop Avro與Google protobuf等;
服務註冊可以使用Zookeeper進行管理,能夠讓應用更加穩定。
—————————————————————————————————————————————————–
java架構師專案實戰,高併發叢集分散式,大資料高可用視訊教程,共760G
下載地址:
https://item.taobao.com/item.htm?id=555888526201
01.高階架構師四十二個階段高
02.Java高階系統培訓架構課程148課時
03.Java高階網際網路架構師課程
04.Java網際網路架構Netty、Nio、Mina等-視訊教程
05.Java高階架構設計2016整理-視訊教程
06.架構師基礎、高階片
07.Java架構師必修linux運維繫列課程
08.Java高階系統培訓架構課程116課時
+
hadoop系列教程,java設計模式與資料結構, Spring Cloud微服務, SpringBoot入門
—————————————————————————————————————————————————–
相關推薦
JAVA通訊(2)--實現簡單的RPC框架
一、RPC簡介 RPC,全稱為Remote Procedure Call,即遠端過程呼叫,它是一個計算機通訊協議。它允許像呼叫本地服務一樣呼叫遠端服務。它可以有不同的實現方式。如RMI(遠端方法呼叫)、Hessian、Http invoker等。另外,RPC是
Scala學習筆記(10)—— Akka 實現簡單 RPC 框架
1 Akka 介紹 目前大多數的分散式架構底層通訊都是通過RPC實現的,RPC框架非常多,比如前我們學過的Hadoop專案的RPC通訊框架,但是Hadoop在設計之初就是為了執行長達數小時的批量而設計的,在某些極端的情況下,任務提交的延遲很高,所有Hadoop的
一個簡單RPC框架是如何煉成的(IV)——實現RPC訊息的編解碼
之前我們制定了一個很簡單的RPC訊息 的格式,但是還遺留了兩個問題,上一篇解決掉了一個,還留下一個 我們並沒有實現相應的encode和decode方法,沒有基於可以跨裝置的字串傳輸,而是直接的記憶體變數傳遞。 現在的RPC request不支援帶引數的請求命令。如add(a,
一個簡單RPC框架是如何煉成的(III)——實現帶引數的RPC呼叫
上一篇,我們制定了一個很簡單的RPC訊息 的格式,但是還遺留了兩個問題 我們並沒有實現相應的encode和decode方法,沒有基於可以跨裝置的字串傳輸,而是直接的記憶體變數傳遞。 現在的RPC request不支援帶引數的請求命令。如add(a, b), 如何在RPC訊息中描述
使用Java實現簡易RPC框架
RPC其全程為Remote Process Call,即為遠端過程呼叫。RPC將傳統的本地呼叫轉換為呼叫遠端的伺服器的方法,給系統的處理能力和吞吐量帶來了極大的提升。 隨著專案的發展,業務越來越複雜,單個專案的話,會非常複雜,且不易維護,如果單個專案掛了
java 網路通訊socket實現簡單例項
Socket通訊的步驟 ① 建立ServerSocket和Socket ② 開啟連線到Socket的輸入/輸出流
BootNettyRpc:采用 Netty 實現的 RPC 框架
ofo 文件配置 RR 實現 端口 監控 ble tin cto 什麽是 BootNettyRpc?BootNettyRpc 是一個采用Netty實現的Rpc框架,適用於Spring Boot項目,支持Spring Cloud。 目前支持的版本為Spring Boot 1.
一個簡單RPC框架是如何煉成的(V)——引入傳輸層
開局篇我們說了,RPC框架的四個核心內容 RPC資料的傳輸。 RPC訊息 協議 RPC服務註冊 RPC訊息處理 接下來處理資料傳輸。實際應用場景一般都是基於socket。socket程式碼比較多,使用起來也比較麻煩。而且具體的傳輸
一個簡單RPC框架是如何煉成的(II)——制定RPC訊息
開局篇我們說了,RPC框架的四個核心內容 RPC資料的傳輸。 RPC訊息 協議 RPC服務註冊 RPC訊息處理 下面,我們先看一個普通的過程呼叫 class Client(object): def __init__(sel
一個簡單RPC框架是如何煉成的(I)——開局篇
開場白,這是一個關於RPC的相關概念的普及篇系列,主要是通過一步步的調整,提煉出一個相對完整的RPC框架。 RPC(Remote Procedure Call Protocol)——遠端過程呼叫協議,基於C/S模型。網路上有一篇文章寫得不錯,可以去了解一下相關概念深入淺出RPC 這裡,直接使
Java編寫基於netty的RPC框架
-c shu resp pre 覆蓋 數據處理 ofo 核心 用兩個 一 簡單概念 RPC: ( Remote Procedure Call),遠程調用過程,是通過網絡調用遠程計算機的進程中某個方法,從而獲取到想要的數據,過程如同調用本地的方法一樣. 阻塞IO :當阻塞
手寫簡單 rpc 框架
手寫簡單 rpc 框架 手寫簡單 rpc 框架 0 緣起 1 技術選型 2 框架思路 3 呼叫方式 3.1 定義服務 3.2 定義 bean
java集合類實現簡單的學生資訊管理系統
package jihe; import java.util.Scanner; public class Student { private String sno; private String sname; private int grade; private int age; private S
Java語言快速實現簡單MQ訊息佇列服務
目錄 MQ基礎回顧 主要角色 自定義協議 流程順序 專案構建流程 具體使用流程 程式碼演示 訊息處理中心 Broker 訊息處理中心服務 BrokerServer 客戶端 MqClient 測試MQ 小結
java 連結redis 實現簡單的查詢
1 新建maven專案 新增依賴 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schema
java基於jsoup實現簡單的圖片爬蟲並下載
2018年11月04日 17:20:32 小小申 閱讀數:4 標籤: jsoup java
netty實現的RPC框架
自己手擼了一個nettyRPC框架,希望在這裡給有興趣的同學們做個參考。 要想實現nettyrpc需要了解的技術要點如下: spring的自定義註解、spring的bean的有關初始化。 反射和動態代理的使用。 瞭解socket的使用。 瞭解zookeeper的使用。 瞭解nio原理。 瞭解netty的基本操
***Java中WebSocket實現簡單的聊天***
Java中WebSocket實現簡單的聊天 1 在pom.xml中新增Jar包依賴 <dependency> <groupId>org.springframework.boot</groupId> <arti
[Java] 原創ssm實現簡單的客戶管理系統
執行環境jdk8+tomcat8+mysql+eclipse專案技術spring+spring mvc+mybatis+bootstrap+jqueryjar包檔案jar包一併在專案裡面,匯入專案直接執行專案截圖執行截圖 http://localhost :8080/SSMB
JAVA用於List實現簡單的學生管理系統
作為一名JAVA的程式設計師,無論初學者也好大神也好,學生管理系統是個很好例子,初學者用陣列、list等來寫簡單的學生管理系統,大神則是用swing+資料庫做有介面的學生管理系統,廢話不多說,今天我就用List來實現學生管理系統。 學生管理系統主要針對學生,我