首頁>技術>

1、RPC1.1 RPC 定義

網際網路公司的系統有成千上萬個大大小小的服務組成,服務各自部署在不同的機器上,服務間的呼叫需要用到網路通訊,服務消費方每呼叫一個服務都要寫一坨網路通訊相關的程式碼,不僅複雜而且極易出錯。還要考慮新服務依賴老服務時如何呼叫老服務,別的服務依賴新服務的時候新服務如何釋出方便他人呼叫。如何解決這個問題呢?業界一般採用RPC遠端呼叫的方式來實現。

RPC

Remote Procedure Call Protocol 既 遠端過程呼叫,一種能讓我們像呼叫本地服務一樣呼叫遠端服務,可以讓呼叫者對網路通訊這些細節無感知,比如服務消費方在執行 helloWorldService.sayHello("sowhat") 時,實質上呼叫的是遠端的服務。這種方式其實就是RPCRPC思想在各大網際網路公司中被廣泛使用,如阿里巴巴的dubbo、噹噹的Dubbox 、Facebook 的 thrift、Google 的grpc、Twitter的finagle等。

1.2 RPC demo

說了那麼多,還是實現一個簡易版的RPC demo吧。

1.2.1 公共介面
public interface SoWhatService {    String sayHello(String name);  } 
1.2.2 服務提供者

介面類實現

public class SoWhatServiceImpl implements SoWhatService{ @Override public String sayHello(String name) {  return "你好啊 " + name; }}  

服務註冊對外提供者

