rpc簡介
rpc大家大概都聽說過,遠程過程調用。簡單來說,就是我的一個操作是遠程操作的給的結果,舉個例子,考試作弊,你把考題發出去了,你同學幫你做好把答案傳輸給你,然後你就把答案寫上,那麼在判卷老師眼裡,你回答的還不錯,但是,其實你是做了遠程過程調用的。
rpc的好處也在上面的例子中體現了,當自身能力不行的時候,可以依靠強大的遠程力量來做到結果。如果自己有能力回答卷子,那就沒必要走rpc了。換句話說就是
自身執行的消耗 > 別人執行的消耗+傳輸的消耗
藉助netty手寫rpc
rpc的要點
- 消息傳給遠程
- 看起來和本地調用差不多
- 服務註冊
消息傳給遠程
這裡就是建立連接的過程,代碼都比較套路,這裡不列舉。最後會貼出代碼地址的,這裡先通思路。序列化沒有選擇pb,而是選擇了protostuff,這裡得解釋一下原因。
rpc傳遞的是什麼
既然是方法調用,一個方法的唯一標誌是類名,方法名,參數類型。你還得把方法參數也傳遞走。
private String id;private String className;private String methodName;private Object[] args;private Class>[] parameterTypes;
這裡還有傳輸一個id,是為了做標誌,例如我發了題目出去,最希望的就是回到我的是第4題答案是什麼,而不是xxxx問題的答案是什麼。id就是唯一表示一次問題的。
大家也發現了裡面有Object類型和Class類型,這些類型是pb裡沒有的,所以此時pb就不適合作為序列化的選擇了。
收到的就比較簡單了,就是唯一的id以及結果
private String id;private Object result;
netty異步如何準確的返回結果
netty的返回的結果是在handler裡,而不是我們的業務線程,如何傳遞就成為了一個問題。上面的唯一的id就是解決的關鍵點,我選擇了SynchronousQueue來作為傳遞的媒介,如果不瞭解這個類的可以先查看一下,他主要就是作為傳遞媒介的,有點類似阻塞隊列。
private static ConcurrentHashMapmapInfo = new ConcurrentHashMap<>();
使用一個map來保存id,和傳遞媒介,業務線程只要拿著SynchronousQueue就好,等消息收到,就把結果放入SynchronousQueue中,業務線程就可以拿到結果了,與此同時,要把id從map裡移除。
看起來和本地調用差不多
想做到方法調用,還擴充了部分功能,這個是裝飾者或者代理模式的效果。因為這裡只做一層包裝,所以選擇代理模式,如果是不斷的擴充功能的情況,裝飾者會更好一些。因為我們是java編寫,動態代理就是一個不錯的選擇。
public staticT getProxy(final Class clazz) {return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {RpcRequest request = new RpcRequest();request.setMethodName(method.getName());request.setClassName(clazz.getName());Class>[] parameterTypes = method.getParameterTypes();request.setArgs(args);String id = UUID.randomUUID().toString();request.setId(id);SynchronousQueue queue = new SynchronousQueue();ResultInfo.putSunchronousQuee(id, queue);Client.write(request);return queue.take();}});}
服務註冊
這裡使用了比較簡單的方法,就是手動把服務加入。
public static void put(Object value) {Class>[] interfaces = value.getClass().getInterfaces();for(Class> interfaceTmp:interfaces){services.put(interfaceTmp.getName(), value);}}
這裡選擇把接口作為key,對象作為value。如果結合spring就可以更簡單一些,通過註解來做,不用自己手動寫了。
rpc實現總結
這裡實現的rpc的基礎功能,就是遠程調用。技術點就在動態代理和消息通訊上。動態代理的目的是為了讓rpc在調用的時候更簡單,通訊部分才是rpc的主要點,通過反射等方式,讓遠程的機器進行運算,並且返回結果。所有的代碼如下:github.com/xpbob/lightrpc
閱讀更多 IT技術之家 的文章