大型分佈式網絡架構設計與實踐筆記01. RPC

RPC

定義

RPC, Remote Process Call, 遠程方法調用.java

RPC 將本地調用轉變爲遠程服務器上的調用,給系統的處理能力和吞吐量無限制提高提供了可能,是實現分佈式計算的基礎。json

服務 Provider

擴容、服務隔離與分組 => 服務路由和負載均衡(router & load balance)瀏覽器

服務 consumer 經過 服務 provider的分組信息和地址信息進行路由,一般服務 provider 是一個集羣,須要採用必定負載均衡策略,選取其中一臺進行調用。服務器

對象的序列化

序列化與反序列化

序列化: 將對象轉化爲二進制流的過程。網絡

反序列化: 將二進制流轉化爲對象的過程。多線程

經常使用的解決方案

Java build-in、Google's Protocal Buffers、Hessian; JSON, XML。併發

  • Protocal Buffers: 高性能,跨平臺;須要編寫 proto 文件,沒法直接使用 Java 對象。
  • Hessian: 對各類語言的支持,性能穩定。
  • Java build-in: 無需引入第三方 jar、簡單;可是性能不高。
  • JSON/XML: 跨平臺,移動互聯網領域普遍使用.

基於 TCP 協議實現 RPC

能夠基於 Java 的 Socket API,實現一個簡單 RPC 調用.負載均衡

模型

基於 TCP 實現 RPC

Demo

|- ISayHellosocket

|-- SayHelloService分佈式

|-- TCPRPCConsumer

|-- TCPRPCProvider

package com.land.rpc;

public interface ISayHello {
    public String sayHello(String arg);
}
package com.land.rpc;

public class SayHelloService implements ISayHello {

    public String sayHello(String arg) {
        if ("hello".equals(arg)) {
            return "hello";
        }

        return "bye";
    }
}
package com.land.rpc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;

public class TCPRPCConsumer {

    public static void main(String[] args) throws NoSuchMethodException, IOException, ClassNotFoundException {
        final String interfaceName = ISayHello.class.getName();
        Method method = ISayHello.class.getMethod("sayHello", java.lang.String.class);
        Object[] methodArgs = {"hello"};
        Socket socket = new Socket("127.0.0.1", 4080);

        // 對象傳輸協議
        ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
        output.writeUTF(interfaceName);
        output.writeUTF(method.getName());
        output.writeObject(method.getParameterTypes());
        output.writeObject(methodArgs);

        ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
        // 阻塞式 I/O
        String result = (String)input.readObject();
        System.out.println(result);
    }
}
package com.land.rpc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class TCPRPCProvider {

    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Map<String, Object> services = new HashMap<String, Object>();
        services.put("com.land.rpc.ISayHello", new SayHelloService());

        final ServerSocket server = new ServerSocket(4080);
        while (true) {
            Socket socket = server.accept();
            ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
            String interaceName = input.readUTF();
            String methodName = input.readUTF();
            Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
            Object[] methodArgs = (Object[]) input.readObject();

            Object service = services.get(interaceName);

            Class<?> serviceInterfaceClass = Class.forName(interaceName);
            Method method = serviceInterfaceClass.getMethod(methodName, parameterTypes);
            Object result = method.invoke(service, methodArgs);
            ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
            output.writeObject(result);
        }
    }
}

基於 HTTP 協議實現 RPC

HTTP 請求與響應

  1. 瀏覽器根據所使用的 HTTP 協議,解析出 url 對應的域名。
  2. 經過 DNS 域名解析,查詢出改域名對應的 IP 地址。
  3. 經過 url 解析出端口號(默認80)。
  4. 瀏覽器發起並創建該 IP 的 該端口的鏈接。
  5. 瀏覽器向服務器發起 GET/POST 請求。
  6. 服務器響應瀏覽器的請求,瀏覽器讀取響應,渲染網頁。
  7. 瀏覽器關閉與服務器的鏈接。

經過 HttpClient 發送 HTTP 請求

若是使用 Socket API 來處理 HTTP 請求,一方面工做量比較大,效果還不必定好(底層的流處理,併發控制 etc)。 HttpClient 提供了一個成熟的解決方案。

###RPC: HTTP vs. TCP

Protocol 優勢 缺點
TCP 處於協議棧的下層,能夠對協議字段進行定製,減小網絡開銷字節數,下降網絡開銷,提升性能,實現更大的吞吐量和併發數 實現成本高(須要考慮多線程併發、鎖、I/O etc 複雜的底層細節),難以跨平臺
HTTP 不少成熟的容器已經很好處理, like. Tomcat, Apache, Jboss; 成熟的響應格式,like. JSON, XML 處於協議棧的上層,同等內容信息比 TCP的字節數多,效率相對要低 => gzip 改善

RESTful & RPC URL 連接風格

兩種主流的 URL:

風格 示例 備註
RPC http://hostname/provider.do?service=com.http.sayhello&format=json&timestamp=2016-09-05-20-36-00&arg1=arg1&arg2=arg2 hostname/format/timestamp/args
RESTful POST http://hostname/people GET http://hostname/people/land PUT http://hostname/people/land DELETE http://hostname/people/land RESTful = Representational State Transfer, 表現層狀態轉換. 利用了 HTTP 協議裏的幾種操做. POST: 建立,GET: 返回,PUT: 更新,DELETE: 刪除
變通 POST arg1=hello arg2=123 URL http://hostname/provider/sayhelloservice/2016-09-05-20-36-00.json provider=服務提供方;sayhelloservice=服務接口名稱;.json=服務端返回的數據格式;2016-09-05-20-36-00=客戶端訪問的時間戳

實現 HTTP RPC

可使用 Servlet、Struts、Spring MVC 實現 HTTP RPC。

相關文章
相關標籤/搜索