<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    I want to fly higher
    programming Explorer
    posts - 114,comments - 263,trackbacks - 0

    參考

    簡介

    RPC,即 Remote Procedure Call(遠程過程調用),說得通俗一點就是:調用遠程計算機上的服務,就像調用本地服務一樣。
    RPC 可基于 HTTP 或 TCP 協議,Web Service 就是基于 HTTP 協議的 RPC,
    它具有良好的跨平臺性,但其性能卻不如基于 TCP 協議的 RPC。會兩方面會直接影響 RPC 的性能,一是傳輸方式,二是序列化。
    眾所周知,TCP 是傳輸層協議,HTTP 是應用層協議,而傳輸層較應用層更加底層,
    在數據傳輸方面,越底層越快,因此,在一般情況下,TCP 一定比 HTTP 快。
    就序列化而言,Java 提供了默認的序列化方式,但在高并發的情況下,
    這種方式將會帶來一些性能上的瓶頸,于是市面上出現了一系列優秀的序列化框架,比如:Protobuf、Kryo、Hessian、Jackson 等,
    它們可以取代 Java 默認的序列化,
    從而提供更高效的性能。
    為了支持高并發,傳統的阻塞式 IO 顯然不太合適,因此我們需要異步的 IO,即 NIO。
    Java 提供了 NIO 的解決方案,Java 7 也提供了更優秀的 NIO.2 支持,用 Java 實現 NIO 并不是遙不可及的事情,只是需要我們熟悉 NIO 的技術細節。
    我們需要將服務部署在分布式環境下的不同節點上,通過服務注冊的方式,
    讓客戶端來自動發現當前可用的服務,并調用這些服務。
    這需要一種服務注冊表(Service Registry)的組件,讓它來注冊分布式環境下所有的服務地址(包括:主機名與端口號)。
    

    應用、服務、服務注冊表之間的關系見下圖:
    


    每臺 Server 上可發布多個 Service,這些 Service 共用一個 host 與 port,
    在分布式環境下會提供 Server 共同對外提供 Service。此外,為防止 Service Registry 出現單點故障,因此需要將其搭建為集群環境。
    本文將為您揭曉開發輕量級分布式 RPC 框架的具體過程,
    該框架基于 TCP 協議,提供了 NIO 特性,提供高效的序列化方式,同時也具備服務注冊與發現的能力。
    根據以上技術需求,我們可使用如下技術選型:
    Spring:它是最強大的依賴注入框架,也是業界的權威標準。
    Netty:它使 NIO 編程更加容易,屏蔽了 Java 底層的 NIO 細節。
    Protostuff:它基于 Protobuf 序列化框架,面向 POJO,無需編寫 .proto 文件。
    ZooKeeper:提供服務注冊與發現功能,開發分布式系統的必備選擇,同時它也具備天生的集群能力。
    

    源代碼目錄結構

    • rpc-client
      • 實現了rpc的服務動態代理(RpcProxy)以及基于Netty封裝的一個客戶端網絡層(RpcClient)
    • rpc-common
      • 封裝了RpcRequest和RpcResponse,即rpc請求和響應的數據結構
      • 基于Netty提供了編解碼器
      • 提供了序列化反序列化等工具
    • rpc-registry
      • 提供了服務發現和注冊接口
    • rpc-registry-zookeeper
      • 基于zookeeper的服務發現和注冊接口
    • rpc-server
      • rpc服務器(RpcServer)的實現,用來監聽rpc請求以及向Zookeeper注冊服務地址
      • rpc服務本地調用
    • rpc-sample-api
      • rpc測試公共api服務接口
    • rpc-sample-client
      • rpc測試客戶端
    • rpc-sample-server
      • rpc測試服務啟動程序和服務實現

    啟動順序

    • 配置Zookeeper
      • 解壓zookeeper-3.4.9
      • 進入conf目錄,重命名zoo_sample.cfg為zoo.cfg(或者復制一份重命名)并修改一些配置選項如dataDir.另外可以看到默認的clientPort是2181
      • 將bin目錄加入環境變量PATH,這樣則可直接使用zkServer命令直接啟動
    • 啟動rpc-sample-server工程的下RpcBootstrap
    • 啟動rpc-sample-client工程下的測試程序HelloClient等

    關鍵實現和核心模塊分析

    • RpcBootstrap
      • 加載spring.xml實例化RpcServer
        • 兩個參數分別是rpc服務地址(127.0.0.1:8000)和基于ZooKeeper的服務注冊接口實現(使用ZkClient連接Zookeeper的2181端口)
      • 加載過程中,會首先調用setApplicationContext方法
        • 掃描com.xxx.rpc.sample.server下帶有@RpcService注解的類,本例是HelloServiceImpl和HelloServiceImpl2,即有兩個rpc服務類,其中HelloServiceImpl2加了一個版本號用來區分第一個服務類,掃描后放入handlerMap,即服務名和服務對象之間的映射map
      • 加載后,調用afterPropertiesSet方法
        • 啟動Netty服務端,監聽8000端口;channelpipeline增加編解碼器(RpcDecoder、RpcEncoder)和邏輯處理類(RpcServerHandler)
          • RpcEncoder,編碼器,消息格式為4個字節的消息長度和消息體;直接使用Protostuff進行序列化,編碼對象為RpcResponse
          • RpcDecoder,解碼器;已解決粘包問題;使用Objenesis和Protostuff繼續反序列化
          • RpcServerHandler,收到RpcRequest后直接從handlerMap找到對應的服務類反射進行方法調用(使用了CGLib);最后向客戶端寫入rpc響應,完畢則主動關閉連接(所以從這里看是短連接)
            • ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE)
              • 這行代碼相當于在rpc響應發送的這個操作完成之后關閉連接
            • 注意Netty強烈建議直接通過添加監聽器的方式獲取I/O操作結果;當I/O操作完成之后,I/O線程會回調ChannelFuture中GenericFutureListener#operationComplete方法
        • 綁定端口成功后,向Zookeeper注冊上面的兩個rpc服務

    ChannelFutureListener CLOSE = new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) {
                        future.channel().close();
                    }
    };
    

    • RpcProxy
      • 初始化亦通過加載spring.xml,指定了基于zookeeper的服務發現類ZooKeeperServiceDiscovery
      • create方法,主要使用了jdk的動態代理;當代理方法執行的時候,首先根據請求的服務名利用Zookeeper的服務發現接口獲取服務的address;然后封裝rpc請求調用Netty客戶端連接服務地址并發送
        • 關于RpcClient,同Netty服務端,需要設置channelpipeline的編解碼器和邏輯處理handler
        • Channel channel = future.channel();
          channel.writeAndFlush(request).sync();
          channel.closeFuture().sync();
          return response;
        • 注意上部分代碼,發送rpc請求后等待發送完畢;發送完畢后等待連接關閉,此時線程阻塞直到服務端發送完回復消息并主動關閉連接,線程繼續;所以這個例子并沒有會有request對不上reponse的問題,因為每次rpc調用都是短連接且當前執行線程掛起;另外服務端收到request的時候,也會用requestId作為response的requestId

    可改進地方

    • 本人覺得spring相對較厚重,所以將spring去掉,對象實例化和依賴注入用比較簡單的方式去處理;不過比較麻煩的是對于掃描@RpcService注解這部分需要手動處理
    • 目前該示例提供的兩個服務均是在同一個端口8000下的服務;如何測試不同的兩個服務在不同的端口?按照該例子的設計,一個RpcServer即一個rpc發布服務器,該監聽的端口下可以注冊不同很多服務(當然一個Netty server本身可以bind多個端口,這個暫時不考慮實現);如果需要增加不同的服務,則需要單獨啟動RpcServer并向Zookeeper注冊

    其他待調研rpc框架

    posted on 2017-02-13 21:41 landon 閱讀(2675) 評論(0)  編輯  收藏 所屬分類: ServerFrameworkNetWork
    主站蜘蛛池模板: 免费一级毛片不卡在线播放| 亚洲AV无码一区二区乱孑伦AS| 97久久精品亚洲中文字幕无码| 无遮挡呻吟娇喘视频免费播放| 在线观看人成视频免费| 久久久久se色偷偷亚洲精品av| 日韩精品福利片午夜免费观着| 亚洲一区欧洲一区| 国内自产少妇自拍区免费| 亚洲丶国产丶欧美一区二区三区| 性感美女视频免费网站午夜| 亚洲www77777| 免费人成在线观看网站视频| 一区二区三区免费视频网站| 国产亚洲精品va在线| 最近免费中文字幕大全高清大全1| 亚洲综合色丁香麻豆| 台湾一级毛片永久免费 | 日韩va亚洲va欧洲va国产| 免费看搞黄视频网站| 亚洲国产精品线观看不卡| 色视频色露露永久免费观看| 免费无码AV一区二区| 亚洲色婷婷一区二区三区| 久久国产精品成人片免费| 久久乐国产综合亚洲精品| 亚洲成网777777国产精品| 野花香在线视频免费观看大全| 亚洲天堂一区二区三区| 国产精品国产午夜免费福利看 | 国产成人人综合亚洲欧美丁香花 | 日本红怡院亚洲红怡院最新| 91大神免费观看| 亚洲色中文字幕在线播放| 亚洲精品色婷婷在线影院| 99久久精品免费视频| 日本亚洲高清乱码中文在线观看| 久久亚洲精品AB无码播放| 成年女人毛片免费观看97| 中国在线观看免费的www| 久久精品亚洲AV久久久无码|