并行的RPC框架
Yar(yet another RPC framework, 教主問(wèn)我為啥都是Ya打頭, 呵呵, 因?yàn)檫@樣名字好起)是我在3個(gè)多月前, 為了解決一個(gè)實(shí)際的問(wèn)題, 而開(kāi)發(fā)的一個(gè)PHP擴(kuò)展的, RPC框架, 和現(xiàn)有的RPC框架(xml-rpc, soap)不同, 這是一個(gè)輕量級(jí)的框架, 支持多種打包協(xié)議(msgpack, json, php), 并且最重要的一個(gè)特點(diǎn)是, 它是可并行化的..
考慮如下的場(chǎng)景:
傳統(tǒng)的Web應(yīng)用, 一個(gè)進(jìn)程, 一個(gè)請(qǐng)求, 天經(jīng)地義. 然而, 當(dāng)一個(gè)請(qǐng)求的處理中, 涉及到多出數(shù)據(jù)源, 并且他們之間具有一定的不依賴(lài)性.
還是傳統(tǒng)的Web應(yīng)用, 一個(gè)應(yīng)用隨著業(yè)務(wù)快速增長(zhǎng), 開(kāi)發(fā)人員的流轉(zhuǎn), 就會(huì)慢慢的進(jìn)入一個(gè)惡性循環(huán), 代碼量上只有加法沒(méi)有了減法. 因?yàn)殡S著系統(tǒng)變復(fù)雜, 牽一發(fā)就會(huì)動(dòng)全局, 而新來(lái)的維護(hù)者, 對(duì)原有的體系并沒(méi)有那么多時(shí)間給他讓他全面掌握. 即使有這么多時(shí)間, 要想掌握以前那么多的維護(hù)者的思維的結(jié)合, 也不是一件容易的事情…
那么, 長(zhǎng)次以往, 這個(gè)系統(tǒng)將會(huì)越來(lái)越不可維護(hù)…. 到一個(gè)大型應(yīng)用進(jìn)入這個(gè)惡性循環(huán), 那么等待他的只有重構(gòu)了.
那么, 能不能對(duì)這個(gè)系統(tǒng)做解耦呢?
我們已經(jīng)做了很多解耦了, 數(shù)據(jù), 中間件, 業(yè)務(wù), 邏輯, 等等, 各種分層. 但到Web應(yīng)用這塊, 還能怎么分呢, MVC我們已經(jīng)做過(guò)了….
基于此, Yar或許能解決你遇到的這倆個(gè)問(wèn)題…
Yar是一個(gè)非常輕量級(jí)的RPC框架, 我在實(shí)現(xiàn)Yar的時(shí)候, 追求了極致的輕量級(jí), 它使用非常簡(jiǎn)單, 對(duì)于Server端:
- <?php
- class API {
- /**
- * the doc info will be generated automatically into service info page.
- * @params
- * @return
- */
- public function api($parameter, $option = "foo") {
- }
- protected function client_can_not_see() {
- }
- }
- $service = new Yar_Server(new API());
- $service->handle();
- ?>
和Soap使用方法很相像吧? 是的, 就這樣, 你的API類(lèi)就可以對(duì)外提供服務(wù)了..
Yar為了方便開(kāi)發(fā), 把文檔和接口綁定到了一起, 對(duì)于上面的例子, 如果我們是簡(jiǎn)單的GET請(qǐng)求這個(gè)接口地址的話(huà), 我們就會(huì)看到如下的信息頁(yè)面:
這樣, 我們可以在注釋中,把接口的信息標(biāo)注好, 就可以讓文檔和接口在一起了.
而對(duì)于Client端來(lái)說(shuō), 簡(jiǎn)單的串行調(diào)用, 會(huì)非常之簡(jiǎn)單:
- <?php
- $client = new Yar_Client("http://host/api/");
- $result = $client->api("parameter);
- ?>
這樣一來(lái), 如果你有多個(gè)服務(wù), 你只需要一個(gè)client.
那么, 最激動(dòng)人心的并行化調(diào)用呢?
- <?php
- function callback($retval, $callinfo) {
- var_dump($retval);
- }
- Yar_Concurrent_Client::call("http://host/api/", "api", array("parameters"), "callback");
- Yar_Concurrent_Client::call("http://host/api/", "api", array("parameters"), "callback");
- Yar_Concurrent_Client::call("http://host/api/", "api", array("parameters"), "callback");
- Yar_Concurrent_Client::call("http://host/api/", "api", array("parameters"), "callback");
- Yar_Concurrent_Client::loop(); //send
- ?>
這樣, 所有的請(qǐng)求會(huì)一次發(fā)出, 只要有任何一個(gè)請(qǐng)求完成, 回調(diào)函數(shù)”callback”就會(huì)被立即調(diào)用.
這里還有一個(gè)細(xì)節(jié), Yar見(jiàn)縫插針的不會(huì)浪費(fèi)任何時(shí)間, 在這些請(qǐng)求發(fā)送完成以后, Yar會(huì)調(diào)用一次callback, 和普通的請(qǐng)求返回回調(diào)不同, 這次的調(diào)用的$callinfo參數(shù)為空.
這樣一來(lái), 我們就可以先發(fā)送請(qǐng)求, 然后再第一次回調(diào), 繼續(xù)做我們當(dāng)前進(jìn)程的工作, 等所有工作結(jié)束以后, 再交給Yar去獲取并行RPC的響應(yīng).
- <?php
- function callback($retval, $callinfo) {
- if ($callinfo == NULL) {
- //做本地的邏輯
- return TRUE;
- }
- //RPC請(qǐng)求返回, 返回值在$retval
- }
有了這些, 我們就可以把一個(gè)Web應(yīng)用中, 多個(gè)數(shù)據(jù)源并行處理, 從而也能把這些邏輯解耦, 分開(kāi)部署…
當(dāng)然Yar目前還在試用階段, 所以還沒(méi)有發(fā)布任何一個(gè)包(Yar at PECL), 但是有興趣的同學(xué)可以現(xiàn)在就把代碼clone下去試用哦(雖然沒(méi)有正式投入試用, 不過(guò)已經(jīng)經(jīng)過(guò)了驗(yàn)證).
Yar: Yar at Github