程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 分享一個基於thrift的java-rpc框架,thriftjava-rpc框架

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

編輯:JAVA綜合教程

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


簡單介紹

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

為了讓它保持小巧、簡單,所以不打算引入Zookeeper支持。我認為50台server組成的集群,已經可以滿足絕大部分需求,所以簡單、小巧、高性能才是最重要的。如果你認為簡單不重要,或者成熟度是最重要的,那麼淘寶的Dubbo在等著你。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的同步調用沒有好處。Netty並不適合。您不用擔心thrift性能有問題,也不用擔心thrift框架太重,我做過測試,性能和直接使用soket通信幾乎不相上下,thrift框架的代碼特別少,僅僅是對soket的簡單封裝,框架非常輕便。

序列化工具使用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

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved