QiuRPC通用網(wǎng)絡(luò)RPC框架
QiuRPC 參考手冊(cè)
一個(gè)通用的網(wǎng)絡(luò)RPC框架,它應(yīng)該包括如下功能:
具有服務(wù)的分層設(shè)計(jì),借鑒Future/Service/Filter概念
2.具有網(wǎng)絡(luò)的分層設(shè)計(jì),區(qū)分協(xié)議層、數(shù)據(jù)層、傳輸層、連接層
3.獨(dú)立的可適配的codec層,可以靈活增加HTTP,Memcache,Redis,MySQL/JDBC,Thrift等協(xié)議的支持。
4.將多年各種遠(yuǎn)程調(diào)用High availability的經(jīng)驗(yàn)融入在實(shí)現(xiàn)中,如負(fù)載均衡,failover,多副本策略,開關(guān)降級(jí)等。
5.通用的遠(yuǎn)程調(diào)用實(shí)現(xiàn),采用async方式來(lái)減少業(yè)務(wù)服務(wù)的開銷,并通過future分離遠(yuǎn)程調(diào)用與數(shù)據(jù)流程的關(guān)注。
6.具有狀態(tài)查看及統(tǒng)計(jì)功能
7.當(dāng)然,最終要的是,具備以下通用的遠(yuǎn)程容錯(cuò)處理能力,超時(shí)、重試、負(fù)載均衡、failover……
QiuRPC特點(diǎn)
QiuRPC是一個(gè)采用JAVA實(shí)現(xiàn)的小巧的RPC框架,一共3K多行代碼,實(shí)現(xiàn)了RPC的基本功能,開發(fā)者也可以自定義擴(kuò)展,可以供大家學(xué)習(xí)探討或者在小項(xiàng)目中使用,目前QiuRPC具有如下特點(diǎn):
-
服務(wù)端基于注解,啟動(dòng)時(shí)自動(dòng)掃描所有RPC實(shí)現(xiàn),基本零配置
2. 客戶端實(shí)現(xiàn)Filter機(jī)制,可以自定義Filter
3. 基于netty的Reactor IO多路復(fù)用網(wǎng)絡(luò)模型
4. 數(shù)據(jù)層提供protobuff和hessian的實(shí)現(xiàn),可以擴(kuò)展ISerializer接口自定義實(shí)現(xiàn)其他
5. 負(fù)載均衡算法采用最少活躍調(diào)用數(shù)算法,可以擴(kuò)展ILoadBlance接口自定義實(shí)現(xiàn)其他
6. 客戶端支持服務(wù)的同步或異步調(diào)用
系統(tǒng)待改進(jìn)點(diǎn)
-
增加注冊(cè)中心功能,在大項(xiàng)目中,一個(gè)項(xiàng)目可能依賴成百上千個(gè)服務(wù),如果基于配置文件直接指定服務(wù)地址會(huì)增加維護(hù)成本,需要引入注冊(cè)中心
2. 目前用的是反射和java代理實(shí)現(xiàn)的服務(wù)端存根和客戶端代理,為了提高性能,可以把這些用javassit,asm等java字節(jié)碼工具實(shí)現(xiàn)
3. 增加一些監(jiān)控功能,為了增強(qiáng)服務(wù)的穩(wěn)定性和服務(wù)的可控性,監(jiān)控功能是不可或缺的
4. 目前應(yīng)用協(xié)議采用的是最簡(jiǎn)單的協(xié)議,僅僅一個(gè)魔數(shù)+序列化的實(shí)體,這些需要增強(qiáng),比如增加版本號(hào)以解決向前兼容性
5. 增加High availability的一些手段,目前只有負(fù)載均衡,其他的比如failover,多副本策略,開關(guān)降級(jí)等,過載保護(hù)等需要自己實(shí)現(xiàn)
示例:
1. 編寫服務(wù)端接口
public interface IServer1 {
public String getMsg();
public Message echoMsg(String msg);
public Message echoMsg(int msg);
}
2. 編寫服務(wù)端實(shí)現(xiàn)類
@ServiceAnnotation(name="myserver1")
public class MyServer1 implements IServer1{
private static final Log log=LogFactory.getLog(MyServer1.class);
public String getMsg()
{
log.info("getMsg echo");
return "Hello";
}
@Override
public Message echoMsg(String msg) {
Message result=new Message();
result.setMsg(msg);
result.setData(new Date());
return result;
}
@Override
public Message echoMsg(int msg) {
Message result=new Message();
result.setMsg("int:"+msg);
result.setData(new Date());
return result;
}
}
3. 啟動(dòng)服務(wù)
public static void main(String[] args) {
RpcServerBootstrap bootstrap=new RpcServerBootstrap();
bootstrap.start(8080);
}
4. 編寫客戶端調(diào)用代碼
public class Client1 {
public static void main(String[] args) {
try {
final IServer1 server1=RpcClientProxy.proxy(IServer1.class,"server1" , "myserver1");
long startMillis=System.currentTimeMillis();
for(int i=0;i<10000;i++)
{
final int f_i=i;
send(server1,f_i);
}
long endMillis=System.currentTimeMillis();
System.out.println("spend time:"+(endMillis-startMillis));
} catch (Throwable e) {
e.printStackTrace();
}
}
public static void send(IServer1 server1,int f_i)
{
Message msg = null;
try
{
//由于客戶端配置的async="true",我們用異步方式來(lái)獲取結(jié)果,如果是同步方式,直接msg=server1.echoMsg(f_i)即可
server1.echoMsg(f_i);
Future future = RpcContext.getContext().getFuture();
msg=future.get();
System.out.println("msg:"+msg.getMsg()+","+msg.getData());
}
catch(Throwable e)
{
e.printStackTrace();
}
}
}
5. 編寫客戶端配置文件
<application maxThreadCount="100">
<service name="server1" connectStr="127.0.0.1:9090;127.0.0.1:8080" maxConnection="100" async="true"></service>
</application>