分享一個基於thrift的java-rpc框架


簡單介紹

這是一個簡單小巧的Java RPC框架,適用於Java平台內、為系統之間的交互提供了、高性能、低延遲的方案。適合在集群數量偏少的情況下使用(50台以下集群環境)。當然、它也可以在大型集群環境下使用,由於未引入Zookeeper支持,所以它在大型集群環境下不夠成熟,例如服務發現以及監控都沒有做,但是作為RPC框架來用已經足夠,至少比使用rest、webservice等性能高得多,也比直接使用thrift、avro等方便的多。

為了讓它保持小巧、簡單,所以不打算引入Zookeeper支持,目前依賴較少,只要將其jar引入到項目中即可。我認為50台server組成的集群,已經可以滿足絕大部分需求,本人認為簡單才是最重要的。此框架並非成熟完整的解決方案,如果您需要更成熟完整的方案,請參考 http://dubbo.io/

背景以及需求

我們要對系統模塊進行拆分,從原系統移出,那么就需要尋找一個遠程調用工具。
1、基於HTTP(rest、webservice等) 主要是性能很差,單次請求延遲較高,而且組裝HTTP請求也比較麻煩,難以形成規范,所以此項被pass。
2、基於thrift,性能雖好,但是使用起來非常麻煩,需要頻繁的生成代碼,而且對Client開發者要求較高,需要自己寫連接池,長連接無法使用LVS還要寫負載均衡和容錯。而且thrift的服務端需要將業務邏輯全部放在一個接口(一個接口就需要發布一個服務,占用一個線程池),這將是個很惡心的事,所以也被pass。

正因為以上兩點,所以我打算自己寫一個框架。要求簡單小巧、依賴少、低延遲、高並發、支持集群、負載均衡、容錯。

如果你也在尋找這樣一個框架,那么很值得看一下。

框架詳解

我做完了這個框架,沒多久便發現了Dubbo,在看了Dubbo的設計以后,驚喜的發現此框架和Dubbo的核心功能幾乎一樣。

說起來很簡單,就是框架會在Client端代理一個接口,調用這個接口的方法,將發送遠程請求,參數序列化傳遞到遠程Server端,Server端處理業務邏輯,完成后、將返回結果序列化給Client端,作為被調用方法的返回值。因此整個過程對用戶是透明的。

項目底層使用thrift,這是為了使用thrift的各種Server模型(本人不擅長網絡開發,因此只能使用一種網絡框架),以此來支持高並發,低延遲。沒有使用Netty,原因是Netty較重,延遲要比thrift稍高一些,Netty適合處理高吞吐的異步IO,對於RPC的同步調用沒有好處。thrift是對IO和NIO的簡單封裝,性能非常好,thrift框架的代碼特別少,也便於日后擴展。

序列化工具使用kryo,這也是性能的關鍵,您也可以自己去查一下kryo相關資料,這里就不說他了,序列化結果很小,速度很快就是了。

框架依賴 thrift、kryo、commons-pool、spring-beans(其中kryo可以自行替換為您喜歡的序列化工具)

集群支持隨機負載均衡,輪詢負載均衡(您也可以自己寫負載均衡實現),優雅停機(kill pid不要加-9),容錯(集群某幾台掛掉並不影響服務)

線程模型 以ThriftThreadPoolServer、ThriftTThreadedSelectorServer 兩種為主,具體細節參考thrift(您也可以自己實現Server)

使用例子

服務端:
/appchina-rpc-test/src/main/java/main/Server.java

ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("/application-server.xml");
ctx.registerShutdownHook();
ctx.start();

/appchina-rpc-test/src/main/resources/application-server.xml

<bean id="servicePublisher" class="com.appchina.rpc.thrift.remote.base.ThriftServicePublisher">
    <property name="definitions">
        <!-- 需要發布的服務列表 -->
        <array>
            <!-- ServiceDefinition 定義了服務的信息 -->
            <bean class="com.appchina.rpc.remote.ServiceDefinition">
                <!-- 可選,用於區分不同實現類 -->
                <property name="serviceName" value="addServiceImpl"></property>
                <!-- 發布服務的接口 -->
                <property name="interfaceClass" value="com.appchina.rpc.test.api.AddService"></property>
                <!-- 發布服務實現類 -->
                <property name="implInstance">
                    <bean class="com.appchina.rpc.test.impl.AddServiceImpl" />
                </property>
            </bean> 
        </array>
    </property> 
