<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          swrpc基于 swoole 開發(fā)的高性能 rpc 包

          聯(lián)合創(chuàng)作 · 2023-09-23 12:09

          swrpc是一個(gè)基于swoole開發(fā)的高性能rpc包,swrpc提供了注冊(cè)發(fā)現(xiàn),鏈路追蹤,中間件等等功能,可以很容易集成到第三方框架,如laravel,yii等等。

          功能

          • 支持多進(jìn)程模式或協(xié)程模式
          • 支持同步,異步調(diào)用
          • 支持自定義中間件
          • 支持服務(wù)端按類提供對(duì)外服務(wù)
          • 支持鏈路追蹤
          • 支持注冊(cè)服務(wù)發(fā)現(xiàn)
          • 支持客戶端負(fù)載均衡,包含隨機(jī),權(quán)重兩種模式
          • 支持自定義日志,包協(xié)議,序列化方式等等

          安裝

          php composer.phar require wuzhc/swprc ~1.0 -vvv

          快速體驗(yàn)

          假設(shè)我們User和School兩個(gè)模塊,為了獲得用戶學(xué)校名稱,我們需要在User模塊發(fā)起rpc請(qǐng)求調(diào)用School模塊的服務(wù)。

          School模塊

          <?php
          use Swrpc\LogicService;
          class SchoolService extends LogicService 
          {
              public function getUserSchool($userID) {
                  $name = $userID == 123 ? '火星' : '水星';
                  return $name.'學(xué)校';
              }    
          }

          School模塊將作為rpc服務(wù)端,對(duì)外提供服務(wù),啟動(dòng)如下:

          <?php
          namespace SwrpcTests;
          use Swrpc\Server;
          
          $basePath = dirname(dirname(__FILE__));
          require_once $basePath . "/vendor/autoload.php";
          
          $options = [
              'enable_coroutine' => true,
              'pid_file'         => __DIR__ . '/swrpc.pid',
          ];
          $server = new Server('School_Module', '127.0.0.1', 9501, 1, $options);
          $server->addService(\SwrpcTests\services\SchoolService::class); 
          $server->start();

          將SchoolService添加到server,server會(huì)自動(dòng)檢索類中所有可用的public方法。

          User模塊

          User模塊作為客戶端,調(diào)用School模塊服務(wù)如下

          <?php
          namespace SwrpcTests;
          use Swrpc\Request;
          use Swrpc\LogicService;
          use Swrpc\Client;
          
          class UserService extends LogicService
          {
              public function getUserSchoolName()
              {
                  $userID = 123;
                  $module = 'School_Module'; //請(qǐng)求目標(biāo)模塊名稱,需要和服務(wù)端定義的一致
                  $client = Client::create($module, '127.0.0.1', 9501);
                  return $client->send(Request::create('\SwrpcTests\services\SchoolService_getUserSchool', [$userID]));
              }
          }
          
          //調(diào)用
          echo UserService::factory()->getUserSchoolName();

          注意:

          • Request.method 為服務(wù)類命名 + 下劃線 + 方法名,例如上面的\SwrpcTests\services\SchoolService_getUserSchool,如果服務(wù)類有命名空間,記得一定要帶上命名空間

          多進(jìn)程和協(xié)程模式

          多進(jìn)程或協(xié)程模式需要和swoole配置一致,具體參考swoole配置

          多進(jìn)程模式

          創(chuàng)建10進(jìn)程來處理請(qǐng)求

          $options = [
              'worker_num'       => 10
              'pid_file'         => __DIR__ . '/swrpc.pid',
          ];
          $server = new Server('School_Module', '127.0.0.1', 9501, 1, $options);

          協(xié)程模式

          目前swrpc協(xié)程模式是運(yùn)行在單進(jìn)程的

          $options = [
              'enable_coroutine' => true,
              'pid_file'         => __DIR__ . '/swrpc.pid',
          ];
          $server = new Server('School_Module', '127.0.0.1', 9501, 1, $options);

          同步調(diào)用和異步調(diào)用

          在客戶端發(fā)起同步調(diào)用,客戶端會(huì)一直等待服務(wù)端返回結(jié)果

          $client = \Swrpc\Client::create($module, '127.0.0.1', 9501);
          return $client->send(SyncRequest::create('SchoolService_getUserSchool', [$userID]));

          在客戶端發(fā)起異步調(diào)用,客戶端會(huì)立馬得到響應(yīng)結(jié)果,請(qǐng)求將被swoole的task進(jìn)程處理

          $client = \Swrpc\Client::create($module, '127.0.0.1', 9501);
          return $client->send(AsyncRequest::create('SchoolService_getUserSchool', [$userID]));

          自定義中間件

          中間件允許程序可以對(duì)請(qǐng)求進(jìn)行前置操作和后置操作,底層使用了責(zé)任鏈設(shè)計(jì)模式,所以為了執(zhí)行下一個(gè)中間件,必須返回$next($request),如果想提前返回,則返回結(jié)果必須是Swrpc\Response類型

          //中間件除了用匿名函數(shù)定義,還可以用實(shí)現(xiàn)Swrpc\Middlewares\MiddlewareInterface接口的類
          $middleware = function (\Swrpc\Request $request, Closure $next) {
              $start = microtime(true); //前置操作,記錄請(qǐng)求開始時(shí)間
              $result = $next($request);
              echo '耗時(shí):'.(microtime(true) - $start).PHP_EOL; //后置操作,記錄請(qǐng)求結(jié)束時(shí)間,從而計(jì)算請(qǐng)求耗時(shí)
              return $result; //繼續(xù)下個(gè)中間件的處理
          };
          $server = new Server('School_Module', '127.0.0.1', 9501, 1, $options);
          $server->addService(SchoolService::class); 
          $server->addMiddleware($middleware); //添加中間件
          $server->start();

          如果要提前中止中間件,可以提前在匿名函數(shù)或類方法中返回\Swrpc\Response對(duì)象,如下

          $middleware = function (\Swrpc\Request $request, Closure $next) {
              if (empty($request->getParams())) {
                  return \Swrpc\Response::error('參數(shù)不能為空'); //提前返回,必須是Response類型
              }   
              return $next($request); 
          };

          服務(wù)端按類提供對(duì)外服務(wù)

          從上面的例子中,我們把SchoolService整個(gè)類添加的server中,這樣server就能對(duì)外提供SchoolService類所有public方法的功能。

          $server = new Server('School_Module', '127.0.0.1', 9501, 1, $options);
          $server->addService(SchoolService::class); //提供SchoolService所有public方法功能
          $server->addService(AreaService::class); //提供AreaService所有public方法功能
          $server->start();

          客戶端使用參考上面的快速體驗(yàn)

          注冊(cè)服務(wù)發(fā)現(xiàn)

          如果服務(wù)端啟動(dòng)的時(shí)候有設(shè)置注冊(cè)中心,則啟動(dòng)成功會(huì)自動(dòng)向注冊(cè)中心注冊(cè)服務(wù)端地址。目前swrpc提供了Consul作為注冊(cè)中心,使用如下

          $server = new Server('School_Module', '127.0.0.1', 9501, 1, $options);
          $server->addRegister(new Consul());
          $server->addService(SchoolService::class); 
          $server->start();

          如上,使用Consul作為服務(wù)的注冊(cè)中心,通過http://127.0.0.1:8500可以查看注冊(cè)信息,如果想用etcd等其他注冊(cè)中心,只要實(shí)現(xiàn)Swrpc\Middlewares\RegisterInterface接口即可,然后在通過$server->addRegister()添加到server

          客戶端負(fù)載均衡

          如果服務(wù)端啟動(dòng)多個(gè)節(jié)點(diǎn),例如School模塊啟動(dòng)3個(gè)節(jié)點(diǎn),并且注冊(cè)到了注冊(cè)中心,那么我們可以從注冊(cè)中心獲取所有服務(wù)端節(jié)點(diǎn)信息,然后做一些策略處理。

          $register = new Consul();
          $client = \Swrpc\Client::createBalancer('School_Module', $register, \Swrpc\Client::STRATEGY_WEIGHT);
          $result = $client->send(Request::create('SchoolService_getUserSchool', [$userID]);

          目前swrpc提供兩種簡(jiǎn)單策略模式,\Swrpc\Client::STRATEGY_WEIGHT權(quán)重模式\Swrpc\Client::STRATEGY_RANDOM隨機(jī)模式

          鏈路追蹤

          當(dāng)我們的服務(wù)非常多并且需要互相調(diào)用時(shí)候,如果其中某個(gè)調(diào)用失敗,會(huì)導(dǎo)致我們得不到我們想要的結(jié)果,而要調(diào)試出是哪個(gè)環(huán)節(jié)出了問題也比較麻煩,可能你需要登錄每臺(tái)機(jī)器看下有沒有錯(cuò)誤日志,或者看返回的錯(cuò)誤信息是哪個(gè)服務(wù)提供的。鏈路追蹤記錄了整個(gè)調(diào)用鏈過程,如果某個(gè)環(huán)節(jié)出錯(cuò),我們可以快速從調(diào)用鏈得到調(diào)用中斷地方。

          class UserService extends LogicService
          {
              public function getUserSchoolName()
              {
                  $userID = 123;
                  $module = 'School_Module'; //請(qǐng)求目標(biāo)模塊名稱,需要和服務(wù)端定義的一致
                  $client = Client::create($module, '127.0.0.1', 9501);
                  return $client->send(Request::create('SchoolService_getUserSchool', [$userID], $this->getTracerContext(__FUNCTION__))); //getTracerContext()用于提供追蹤上下文
              }
          }
          
          $users = UserService::factory()
              ->setModule('User_Module') //當(dāng)前模塊,用于調(diào)用鏈的起點(diǎn)
              ->setTracerUrl('http://127.0.0.1:9411/api/v2/spans') //zipkin鏈路追蹤地址
              ->getUserSchoolName();

          如圖,User_Module調(diào)用Class_Module,Class_Module又去調(diào)用School_Module

          每個(gè)調(diào)用還記錄響應(yīng)結(jié)果

          自定義日志處理器

          默認(rèn)使用Monolog/Logger作為日志處理器,日志信息會(huì)輸出到控制臺(tái)??筛鶕?jù)自己需求覆蓋默認(rèn)處理器,只要日志類 實(shí)現(xiàn)Psr\Log\LoggerInterface即可

          use Swrpc\Server;
          use Monolog\Handler\StreamHandler;
          use Monolog\Logger;
          
          $logger = new Logger('swrpc');
          $logger->pushHandler(new StreamHandler(fopen('xxxx.log','w+'), Logger::DEBUG));
          
          $server = new Server('127.0.0.1', 9501, ['enable_coroutine'=>true]);
          $server->addService(UserService::class);
          $server->addLogger($logger); //覆蓋默認(rèn)日志處理器
          $server->start();

          序列化方式

          默認(rèn)使用固定頭+包體來解決tcp粘包問題,默認(rèn)配置為'package_length_type' => 'N','package_body_offset' => 4 默認(rèn)序列化數(shù)據(jù)會(huì)使用serialize(),如果swoole版本在4.5以上的自動(dòng)使用swoole_substr_unserialize(),可以實(shí)現(xiàn)的類來覆蓋默認(rèn)配置,只要實(shí)現(xiàn)src/Packer/PackerInterface即可,注意服務(wù)端和客戶端需要使用一樣的協(xié)議,否則解析不了。

          use Swrpc\Server;
          
          $packer = new \Swrpc\Packer\SerializeLengthPacker();
          $server = new Server('127.0.0.1', 9501, ['enable_coroutine'=>true]);
          $server->addService(UserService::class); 
          $server->addPacker($packer); //覆蓋默認(rèn)值

          安全證書配置

          參考:https://wiki.swoole.com/#/server/setting?id=ssl_cert_file

          服務(wù)端

          $options = [
              'ssl_cert_file' => __DIR__.'/config/ssl.crt',
              'ssl_key_file'  => __DIR__.'/config/ssl.key',
              'pid_file'      => __DIR__ . '/swrpc.pid',
          ];
          $server = new Server('School_Module', '127.0.0.1', 9501, $options, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
          $server->addService(SchoolService::class); 
          $server->start();

          注意:

          • 文件必須為 PEM 格式,不支持 DER 格式,可使用 openssl 工具進(jìn)行轉(zhuǎn)換

          測(cè)試

          使用phpuint實(shí)現(xiàn)的簡(jiǎn)單測(cè)試案例,配置文件phpunit.xml

          php phpunit.phar tests --debug

          phpunit 測(cè)試報(bào)告

          Client (SwrpcTests\Client)
           [x] Client connect
           [x] Client sync request
           [x] Client async request
          
          Packer (SwrpcTests\Packer)
           [x] Serialize length pack
           [x] Serialize lenght unpack
           [x] Serialize eof pack
           [x] Serialize eof unpack
          
          Server (SwrpcTests\Server)
           [x] Server register to consul
           [x] Server unregister from consul
           [x] Server add service
           [x] Server add middleware
          瀏覽 23
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人人色,人人操 | 手机在线永久免费观看AV片 | 欧美又粗又大一区二区 | 亚洲国产另类无码 | 国产精品www |