/** * 服務註冊對外提供者 */public class ServiceFramework{ public static void export(Object service, int port) throws Exception {  ServerSocket server = new ServerSocket(port);  while (true)  {   Socket socket = server.accept();   new Thread(() ->   {    try    {     //反序列化     ObjectInputStream input = new ObjectInputStream(socket.getInputStream());     //讀取方法名     String methodName =(String) input.readObject();     //引數型別     Class<?>[] parameterTypes = (Class<?>[]) input.readObject();     //引數     Object[] arguments = (Object[]) input.readObject();     //找到方法     Method method = service.getClass().getMethod(methodName, parameterTypes);     //呼叫方法     Object result = method.invoke(service, arguments);     // 返回結果     ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());     output.writeObject(result);    } catch (Exception e)    {     e.printStackTrace();    }   }).start();  } }}

服務執行

public class ServerMain{ public static void main(String[] args) {  //服務提供者 暴露出介面  SoWhatService service = new SoWhatServiceImpl();  try  {   ServiceFramework.export(service, 1412);  } catch (Exception e)  {   e.printStackTrace();  } }}
1.2.3 服務呼叫者

動態代理呼叫遠端服務

/** * @author sowhat * 動態代理呼叫遠端服務 */public class RpcFunction{ public static <T> T refer(Class<T> interfaceClass, String host, int port) throws Exception {  return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass},    new InvocationHandler()    {     @Override     public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable     {      //指定 provider 的 ip 和埠      Socket socket = new Socket(host, port);      ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());      //傳方法名      output.writeObject(method.getName());      //傳引數型別      output.writeObject(method.getParameterTypes());      //傳引數值      output.writeObject(arguments);      ObjectInputStream input = new ObjectInputStream(socket.getInputStream());      //讀取結果      Object result = input.readObject();      return result;     }    }); }}

呼叫方法

public class RunMain{ public static void main(String[] args) {  try  {   //服務呼叫者 需要設定依賴   SoWhatService service = RpcFunction.refer(SoWhatService.class, "127.0.0.1", 1412);   System.out.println(service.sayHello(" sowhat1412"));  } catch (Exception e)  {   e.printStackTrace();  } }}
2、Dubbo 框架設計2.1 Dubbo 簡介

Dubbo 是阿里巴巴研發開源工具,主要分為2.6.x 跟 2.7.x 版本。是一款分散式、高效能、透明化的 RPC 服務框架,提供服務自動註冊、自動發現等高效服務治理方案,可以和Spring 框架無縫整合,它提供了6大核心能力:

1. 面向介面代理的高效能RPC呼叫

2. 智慧容錯和負載均衡

3. 服務自動註冊和發現

4. 高度可擴充套件能力

5. 執行期流量排程

6. 視覺化的服務治理與運維

呼叫過程

服務提供者 Provider 啟動然後向 Registry 註冊自己所能提供的服務。

服務消費者 Consumer 向Registry訂閱所需服務,Consumer 解析Registry提供的元資訊,從服務中透過負載均衡選擇 Provider呼叫。

服務提供方 Provider 元資料變更的話Registry會把變更推送給Consumer,以此保證Consumer獲得最新可用資訊。

注意點

ProviderConsumer 在記憶體中記錄呼叫次數跟時間,定時傳送統計資料到Monitor,傳送的時候是連線。

MonitorRegistry 是可選的,可直接在配置檔案中寫好,ProviderConsumer進行直連。

MonitorRegistry 掛了也沒事, Consumer 本地快取了 Provider 資訊。

Consumer 直接呼叫 Provider 不會經過 RegistryProviderConsumer這倆到 Registry之間是長連線。

2.2 Dubbo框架分層

如上圖,總的而言 Dubbo 分為三層。

Busines層:由使用者自己來提供介面和實現還有一些配置資訊。

RPC層:真正的RPC呼叫的核心層,封裝整個RPC的呼叫過程、負載均衡、叢集容錯、代理。

Remoting層:對網路傳輸協議和資料轉換的封裝。

如果每一層再細分下去,一共有十層。

介面服務層(Service):該層與業務邏輯相關,根據 provider 和 consumer 的業務設計對應的介面和實現。配置層(Config):對外配置介面,以 ServiceConfig 和 ReferenceConfig 為中心初始化配置。服務代理層(Proxy):服務介面透明代理,Provider跟Consumer都生成代理類,使得服務介面透明,代理層實現服務呼叫跟結果返回。服務註冊層(Registry):封裝服務地址的註冊和發現,以服務 URL 為中心。路由層(Cluster):封裝多個提供者的路由和負載均衡,並橋接註冊中心,以Invoker 為中心,擴充套件介面為 Cluster、Directory、Router 和 LoadBlancce。監控層(Monitor):RPC 呼叫次數和呼叫時間監控,以 Statistics 為中心,擴充套件介面為 MonitorFactory、Monitor 和 MonitorService。遠端呼叫層(Protocal):封裝 RPC 呼叫,以 Invocation 和 Result 為中心,擴充套件介面為 Protocal、Invoker 和 Exporter。資訊交換層(Exchange):封裝請求響應模式,同步轉非同步。以 Request 和Response 為中心,擴充套件介面為 Exchanger、ExchangeChannel、ExchangeClient 和 ExchangeServer。網路傳輸層(Transport):抽象 mina 和 netty 為統一介面,以 Message 為中心,擴充套件介面為 Channel、Transporter、Client、Server 和 Codec。資料序列化層(Serialize):可複用的一些工具,擴充套件介面為 Serialization、ObjectInput、ObjectOutput 和 ThreadPool。

他們之間的呼叫關係直接看下面官網圖即可。

3、Dubbo SPI 機制

Dubbo 採用 微核心設計 + SPI 擴充套件技術來搭好核心框架,同時滿足使用者定製化需求。這裡重點說下SPI

3.1 微核心

作業系統層面的微核心跟宏核心:

微核心Microkernel:是一種核心的設計架構,由儘可能精簡的程式所組成,以實現一個作業系統所需要的最基本功能,包括了底層的定址空間管理、執行緒管理、與程序間通訊。成功案例是QNX系統,比如黑莓手機跟車用市場。

宏核心Monolithic :把 程序管理、記憶體管理、檔案系統、程序通訊等功能全部作為核心來實現,而微核心則僅保留最基礎的功能,Linux 就是宏核心架構設計。

Dubbo中的廣義微核心:

思想是 核心系統 + 外掛,說白了就是把不變的功能抽象出來稱為核心,把變動的功能作為外掛來擴充套件,符合開閉原則,更容易擴充套件、維護。比如小霸王遊戲機中機體本身作為核心系統,遊戲片就是外掛。vscode、Idea、chrome等都是微核心的產物。

微核心架構其實是一直架構思想,可以是框架層面也可以是某個模組設計,它的本質就是將變化的部分抽象成外掛,使得可以快速簡便地滿足各種需求又不影響整體的穩定性。

3.2 SPI 含義

主流的資料庫有MySQL、Oracle、DB2等,這些資料庫是不同公司開發的,它們的底層協議不大一樣,那怎麼約束呢?一般就是定製統一介面,具體實現不管,反正面向相同的介面程式設計即可。等到真正使用的時候用具體的實現類就好,問題是哪裡找用那個實現類呢?這時候就採用約定好的法則將實現類寫到指定位置即可。

SPI 全稱為 Service Provider Interface,是一種服務發現機制。它約定在ClassPath路徑下的META-INF/services資料夾查詢檔案,自動載入檔案裡所定義的類。

3.3 SPI demo

介面:

package com.example.demo.spi;public interface SPIService {    void execute();}

實現類1:

public class SpiImpl1 implements SPIService{ @Override    public void execute() {        System.out.println("SpiImpl1.execute()");    }}

實現類2:

public class SpiImpl2 implements SPIService{ @Override    public void execute() {  System.out.println("SpiImpl2.execute()");    }}

配置路徑

呼叫載入類

package com.example.demo.spi;import sun.misc.Service;import java.util.Iterator;import java.util.ServiceLoader;public class Test {    public static void main(String[] args) {            Iterator<SPIService> providers = Service.providers(SPIService.class);        ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);        while(providers.hasNext()) {            SPIService ser = providers.next();            ser.execute();        }        System.out.println("--------------------------------");        Iterator<SPIService> iterator = load.iterator();        while(iterator.hasNext()) {            SPIService ser = iterator.next();            ser.execute();        }    }}
3.4 SPI原始碼追蹤

ServiceLoader.load(SPIService.class) 底層呼叫大致邏輯如下:

iterator.hasNext() 跟 iterator.next()底層呼叫大致如下:

3.5 Java SPI缺點不能按需載入,Java SPI在載入擴充套件點的時候,會一次性載入所有可用的擴充套件點,很多是不需要的,會浪費系統資源。獲取某個實現類的方式不夠靈活,只能透過 Iterator 形式獲取,不能根據某個引數來獲取對應的實現類。不支援AOP與依賴注入,JAVA SPI可能會丟失載入擴充套件點異常資訊,導致追蹤問題很困難。3.6 Dubbo SPI

JDK自帶的不好用Dubbo 就自己實現了一個 SPI,該SPI 可以透過名字例項化指定的實現類,並且實現了 IOC 、AOP 與 自適應擴充套件 SPI

key = com.sowhat.value

Dubbo 對配置檔案目錄的約定,不同於 Java SPI ,Dubbo 分為了三類目錄。

META-INF/services/ :該目錄下 SPI 配置檔案是為了用來相容 Java SPI 。

META-INF/dubbo/ :該目錄存放使用者自定義的 SPI 配置檔案。

META-INF/dubbo/internal/ :該目錄存 Dubbo 內部使用的 SPI 配置檔案。

使用的話很簡單 引入依賴,然後百度教程即可。

@Test void sowhat() {  ExtensionLoader<SPIService> spiService = ExtensionLoader.getExtensionLoader(SPIService.class);        //按需獲取實現類物件  SPIService demo1 = spiService.getExtension("SpiImpl1");  demo1.execute(); }
3.7 Dubbo SPI原始碼追蹤

ExtensionLoader.getExtension 方法的整個思路是 查詢快取是否存在,不存在則讀取SPI檔案,透過反射建立類,然後設定依賴注入這些東西,有包裝類就包裝下,執行流程如下圖所示:

說下重要的四個部分:

injectExtension IOC

查詢 set 方法,根據引數找到依賴物件則注入。

WrapperClass AOP

包裝類,Dubbo 幫你自動包裝,只需要某個擴充套件類的建構函式只有一個引數,並且是擴充套件介面型別,就會被判定為包裝類。

Activate

Active 有三個屬性,group 表示修飾在哪個端,是 provider 還是 consumer,value 表示在 URL引數中出現才會被啟用,order 表示實現類的順序。

3.8 Adaptive 自適應擴充套件

需求:根據配置來進行 SPI 擴充套件的載入後不想在啟動的時候讓擴充套件被載入,想根據請求時候的引數來動態選擇對應的擴充套件。實現:Dubbo用代理機制實現了自適應擴充套件,為使用者想擴充套件的介面 透過JDK 或者 Javassist 編譯生成一個代理類,然後透過反射建立例項。例項會根據本來方法的請求引數得知需要的擴充套件類,然後透過 ExtensionLoader.getExtensionLoader(type.class).getExtension(name)來獲取真正的例項來呼叫,看個官網樣例。

public interface WheelMaker {    Wheel makeWheel(URL url);}// WheelMaker 介面的自適應實現類public class AdaptiveWheelMaker implements WheelMaker {    public Wheel makeWheel(URL url) {        if (url == null) {            throw new IllegalArgumentException("url == null");        }     // 1. 呼叫 url 的 getXXX 方法獲取引數值        String wheelMakerName = url.getParameter("Wheel.maker");        if (wheelMakerName == null) {            throw new IllegalArgumentException("wheelMakerName == null");        }        // 2. 呼叫 ExtensionLoader 的 getExtensionLoader 獲取載入器        // 3. 呼叫 ExtensionLoader 的 getExtension 根據從url獲取的引數作為類名稱載入實現類        WheelMaker wheelMaker = ExtensionLoader.getExtensionLoader(WheelMaker.class).getExtension(wheelMakerName);        // 4. 呼叫實現類的具體方法實現呼叫。        return wheelMaker.makeWheel(URL url);    }}

檢視Adaptive註解原始碼可知該註解可用在方法上,Adaptive 註解在類上或者方法上有不同的實現邏輯。

7.8.1 Adaptive 註解在類上

Adaptive 註解在類上時,Dubbo 不會為該類生成代理類,Adaptive 註解在類上的情況很少,在 Dubbo 中,僅有兩個類被 Adaptive 註解了,分別是 AdaptiveCompiler 和 AdaptiveExtensionFactory,表示拓展的載入邏輯由人工編碼完成,這不是我們關注的重點。

7.8.2 Adaptive 註解在方法上

Adaptive 註解在方法上時,Dubbo 則會為該方法生成代理邏輯,表示拓展的載入邏輯需由框架自動生成,大致的實現機制如下:

載入標註有 @Adaptive 註解的介面,如果不存在,則不支援 Adaptive 機制;為目標介面按照一定的模板生成子類程式碼,並且編譯生成的程式碼,然後透過反射生成該類的物件;結合生成的物件例項,透過傳入的URL物件,獲取指定key的配置,然後載入該key對應的類物件,最終將呼叫委託給該類物件進行。
@SPI("apple")public interface FruitGranter {  Fruit grant();  @Adaptive  String watering(URL url);}---// 蘋果種植者public class AppleGranter implements FruitGranter {  @Override  public Fruit grant() {    return new Apple();  }  @Override  public String watering(URL url) {    System.out.println("watering apple");    return "watering finished";  }}---// 香蕉種植者public class BananaGranter implements FruitGranter {  @Override  public Fruit grant() {    return new Banana();  }  @Override  public String watering(URL url) {    System.out.println("watering banana");    return "watering success";  }}

呼叫方法實現:

public class ExtensionLoaderTest {  @Test  public void testGetExtensionLoader() {    // 首先建立一個模擬用的URL物件    URL url = URL.valueOf("dubbo://192.168.0.1:1412?fruit.granter=apple");    // 透過ExtensionLoader獲取一個FruitGranter物件    FruitGranter granter = ExtensionLoader.getExtensionLoader(FruitGranter.class)      .getAdaptiveExtension();    // 使用該FruitGranter呼叫其"自適應標註的"方法,獲取呼叫結果    String result = granter.watering(url);    System.out.println(result);  }}

透過如上方式生成一個內部類。大致呼叫流程如下:

4、Dubbo 服務暴露流程4.1 服務暴露總覽

Dubbo框架是以URL為匯流排的模式,執行過程中所有的狀態資料資訊都可以透過URL來獲取,比如當前系統採用什麼序列化,採用什麼通訊,採用什麼負載均衡等資訊,都是透過URL的引數來呈現的,所以在框架執行過程中,執行到某個階段需要相應的資料,都可以透過對應的KeyURL的引數列表中獲取。URL 具體的引數如下:

protocol:指的是 dubbo 中的各種協議,如:dubbo thrift http username/password:使用者名稱/密碼 host/port:主機/埠 path:介面的名稱 parameters:引數鍵值對

protocol://username:password@host:port/path?k=v

服務暴露從程式碼流程看分為三部分:

檢查配置,最終組裝成 URL

暴露服務到到本地服務跟遠端服務。

服務註冊至註冊中心。

服務暴露從物件構建轉換看分為兩步:

將服務封裝成Invoker

Invoker透過協議轉換為Exporter

4.2 服務暴露原始碼追蹤容器啟動,Spring IOC 重新整理完畢後呼叫 onApplicationEvent 開啟服務暴露,ServiceBean 。export 跟 doExport 來進行拼接構建URL,為遮蔽呼叫的細節,統一暴露出一個可執行體,透過ProxyFactory 獲取到 invoker。呼叫具體 Protocol 將把包裝後的 invoker 轉換成 exporter,此處用到了SPI。然後啟動伺服器server,監聽埠,使用NettyServer建立監聽伺服器。透過 RegistryProtocol 將URL註冊到註冊中心,使得consumer可獲得provider資訊。5、Dubbo 服務引用流程

Dubbo中一個可執行體就是一個invoker,所以 provider 跟 consumer 都要向 invoker 靠攏。透過上面demo可知為了無感呼叫遠端介面,底層需要有個代理類包裝 invoker。

服務的引入時機有兩種

餓漢式:

透過實現 Spring 的 InitializingBean 介面中的 afterPropertiesSet 方法,容器透過呼叫 ReferenceBean的 afterPropertiesSet 方法時引入服務。

懶漢式(預設):

懶漢式是隻有當服務被注入到其他類中時啟動引入流程。

服務引用的三種方式

本地引入:服務暴露時本地暴露,避免網路呼叫開銷。

直接連線引入遠端服務:不啟動註冊中心,直接寫死遠端Provider地址 進行直連。

透過註冊中心引入遠端服務:透過註冊中心抉擇如何進行負載均衡呼叫遠端服務。

服務引用流程

檢查配置構建map ,map 構建 URL ,透過URL上的協議利用自適應擴充套件機制呼叫對應的 protocol.refer 得到相應的 invoker ,此處

想註冊中心註冊自己,然後訂閱註冊中心相關資訊,得到provider的 ip 等資訊,再透過共享的netty客戶端進行連線。

當有多個 URL 時,先遍歷構建出 invoker 然後再由 StaticDirectory 封裝一下,然後透過 cluster 進行合併,只暴露出一個 invoker 。

然後再構建代理,封裝 invoker 返回服務引用,之後 Comsumer 呼叫的就是這個代理類。

呼叫方式

oneway:不關心請求是否傳送成功。Async非同步呼叫:Dubbo天然非同步,客戶端呼叫請求後將返回的 ResponseFuture 存到上下文中,使用者可隨時呼叫 future.get 獲取結果。非同步呼叫透過唯一ID 標識此次請求。Sync同步呼叫:在 Dubbo 原始碼中就呼叫了 future.get,使用者感覺方法被阻塞了,必須等結果後才返回。6、Dubbo 呼叫整體流程

呼叫之前你可能需要考慮這些事

consumer 跟 provider 約定好通訊協議,dubbo支援多種協議,比如dubbo、rmi、hessian、http、webservice等。預設走dubbo協議,連線屬於單一長連線NIO非同步通訊。適用傳輸資料量很小(單次請求在100kb以內),但是併發量很高。約定序列化模式,大致分為兩大類,一種是字元型(XML或json 人可看懂 但傳輸效率低),一種是二進位制流(資料緊湊,機器友好)。預設使用 hessian2作為序列化協議。consumer 呼叫 provider 時提供對應介面、方法名、引數型別、引數值、版本號。provider列表對外提供服務涉及到負載均衡選擇一個provider提供服務。consumer 跟 provider 定時向monitor 傳送資訊。

呼叫大致流程

客戶端發起請求來呼叫介面,介面呼叫生成的代理類。代理類生成RpcInvocation 然後呼叫invoke方法。ClusterInvoker獲得註冊中心中服務列表,透過負載均衡給出一個可用的invoker。序列化跟反序列化網路傳輸資料。透過NettyServer呼叫網路服務。服務端業務執行緒池接受解析資料,從exportMap找到invoker進行invoke。呼叫真正的Impl得到結果然後返回。

呼叫方式

oneway:不關心請求是否傳送成功,消耗最小。sync同步呼叫:在 Dubbo 原始碼中就呼叫了 future.get,使用者感覺方法被阻塞了,必須等結果後才返回。Async 非同步呼叫:Dubbo天然非同步,客戶端呼叫請求後將返回的 ResponseFuture 存到上下文中,使用者可以隨時呼叫future.get獲取結果。非同步呼叫透過唯一ID標識此次請求。7、Dubbo叢集容錯負載均衡

Dubbo 引入了ClusterDirectoryRouterLoadBalanceInvoker模組來保證Dubbo系統的穩健性,它們的關係如下圖:

服務發現時會將多個多個遠端呼叫放入Directory,然後透過Cluster封裝成一個Invoker,該invoker提供容錯功能。消費者代用的時候從Directory中透過負載均衡獲得一個可用invoker,最後發起呼叫。你可以認為Dubbo中的Cluster對上面進行了大的封裝,自帶各種魯棒性功能。7.1 叢集容錯

叢集容錯是在消費者端透過Cluster子類實現的,Cluster介面有10個實現類,每個Cluster實現類都會建立一個對應的ClusterInvoker物件。核心思想是讓使用者選擇性呼叫這個Cluster中間層,遮蔽後面具體實現細節

7.2 智慧容錯之負載均衡

Dubbo中一般有4種負載均衡策略。

RandomLoadBalance:加權隨機,它的演算法思想簡單。假設有一組伺服器 servers = [A, B, C],對應權重為 weights = [5, 3, 2],權重總和為10。現把這些權重值平鋪在一維座標值上,[0, 5) 區間屬於伺服器 A,[5, 8) 區間屬於伺服器 B,[8, 10) 區間屬於伺服器 C。接下來透過隨機數生成器生成一個範圍在 [0, 10) 之間的隨機數,然後計算這個隨機數會落到哪個區間上。預設實現LeastActiveLoadBalance:最少活躍數負載均衡,選擇現在活躍呼叫數最少的提供者進行呼叫,活躍的呼叫數少說明它現在很輕鬆,而且活躍數都是從 0 加起來的,來一個請求活躍數+1,一個請求處理完成活躍數-1,所以活躍數少也能變相的體現處理的快。RoundRobinLoadBalance:加權輪詢負載均衡,比如現在有兩臺伺服器 A、B,輪詢的呼叫順序就是 A、B、A、B,如果加了權重,A 比B 的權重是2:1,那現在的呼叫順序就是 A、A、B、A、A、B。ConsistentHashLoadBalance:一致性 Hash 負載均衡,將伺服器的 IP 等資訊生成一個 hash 值,將hash 值投射到圓環上作為一個節點,然後當 key 來查詢的時候順時針查詢第一個大於等於這個 key 的 hash 值的節點。一般而言還會引入虛擬節點,使得資料更加的分散,避免資料傾斜壓垮某個節點。如下圖 Dubbo 預設搞了 160 個虛擬節點。7.3 智慧容錯之服務目錄

關於 服務目錄Directory 你可以理解為是相同服務Invoker的集合,核心是RegistryDirectory類。具有三個功能。

從註冊中心獲得invoker列表。

監控著註冊中心invoker的變化,invoker的上下線。

重新整理invokers列表到服務目錄。

7.4 智慧容錯之服務路由

服務路由其實就是路由規則,它規定了服務消費者可以呼叫哪些服務提供者。條件路由規則由兩個條件組成,分別用於對服務消費者和提供者進行匹配。比如有這樣一條規則:

host = 10.20.153.14 => host = 10.20.153.12

該條規則表示 IP 為 10.20.153.14 的服務消費者只可呼叫 IP 為 10.20.153.12 機器上的服務,不可呼叫其他機器上的服務。條件路由規則的格式如下:

[服務消費者匹配條件] => [服務提供者匹配條件]

如果服務消費者匹配條件為空,表示不對服務消費者進行限制。如果服務提供者匹配條件為空,表示對某些服務消費者禁用服務。

8、設計RPC

通讀下Dubbo的大致實現方式後其實就可以依葫蘆畫瓢了,一個RPC框架大致需要下面這些東西:

服務的註冊跟發現的搞一個吧,你可以用ZooKeeper或者Redis來實現。接下來consumer發起請求的時候你的面向介面程式設計啊,用到動態代理來實現呼叫。多個provider提供相同服務你的用到LoadBalance啊。最終選擇一個機器後你的約定好通訊協議啊,如何進行序列化跟反序列化呢?底層就用現成的高效能Netty框架 NIO模式實現唄。服務開啟後的有monitor啊。

13
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 多執行緒場景下一種可靈活編排的軟體架構