聊聊RPC及其原理

  什麼是RPC? RPC是Remote Procedure Call的縮寫,像Client-Servier同樣的遠程過程調用,也就是調用遠程服務就跟調用本地服務同樣方便,通常用於將程序部署在不一樣的機器上,供客戶端進行調用。就像一個request-response調用系統同樣簡單。在面向對象編程的程序中,RPC也能夠用Remote method invocation(RMI)來展示。爲何用它呢,由於隨着分佈式結構的廣泛,愈來愈多的應用須要解耦,將不一樣的獨立功能部署發佈成不一樣的服務供調用。java

  它的主要流程是Client -> Client Stub -> Network -> Server Stub -> Server 執行完成以後再進行返回。web

  這裏邊比較重要的就是Clint Stub和Server Stub,他們主要的做用就是將調用的方法和參數進行編碼(Marshalling)序列化,將序列化後的數據經過網絡發送給Server Stub,而後等待Server回執。Server Stub將受到的序列化字節進行解碼(Unmarshaling)反序列化,而後再將參數傳入到對應到的方法中執行,將得出的結果計算出來以後再進行返回,返回的過程和正向的過程相似。編程

  那麼這個結構裏邊的內容這麼複雜,並且還須要保證數據的完整,網絡等因素,因此這塊有一個通信的標準就是IDL(Interface Description Language)接口定義語言,由於不少程序採用了不一樣的編程語言(Java,C, C++ etc.)和不一樣的操做系統(Windows, CentOs, RHEL etc.),要保證數據可以正常通信,而且不受語言和操做系統等限制,就有了它。好比Apache的Thrift 、Avro和Google的 Protocol Buffers、阿里的Dubbo等。小程序

  其實不少人早已經應用了它了,可是可能不知道,好比web service的WSDL。下面我就用一個小程序來建立一個簡單基於的WSDL的RPC。使用JDK的JAX-WS實現網絡

  接口類(定義了一個很是簡單的方法):編程語言

package com.hqs.rpc;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

/**
 * 接口
 * @author hqs
 *
 */
@WebService
@SOAPBinding(style = Style.RPC)
public interface IRPCService {
    @WebMethod
    public String RPCMethod(String str);
}

   實現類:分佈式

package com.hqs.rpc;

import javax.jws.WebService;

/**
 * 實現類
 * @author hqs
 *
 */
@WebService (endpointInterface = "com.hqs.rpc.IRPCService")
public class RPCServiceImpl implements IRPCService {

    @Override
    public String RPCMethod(String str) {
        System.out.println("service received:" + str);
        return "RPC Method invoked: " + str;
    }

}

  服務發佈類:ide

package com.hqs.rpc;

import javax.xml.ws.Endpoint;

/**
 * 發佈類
 * @author hqs
 *
 */
public class RPCPublisher {
    public static void main(String[] args) {
        //本身定義地址
        Endpoint.publish("http://localhost:9966/rpc", new RPCServiceImpl());
    }
}

  這個時候啓動服務類,而後就能夠經過地址http://localhost:9966/rpc?wsdl訪問WSDL文件了了:編碼

<?xml version="1.0" encoding="UTF-8"?>

<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. -->

<!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. -->

-<definitions name="RPCServiceImplService" targetNamespace="http://rpc.hqs.com/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://rpc.hqs.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">

<types/>


-<message name="RPCMethod">

<part type="xsd:string" name="arg0"/>

</message>


-<message name="RPCMethodResponse">

<part type="xsd:string" name="return"/>

</message>


-<portType name="IRPCService">


-<operation name="RPCMethod">

<input message="tns:RPCMethod" wsam:Action="http://rpc.hqs.com/IRPCService/RPCMethodRequest"/>

<output message="tns:RPCMethodResponse" wsam:Action="http://rpc.hqs.com/IRPCService/RPCMethodResponse"/>

</operation>

</portType>


-<binding type="tns:IRPCService" name="RPCServiceImplPortBinding">

<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>


-<operation name="RPCMethod">

<soap:operation soapAction=""/>


-<input>

<soap:body namespace="http://rpc.hqs.com/" use="literal"/>

</input>


-<output>

<soap:body namespace="http://rpc.hqs.com/" use="literal"/>

</output>

</operation>

</binding>


-<service name="RPCServiceImplService">


-<port name="RPCServiceImplPort" binding="tns:RPCServiceImplPortBinding">

<soap:address location="http://localhost:9966/rpc"/>

</port>

</service>

</definitions>

  接下來咱們就能夠寫客戶端類:url

package com.hqs.rpc;

import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

/**
 * 客戶端類
 * @author hqs
 *
 */
public class RPCClient {
    public static void main(String[] args) {
        try {
            URL url = new URL("http://localhost:9966/rpc?wsdl");
            QName qname = new QName("http://rpc.hqs.com/","RPCServiceImplService");
            Service service = Service.create(url, qname);
            IRPCService irpc = service.getPort(IRPCService.class);
            System.out.println(irpc.RPCMethod("client"));
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}

RPC Method invoked: client

  簡單的RPC就這麼實現了。其實目前實現上一些公司實現的比較複雜,分爲服務分爲provider和consumer,以及負責監控管理的provider,provider通常採用zookeeper單數集羣,用於管理和監控provider的服務註冊,由於provider可能部署在同一臺機器上的不一樣端口或者不一樣機器上,consumer經過zookeeper就能夠拿到provider的IP/接口/版本號/端口等信息,而後進行調用。

  好了,若是有不對的地方,請你們指正。

相關文章
相關標籤/搜索