基於 Swoole 的輕量級高效能框架 swoolefy 1.0.6 釋出

類別: IT

swoolefy是基於swoole實現的輕量級高效能框架,框架支援http,websocket,udp伺服器,以及基於tcp實現可擴充套件的rpc服務,同時支援composer包方式安裝部署專案。基於實用,swoolefy抽象Event事件處理類,實現與底層的回撥的解耦,支援同步|非同步呼叫,內建view、log、session、mysql、redis、memcached、mongodb等常用元件等。

swoolefy經過多個版本的迭代和實踐,以及優化,效能穩定,目前已經至1.0.6版本。

1.0.6版本主要的更新:

  • 新增RpcClientManager管理器,可以方便的註冊client服務例項,支援單sock連線(或者多socket連線)阻塞呼叫,單sock連線(或者多sock連線)並行呼叫,同時RpcClientManager可以在apache|php-fpm中使用。

  • RPC的服務端和RPC的客戶端支援多種方式獲取整包資料,包頭,包體。

  • RPC配置服務化,簡單配置服務即可快速搭建一個RPC的伺服器和對應的RPC的服務端。

  • 元件例項化支援配置閉包回撥函式。

  • 新增了程式池PoolsManager管理器,方便建立swoole_process

github:https://github.com/bingcool/swoolefy

文件:https://www.kancloud.cn/bingcoolhuang/php-swoole-swoolefy/587501

下面是一個rpc的demo:

RPC的服務端:

1、設定協議層配置檔案protocol/rpc/config.php,新增packet設定:

'packet'=>[		// 服務端使用長度檢查packet時,設定包頭結構體,如果使用eof時,不需要設定,底層會讀取package_eof		'server'=>[			'pack_header_struct' => ['length'=>'N', 'version'=>'a10', 'name'=>'a30', 'request_id'=>'a12'],			'pack_length_key' => 'length',			'serialize_type' => 'json'		],		//客戶端解包設定		'client' => [				'pack_check_type' => 'length',				'pack_header_struct' => ['length'=>'N', 'version'=>'a10', 'name'=>'a30', 'request_id'=>'a12'],				'pack_length_key' => 'length',				'serialize_type' => 'json'		]	],

2、服務端的控制器中

<?phpnamespace Service\Coms\Book;use Swoolefy\Core\Swfy;use Swoolefy\Core\SController;use Swoolefy\Core\Application;use Swoolefy\Core\Task\TaskManager;class BookmanageService extends SController {	public function test($params) {		// 客戶端傳送過來的資料     		var_dump($params);		$data = $params;        //客戶端的頭部與服務端頭部相同,當然可以根據返回資料不同,返回包頭可以不同。		$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool', 'request_id'=>$this->getRpcPackHeader()['request_id']];		//   返回資料給客戶端     		$this->send($this->fd, $data, $header);	}

至此,很很簡單的服務端就ok了,其實就是設定一下packet就可以了。

RPC的客戶端:

client端是基於swoole_client實現的,所以環境中必須安裝swoole和swoole_serialize擴充套件。這個客戶端其實是可以用在Apache|php-fpm的環境中,並且支援並行呼叫。

1、在/protocol/rpc/RpcServer.php的onWorkerStart中註冊client的訪問的服務,或者在start_init配置項中的類的onWorkerStart函式中註冊服務,因為該類必須繼承於Swoolefy\Core\StartInit的。

/**	 * onWorkerStart	 * @param    $server	 * @return   	 */	public function onWorkerStart($server, $worker_id) {		if(Swfy::isWorkerProcess()) {			$productServiceConfig = [				'servers' => '127.0.0.1:9504',				'timeout' => 0.5,				'noblock' => 0			];			$orderServiceConfig = array(				'servers' => '127.0.0.1:9506',				'timeout' => 0.5,				'noblock' => 0			);			//客戶端pack長度檢查設定			$setting = array(				'open_length_check'     => 1,			    'package_length_type'   => 'N',			    'package_length_offset' => 0,       //第N個位元組是包長度的值			    'package_body_offset'   => 56,       //第幾個位元組開始計算長度			    'package_max_length'    => 2000000,  //協議最大長度			);			// 包頭結構體設定,預設客戶端與服務端包頭結構體相同			$header_struct = array(				'length'=>'N', 				'version'=>'a10', 				'name'=>'a30', 				'request_id'=>'a12'			);			// 註冊product服務			RpcClientManager::getInstance(true)->registerService('productService', productServiceConfig, $setting, $header_struct,[				// swoole_client 長連線             					'swoole_keep' => false			]);			// 註冊order服務			RpcClientManager::getInstance(true)->registerService('orderService', $orderServiceConfig, $setting, $header_struct,[            // swoole_client 長連線				'swoole_keep' => true			]);		}	}

2、在controller或者model中可以直接呼叫向服務端傳送資料
a、阻塞呼叫,請求/應答模式

public function test() {		$callable = 'Service\Coms\Book\BookmanageService::test';		$params = ['content'=>'我是rpc的客戶端,我向你傳送訊息'];		$header = ['length'=>'', 'version'=>'1.0.0', 'name'=>'bingcool'];        //呼叫傳送資料		$client1 = RpcClientManager::getInstance()->getServices('productService')->buildHeaderRequestId($header)->waitCall($callable, $params);        //阻塞等待資料返回		$res1 = $client1->waitRecv();		var_dump($res1);}

上面將返回一個資料,陣列裡有兩個元素,arr[0]是包頭,arr[1]是包體資料,例如:

array(2) {  [0] => array(4) {    ["length"] => int(83)    ["version"] => string(10) "1.0.0"    ["name"] => string(30) "bingcool"    ["request_id"] => string(12) "d189dfd5b997"  }  [1] => array(4) {    ["content"] => array(1) {      ["content"] => string(16) "我是rpc的服務端,我已收到你傳送的訊息"  }}

b、並行呼叫,然後在時間內等待接收所有資料,再進行資料聚合

// productService 呼叫$callable = 'Service\Coms\Book\BookmanageService::test';$params = ['content'=>'hhhhhhhhhhhhhhhh'];$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool'];$client2 = RpcClientManager::getInstance()->getServices('productService')->buildHeaderRequestId($header)->waitCall($callable, $params);// orderService 呼叫$callable = 'Service\Coms\Book\BookmanageService::test';$params = ['content'=>'hhhhhhhhhhhhhhhh'];$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool'];$client3 = RpcClientManager::getInstance()->getServices('orderService')->buildHeaderRequestId($header)->waitCall($callable, $params);// productService 呼叫$callable = 'Service\Coms\Book\BookmanageService::test';$params = ['content'=>'hhhhhhhhhhhhhhhh'];$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool'];$client4 = RpcClientManager::getInstance()->getServices('productService')->buildHeaderRequestId($header)->waitCall($callable, $params);// productService 呼叫$callable = 'Service\Coms\Book\BookmanageService::test';$params = ['content'=>'hhhhhhhhhhhhhhhh'];$header = ['length'=>'', 'version'=>'1.0.1', 'name'=>'bingcool'];$client5 = RpcClientManager::getInstance()->getServices('productService')->buildHeaderRequestId($header)->waitCall($callable, $params);// 並行等待資料返回,這裡返回的是所有呼叫的資料,例如上面呼叫4次,那麼將返回給陣列$res中4個整包元素$res = RpcClientManager::getInstance()->multiRecv();var_dump($res);~~~那麼如何獲取其中某一個的客戶端的資料呢,很簡單~~~// 獲取整包資料,包括包頭和包體$pack_data = $client2->getResponsePackData();// 分離包頭包體list($pack_header, $pack_body) = $pack_data;// 直接獲取包頭$pack_header = $client2->getResponsePackHeader();或者$pack_header = $pack_data[0];// 直接獲取包頭$pack_body = $client2->getResponsePackBody();或者$pack_body =  $pack_data[1];

這是一個簡單的說明,具體可以參考文件。

基於 Swoole 的輕量級高效能框架 swoolefy 1.0.6 釋出原文請看這裡