</bean>  

<bean class="com.appchina.rpc.thrift.server.ThriftThreadPoolServer">
    <property name="processor" ref="servicePublisher"></property>
    <property name="port" value="9090"></property>
    <property name="minWorkerThreads" value="100"></property>
    <property name="workerThreads" value="500"></property>
    <property name="security" value="true"></property>
    <property name="stopTimeoutVal" value="3000"></property>
    <property name="clientTimeout" value="10000"></property>
    <property name="allowedFromTokens">
        <map>
            <entry key="DONGJIAN" value="DSIksduiKIOYUIOkYIOhIOUIOhjklYUI"></entry>
        </map>
    </property>
</bean> 

客戶端:
/appchina-rpc-test/src/main/java/main/Client.java

ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("/application-client.xml");
AddService addService = (AddService) ctx.getBean("addService");
addService.add(100);

/appchina-rpc-test/src/main/resources/application-client.xml

<bean id="factoryProvider" class="com.appchina.rpc.thrift.cluster.ThriftClientFactoryProvider">    
    <!-- server列表 -->       
    <property name="hostPorts"> 
        <list>                   
            <value>127.0.0.1:9090</value>                
            <value>127.0.0.1:9191</value>
        </list>
    </property>
    <!-- 請求超時,根據業務設置 -->
    <property name="timeout" value="60000"></property>
    <!-- 連接超時,超過這個時間無法創建連接的server將被設置為暫時無效,恢復時設置為有效   -->
    <property name="connectionTimeout" value="10000"></property>
    <!-- 如果服務端是NIO,需要啟用此配置 -->
    <property name="framed" value="false"></property>
    <!-- 安全選項 -->
    <property name="from" value="DONGJIAN"></property>
    <property name="token" value="DSIksduiKIOYUIOkYIOhIOUIOhjklYUI"></property>
</bean>


<!-- 關於集群的相關配置 -->   
<bean id="client" class="com.appchina.rpc.base.cluster.client.DistributeClient">   
    <property name="factoryProvider" ref="factoryProvider"></property>   
    <!-- 負載均衡實現類 -->   
    <property name="loadBalance">   
        <bean class="com.appchina.rpc.base.cluster.RoundrobinLoadBalance"></bean>   
    </property>   
    <!-- 心跳頻率,用於檢測Server可用性的間隔 -->  
    <property name="heartbeat" value="1000"></property>   
    <!-- 處理心跳的最大線程數,一般1個線程足夠 -->   
    <property name="maxHeartbeatThread" value="1"></property>   
    <!-- 連接池耗完直接重試,重試其他池子的次數,因此、maxWait的時間可能疊加 -->   
    <property name="retry" value="3"></property>                 
    <!-- 由於被借走時間不一樣,可能導致單個池子不夠用,建議這個值大一些,可以通過maxIdle來限制長連接數量 -->                          
    <property name="maxActive" value="300"></property>                  
    <!-- 最大空閑,當池內連接大於maxIdle,每次returnObject都會銷毀連接,maxIdle保證了長連接的數量 -->                  
    <property name="maxIdle" value="200"></property>                
    <!-- 最小空閑 -->              
    <property name="minIdle" value="5"></property>                  
    <!-- 等待連接池的時間 -->                
    <property name="maxWait" value="1000"></property>                   
    <!-- 連接使用多久之后被銷毀 -->               
    <property name="maxKeepMillis" value="-1"></property>                  
    <!-- 連接使用多少次之后被銷毀 -->                  
    <property name="maxSendCount" value="-1"></property>                  
</bean> 

<bean id="addService" class="com.appchina.rpc.thrift.remote.base.ThriftRemoteProxyFactory">  
    <property name="serviceName" value="addService"></property>     
    <property name="proxyInterface" value="com.appchina.rpc.test.api.AddService"></property>
    <property name="client" ref="client"></property>        
</bean>      

git:https://github.com/dongjian1029/java-rpc-thrift.git


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM