<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 5.3 異步Http Client 支持協程的異步Http Client很關鍵,在微服務系統框架中,服務與服務的交互大多是通過Http接口來實現,即使有封裝RPC,也大多在Http Client的基礎上,當然我們也可以選擇自定義的Tcp文本或者二進制協議,這里我們主要介紹MSF框架中的Http Client的實現與使用。本節中的示例代碼:[https://github.com/pinguo/php-msf-demo/app/Controllers/Http.php](https://github.com/pinguo/php-msf-demo/blob/master/app/Controllers/Http.php) ## 實現 框架對http client的支持是基于swoole_http_client,同時在此基礎上封裝了dns查詢、dns緩存、keep-alive、簡單快捷操作、多個請求并行的各種方法。 ## 基本用法 ```php <?php /** * 異步HTTP CLIENT示例 * * @author camera360_server@camera360.com * @copyright Chengdu pinguo Technology Co.,Ltd. */ namespace App\Controllers; use PG\MSF\Controllers\Controller; use \PG\MSF\Client\Http\Client; class Http extends Controller { /** * 獲取百度首頁,手工進行DNS解析和數據拉取 */ public function actionBaiduIndexWithOutDNS() { /** * @var Client $client */ $client = $this->getObject(Client::class); yield $client->goDnsLookup('http://www.baidu.com'); $sendGet = $client->goGet('/'); $result = yield $sendGet; $this->outputView(['html' => $result['body']]); } } ``` 這種用法將一個Http請求方法分成為兩步: 第一步,DNS查詢;第二步,Get請求。可能大家會很奇怪,不就一個Http請求嘛,還分兩步?其實我們原來使用CURL擴展的時候,也是這兩個步驟,只是CURL內部把我們完成了DNS查詢。 另外,由于DNS查詢是一次UDP的請求,PHP內置函數`string gethostbyname ( string $hostname )`是同步阻塞模式,如果使用這個函數,將使我們的Sever退化為同步Server,MSF框架進行DNS查詢使用了`swoole_async_dns_lookup()`進行異步DNS解析。 一個http請求,開發代碼進行兩次yield,開發效率不高,但是性能是最好的;同時我們也提供一些快捷的方法,在只有一次接口請求的開發中性能和效率均可得到提升。 ## 快捷POST/GET ```php <?php /** * 異步HTTP CLIENT示例 * * @author camera360_server@camera360.com * @copyright Chengdu pinguo Technology Co.,Ltd. */ namespace App\Controllers; use PG\MSF\Controllers\Controller; use \PG\MSF\Client\Http\Client; class Http extends Controller { /** * 獲取百度首頁,自動進行DNS,自動通過Get拉取數據 */ public function actionBaiduIndexGet() { /** * @var Client $client */ $client = $this->getObject(Client::class); $result = yield $client->goSingleGet('http://www.baidu.com/'); $this->outputView(['html' => $result['body']]); } /** * 獲取百度首頁,自動進行DNS,自動通過Post拉取數據 */ public function actionBaiduIndexPost() { /** * @var Client $client */ $client = $this->getObject(Client::class); $result = yield $client->goSinglePost('http://www.baidu.com/'); $this->outputView(['html' => $result['body']]); } } ``` `\PG\MSF\Client\Http\Client::goSingleGet()`,`\PG\MSF\Client\Http\Client::goSinglePost()`兩個方法可以快捷的自動完成DNS和請求的發送,直接返回響應內容。 ## 響應數據 ``` [ 'errCode' => 0 'sock' => 17 'host' => '180.97.33.107' 'port' => 80 'headers' => [ 'content-type' => 'text/html' 'content-encoding' => 'gzip' 'cache-control' => 'no-cache' 'pragma' => 'no-cache' 'content-length' => '363' 'set-cookie' => 'bai=16.;Domain=.baidu.com;Path=/;Max-Age=10' ] 'type' => 1025 'requestHeaders' => [ 'Host' => 'www.baidu.com' 'X-Ngx-LogId' => '59496e12c3474d040f41fda2' ] 'requestBody' => null 'cookies' => [ 'bai' => '16.' ] 'set_cookie_headers' => [ 'bai' => 'bai=16.;Domain=.baidu.com;Path=/;Max-Age=10' ] 'body' => '<body></body><script type=\"text/javascript\">u=\"https://www.baidu.com/?tn=93817326_hao_pg\";d=document;/webkit/i.test(navigator.userAgent)?(f=d.createElement(\'iframe\'),f.style.width=1,f.style.height=1,f.frameBorder=0,d.body.appendChild(f).src=\'javascript:\"<script>top.location.replace(\\\'\'+u+\'\\\')<\\/script>\"\'):(d.open(),d.write([\'<meta http-equiv=\"refresh\"content=\"0;url=\',\'\"/>\'].join(u)),d.close());function g(k){return v=eval(\"/\"+k+\"=(.*?)(&|$)/i.exec(location.href)\"),v?v[1]:\"\"}</script>' 'statusCode' => 200 ] ``` 其中: errCode的具體含義:[附錄:Linux錯誤信息(errno)列表](https://wiki.swoole.com/wiki/page/172.html) statusCode為Http響應的狀態碼: [維基百科HTTP狀態碼](https://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81) [OSCHINA HTTP狀態碼](http://tool.oschina.net/commons?type=5) body為響應正文 ## 并行請求 Http請求分成了DNS查詢和發送數據兩個異步部分,從而在多個內部接口請求中會寫大量的冗余代碼的,故框架封裝了簡單實用的并行的Http Client,大大的簡化了發送并行請求。 ```php <?php /** * 異步HTTP CLIENT示例 * * @author camera360_server@camera360.com * @copyright Chengdu pinguo Technology Co.,Ltd. */ namespace App\Controllers; use PG\MSF\Controllers\Controller; use \PG\MSF\Client\Http\Client; class Http extends Controller { // 略 /** * 并行多次獲取百度首頁,自動進行DNS,自動通過Get或者Post拉取數據 */ public function actionConcurrentBaiduIndex() { /** * @var Client $client */ $client = $this->getObject(Client::class); $requests = [ 'http://www.baidu.com/', [ 'url' => 'http://www.baidu.com/', 'method' => 'POST' ], ]; $results = yield $client->goConcurrent($requests); $this->outputView(['html' => $results[0]['body'] . $results[0]['body']]); } } ``` `\PG\MSF\Client\Http\Client::goConcurrent($requests)`是我們封裝的快捷并行請求方式,`$requests`的數據結構如: ```php [ 'http://www.baidu.com/xxx', [ // 必須為全路徑URL 'url' => 'http://www.baidu.com/xxx', 'method' => 'GET', 'dns_timeout' => 1000, // 默認為30s 'timeout' => 3000, // 默認不超時 'headers' => [], // 默認為空 'data' => ['a' => 'b'] // 發送數據 ], [ 'url' => 'http://www.baidu.com/xxx', 'method' => 'POST', 'timeout' => 3000, 'headers' => [], 'data' => ['a' => 'b'] // 發送數據 ], [ 'url' => 'http://www.baidu.com/xxx', 'method' => 'POST', 'timeout' => 3000, 'headers' => [], 'data' => ['a' => 'b'] // 發送數據 ], ] ``` ## DNS緩存 HTTP Client的DNS查詢為提升性能,默認情況下,已經開啟緩存,緩存策略為: 1. DNS緩存有效時間默認為60s 2. 已解析DNS使用次數上限為10000次 只要判斷有效時間,如果已過有效期即緩存失效;如果在有效期內,使用次數超過10000次,則重新進行DNS解析 ## DNS配置 默認開啟了DNS緩存,并有相應的策略,我們也提供了配置項來修改緩存策略, ```php $config['http']['dns'] = [ // 有效時間,單位秒 'expire' => 30, // 使用次數上限 'times' => 1000, ]; ``` ## Keep-Alive HTTP持久連接(HTTP persistent connection,也稱作HTTP keep-alive或HTTP connection reuse) 是使用同一個TCP連接來發送和接收多個HTTP請求/應答,而不是為每一個新的請求/應答打開新的連接的方法。 如果客戶端支持 keep-alive,它會在請求的包頭中添加: ``` Connection: Keep-Alive ``` 然后當服務器收到請求,作出回應的時候,它也添加一個頭在響應中: ``` Connection: Keep-Alive ``` 這樣做,連接就不會中斷,而是保持連接。當客戶端發送另一個請求時,它會使用同一個連接。 這一直繼續到客戶端或服務器端認為會話已經結束,其中一方中斷連接。 #### 優勢 - 較少的CPU和內存的使用(由于同時打開的連接的減少了) - 允許請求和應答的HTTP管線化 - 降低擁塞控制 (TCP連接減少了) - 減少了后續請求的延遲(無需再進行握手) - 報告錯誤無需關閉TCP連接 ## Keep-Alive 配置 由上面的描述可知,Keep-Alive需要客戶端和服務端都支持才可以。 假如我們的請求鏈路是:瀏覽器->Nginx->php-msf->后端API服務 那么:瀏覽器是純客戶端,后端API服務是純服務端,Nginx和php-msf既是服務端又是客戶端。 #### 保持和client的長連接 Nginx作為http服務端,默認情況下,已經自動開啟了對client連接的keep-alive支持。 一般場景可以直接使用,但是對于一些比較特殊的場景,還是有必要調整個別參數。 需要修改Nginx的配置文件(在nginx安裝目錄下的conf/nginx.conf): ``` http { keepalive_timeout 120s 120s; keepalive_requests 10000; } ``` keepalive_timeout指令的語法: ``` Syntax: keepalive_timeout timeout [header_timeout]; Default: keepalive_timeout 75s; Context: http, server, location ``` 第一個參數設置keep-alive客戶端連接在服務器端保持開啟的超時值。值為0會禁用keep-alive客戶端連接。 可選的第二個參數在響應的header域中設置一個值“Keep-Alive: timeout=time”。這兩個參數可以不一樣。 注:默認75s一般情況下也夠用,對于一些請求比較大的內部服務器通訊的場景,適當加大為120s或者300s。第二個參數通常可以不用設置。 keepalive_requests指令用于設置一個keep-alive連接上可以服務的請求的最大數量。當最大請求數量達到時,連接被關閉。默認是100。 這個參數的真實含義,是指一個keep alive建立之后,nginx就會為這個連接設置一個計數器,記錄這個keep alive的長連接上已經接收并處理的客戶端請求的數量。如果達到這個參數設置的最大值時,則nginx會強行關閉這個長連接,逼迫客戶端不得不重新建立新的長連接。 這個參數往往被大多數人忽略,因為大多數情況下當QPS(每秒請求數)不是很高時,默認值100湊合夠用。但是,對于一些QPS比較高(比如超過10000QPS,甚至達到30000,50000甚至更高) 的場景,默認的100就顯得太低。 簡單計算一下,QPS=10000時,客戶端每秒發送10000個請求(通常建立有多個長連接),每個連接只能最多跑100次請求,意味著平均每秒鐘就會有100個長連接因此被nginx關閉。同樣意味著為了保持QPS,客戶端不得不每秒中重新新建100個連接。因此,如果用netstat命令看客戶端機器,就會發現有大量的TIME_WAIT的socket連接(即使此時keep alive已經在client和nginx之間生效)。 因此對于QPS較高的場景,非常有必要加大這個參數,以避免出現大量連接被生成再拋棄的情況,減少TIME_WAIT。 #### 保持和php-msf server的長連接 為了讓nginx和php-msf server(nginx稱為upstream)之間保持長連接,典型設置如下: ``` http { upstream MSF_BACKEND { server 127.0.0.1:8000; keepalive 300; // 這個很重要!設置每個worker進程在緩沖中保持的到upstream服務器的空閑keepalive連接的最大數量.當這個數量被突破時,最近使用最少的連接將被關閉。 } server { listen 80 default_server; server_name ""; location / { proxy_pass http://MSF_BACKEND; proxy_set_header Host $Host; proxy_set_header x-forwarded-for $remote_addr; proxy_set_header X-Real-IP $remote_addr; add_header Cache-Control no-store; add_header Pragma no-cache; proxy_http_version 1.1; // 這兩個最好也設置 proxy_set_header Connection ""; client_max_body_size 3072k; client_body_buffer_size 128k; } } } ``` ## MSF長連接 #### 保持和客戶端的長連接 和Nginx一樣,只要客戶端支持長連接,msf就會默認支持長連接,不需要任何配置。 #### 保持和后端接口服務的長連接 當我們的服務需要請求其他的服務的時候,那么這個場景長連接就是需要的了,php-msf默認開啟的長連接,默認的配置如下: ``` http.keepAlive.expire = 120 //每個長連接有效期為20s http.keepAlive.times = 10000 //每個長連接在有效期內最多處理10000個請求 ``` 也可用通過 ``` $config['http']['keepAlive'] = [ 'expire' => 60, // 為0時表示關閉 keep-alive 'times' => 1000 ] ``` 來控制 http-client 的keep-alive行為。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看