2022年04月22日10:52:41更新
本篇內容主要講述了最新的think-swoole
擴展的使用。
本指南的目的不是為了讓你掌握
Swoole
開發,而且幫助你使用think-swoole
快速部署ThinkPHP5.1
應用到Swoole
的HttpServer
,以及使用快速啟動Swoole
服務,如果你需要了解Swoole
的具體用法和原理,請參考Swoole官方文檔,說的比較詳細了。
本文的內容並不適用於ThinkPHP
5.0
及以下版本(5.0
或者5.1.18
之前版本的Swoole
的支持可以參考這里) !
安裝Swoole
首先按照Swoole官網說明安裝swoole
擴展,推薦新手可以直接使用
sudo pecl install swoole
會安裝最新的穩定版(截至本文發布最新版本是4.0.3
版本),如果你需要安裝某個版本,例如,如果你不需要使用協程功能,只需要安裝1.*
版本,可以使用:
sudo pecl install swoole-1.10.5
可以在這里查看所有的swoole版本。
安裝完成后,你可能需要在你的php.ini
中添加:
extension=swoole
最后,請確認你的php的swoole
模塊已經支持。
php -m
如果你能夠看到swoole
在列表中,說明swoole
模塊已經正常安裝了。
如果安裝過程中遇到問題,根據提示進行操作即可,或者自行百度,這里不再贅述。
安裝think-swoole
接下來第二步是安裝think-swoole
擴展,本文中的內容以最新版本的擴展為例(可能部分功能老版本的擴展不支持),如果你的擴展版本較舊,請更新框架或者擴展版本。
think-swoole
是ThinkPHP官方發布的swoole
擴展,從2.0+
版本完善了對Swoole
的支持。
ThinkPHP5+
的擴展都是基於Composer
安裝的,所以確認你已經安裝了Composer
。
如果你已經有自己的ThinkPHP5.1
項目了,為了使用最新的特性,建議更新到最新版本(V5.1.20+
),然后可以在應用根目錄下使用下面命令安裝擴展。
composer require topthink/think-swoole=2.0.*
會安裝最新的穩定版本的think-swoole
擴展。
如果你是第一次使用ThinkPHP5.1
,那么可以先創建一個初始項目,然后再安裝擴展,依次執行下面的命令即可。
composer create-project topthink/think tp
cd tp
composer require topthink/think-swoole
如果你的composer不是最新版本的,請執行命令更新:composer self-update
如果你的composer鏡像不是國內的,請執行命令切換阿里composer鏡像:
所有項目都會使用該鏡像地址:
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
取消配置:
composer config -g --unset repos.packagist
項目配置
僅修改當前工程配置,僅當前工程可使用該鏡像地址:
composer config repo.packagist composer https://mirrors.aliyun.com/composer/
取消配置:
composer config --unset repos.packagist
調試
composer 命令增加 -vvv 可輸出詳細的信息,命令如下:
composer -vvv require alibabacloud/sdk
啟動Swoole HTTP
服務
第一個場景(也是該擴展最重要的一個場景),畢竟大部分使用think-swoole
擴展的用戶都是在使用ThinkPHP開發網站或者項目,使用think-swoole
擴展可以讓你的產品直接部署到Swoole
上,並且享受下面的優勢:
- 無需對代碼進行改造就能帶來性能的數倍提升;
- 可以在
Apache
/Nginx
等傳統WEB服務器和Swoole
之間切換部署;
簡單點說,就是你可以在傳統模式下開發你的應用,然后直接部署到
Swoole
上運行,但無需針對Swoole
寫任何的處理代碼。
安裝完擴展后,你什么都不需要做,最簡單的就是直接在命令行(應用根目錄下面)下執行:
php think swoole
啟動成功后會顯示
Starting swoole http server...
Swoole http server started: <http://0.0.0.0:9501>
You can exit with `CTRL-C`
可以看到已經在0.0.0.0:9501
啟動一個HTTP Server服務端,下面我們可以直接訪問當前的應用。
http://localhost:9501
如果你之前已經有運行一個80端口的WEB服務,那么可以比較下兩個頁面的區別。
如果你是剛創建的項目,那么可以直接看到ThinkPHP5.1
的歡迎頁面。
否則你會看到你的項目首頁。
配置文件
HTTPServer
的參數可以在應用配置目錄下的swoole.php
里面配置,該文件會在擴展安裝的時候自動生成(如果沒有則可以自己創建)。
擴展自帶的配置參數主要包括:
配置參數 | 描述 | 默認值 |
---|---|---|
host | 監聽地址 | 0.0.0.0 |
port | 監聽端口 | 9501 |
mode | 運行模式 | SWOOLE_PROCESS |
sock_type | Socket type | SWOOLE_SOCK_TCP |
app_path | 應用目錄(守護進程模式必須設置) | 自動識別 |
ssl | 是否啟用https | false |
file_monitor | 是否監控文件更改(V2.0.9+) | false |
file_monitor_interval | 監控文件間隔(秒)(V2.0.9+) | 2 |
file_monitor_path | 監控目錄 (V2.0.9+) | 默認監控application和config目錄 |
其它的
swoole
參數可以參考官方文檔的配置參數,所有swoole
本身支持的配置參數都可以直接在swoole.php
中使用。
守護進程模式
如果需要使用守護進程模式運行,可以使用
php think swoole -d
或者在swoole.php
文件中設置
'daemonize' => true
不過一定要記得,如果啟用守護進程模式,必須設置應用目錄app_path
(使用絕對路徑),否則會出錯。
'host' => '0.0.0.0', // 監聽地址
'port' => 9501, // 監聽端口
'daemonize' => true,
'app_path' => '/home/www/tp/application/',
基本操作
如果要停止服務,可以使用
php think swoole stop
reload
服務
php think swoole reload
stop
服務
php think swoole stop
restart
服務
php think swoole restart
restart
和reload
的區別是,restart
會先stop
然后start
,而reload
則是平滑重啟服務,不會中斷服務。
如果你需要修改地址和端口,可以修改swoole.php
配置文件
'host' => 'tp5.com', // 監聽地址
'port' => 8080, // 監聽端口
改完后,需要重啟服務才能生效
php think swoole restart
現在可以直接訪問
http://tp5.com:8080
如果你需要設置
80
端口,需要root
權限才可以。
如果你安裝的是
2.0.12+
版本的擴展,還可以支持在命令行指定地址和端口,例如:
php think swoole -H tp.com -p 9508
如果啟動了多個不同端口的服務,reload
、restart
和stop
操作必須也是針對某個端口的才能正確操作,我們以reload
操作為例進行說明。
如果我們需要reload
前面啟動的tp.com:9508
服務,下面的指令是錯誤的
php think swoole reload
可能會出現錯誤提示:
no swoole http server process running.
必須帶上正確的端口號(host
不是必須的)
php think swoole reload -p 9508
然后,你會看到提示信息如下,表示reload
成功:
Reloading swoole http server...
> success
Cookie
和Session
由於Swoole
的特殊性,擴展本身接管了Cookie
類和Session
類的處理,因此不要調用(包括依賴注入)think\Cookie
和think\Session
類,而應該改為think\swoole\Cookie
類和think\swoole\Session
類。但think\facade\Cookie
和think\facade\Session
類的用法是正常的,因此原來的靜態方法調用依然可以正常使用。同時,Request
對象的cookie
方法和session
方法也可以正常使用。
關於Swoole
的Session
的用法,這里要特別強調下。
Swoole
是沒有Session
的概念,因此所有PHP內置的session
函數都是無效的,think-swoole
擴展單獨封裝了一個Session
類,和系統的Session
機制無關。
該擴展提供的think\swoole\Session
類是基於swoole_table
和ThinkPHP
緩存的混合解決方案。
每次Session::start()
的時候系統會從swoole_table
或者定義的緩存類型中獲取當前用戶的Session
數據,而session_id
數據則通過Cookie
獲取。並且在當前worker
進程中不會過期,但每次從swoole_table
或者緩存中獲取session
的時候則會判斷是否過期,session
的有效期還是通過session.php
配置文件的expire
配置參數進行設置。
swoole_table
一個基於共享內存和鎖實現的超高性能,並發數據結構。用於解決多進程/多線程數據共享和同步加鎖問題。
由於swoole_table
需要事先分配內存大小和字段定義,在swoole.php
配置文件中需要添加定義:
'table' => [
// 定義最大記錄數
'size' => 1024,
// 字段類型定義(目前僅支持 string int 和 float類型)
'column' =>[
'data' => ['string',255], // 字符串類型 長度為255個字節
'expire'=> ['int',8], // 整型 長度為8
],
],
swoole_table
分配的內存無法動態擴容和調整字段類型,如果修改則需要重啟才能生效。
然后在session.php
配置文件中,添加
'use_swoole_table' => true,
swoole_table
是一個可選方案。我們更建議使用緩存機制來處理Session
,如果你的應用比較大,則應該配置使用redis
之類的緩存機制更加適合,直接在你的cache.php
中定義相關緩存配置即可。
為了避免復雜,swoole的
Session
類不再支持prefix
參數,如果需要區分比如前后台不同session
的需求,可以使用name
參數進行區分。
文件監控
由於Swoole
服務運行過程中PHP文件是常駐內存運行的,這樣可以避免重復讀取磁盤、重復解釋編譯PHP,以便達到最高性能。所以更改業務代碼后必須手動reload
或者restart
才能生效。
think-swoole
擴展提供了監控文件更新的功能,在檢測到相關目錄的文件有更新后會自動reload
,從而不需要手動進行reload
操作,方便開發調試。
如果你的應用開啟了調試模式,文件監控功能是自動開啟的。原則上,在部署模式下不建議開啟文件監控,一方面有性能損耗,另外一方面對文件所做的任何修改都需要確認無誤才能進行更新部署。如果你確實需要在部署模式下開啟文件監控,可以設置如下:
'file_monitor' => true, // 開啟文件監控
'file_monitor_interval' => 1, // 文件監控檢測的時間間隔
'file_monitor_path' => '', // 文件監控目錄 一般不需要設置 默認會監控應用目錄和配置目錄
事件回調
擴展自帶的HTTPServer
包含了onWorkerStart
和onRequest
兩個事件回調,你如果需要增加其它的回調事件處理,可以在配置文件中直接添加:
'WorkerStop' => function($server, $worker_id) {
},
'WorkerError' => function($serv, $worker_id, $worker_pid, $exit_code, $signal) {
},
關於事件回調的具體用法,可以參考swoole
官方文檔。
如果不熟悉內部機制,請勿隨意替換和更改
onWorkerStart
和onRequest
事件回調,會導致不可預期的結果。
Nginx+Swoole
部署
可以使用Nginx
請求轉發到Swoole
的方式部署,充分發揮Nginx
的配置優勢和強大功能。
server {
listen 80;
root /var/www/tp/public/;
server_name 127.0.0.1;
index index.html index.htm index.php;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "keep-alive";
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:9501;
}
}
靜態資源訪問
如果你沒有使用Nginx
代理的話,為了確保靜態資源的正常訪問,請確認下面的參數配置正確:
// 網站根目錄位置
'document_root' => Env::get('root_path') . 'public',
// 開啟靜態資源處理
'enable_static_handler' => true,
使用Chrome瀏覽器會自動請求一次
favicon.ico
,所以確保你的網站根目錄下面有存在favicon.ico
文件,否則會產生一次404
請求的錯誤日志。
HTTPS
和HTTP2
支持
如果需要配置你的HTTP
服務支持HTTPS
,需要增加配置如下:
'ssl' => true,
'ssl_cert_file' => __DIR__.'/ssl.crt',
'ssl_key_file' => __DIR__.'/ssl.key',
記得准確指定你的cert
證書和key
私鑰的路徑。
使用
SSL
必須在編譯swoole
時加入--enable-openssl
選項
如果需要支持HTTP2
協議,則在SSL支持的基礎上還需要在編譯的時候加入--enable-http2
選項
./configure --enable-openssl --enable-http2
然后在swoole.php
中增加配置
'open_http2_protocol' => true
其它注意事項
為了讓你的應用能夠順利的運行在
Swoole
上面,擴展做了大量的底層處理工作,包括讓你的請求數據、Cookie
和Session
正常運作。
在
Swoole
下面,不能使用$_GET
、$_POST
、$_REQUEST
、$_SERVER
、$_COOKIE
以及$_SESSION
等原生的PHP用法,只能使用框架提供的類和方法進行獲取。
錯誤的用法:
$name = $_GET['name'];
$name = $_POST['name'];
$name = $_COOKIE['name'];
$name = $_SESSION['name'];
$host = $_SERVER['HTTP_HOST'];
V2.0.11+
版本開始,系統可以支持原生全局變量的獲取,但仍然不建議使用。
正確的用法(以下用法都采用了Facade
靜態代理類):
$name = Request::get('name');
$name = Request::param('name');
$name = Cookie::get('name');
$name = Session::get('name');
$host = Request::server('http_host');
如果你要獲取php://input
內容,必須把原來的代碼
file_get_contents('php://input');
改成
Request::getInput();
不過更建議使用
Request::put();
因為可以支持json
數據的自動解析而不需要手動進行json_decode
。
由於onWorkerStart
運行的時候還沒有HTTP_HOST
,因此最好在應用配置文件config/app.php
中設置app_host
。
請不要調用PHP原生的header
方法,使用Response
對象的header
方法替代。
不要使用PHP原生的session
相關函數,使用Session
類的相關方法。
目前為止,尚有一些功能不夠完善(例如文件上傳之類),請期待后續版本更新。
快速啟動Swoole Server
現在來看第二個場景,通過簡單的配置快速啟動一個swoole
服務,包括WebSocket
/Http
/Socket
服務。
可以支持直接啟動一個Swoole server(需要think-swoole
擴展 2.0.9+
版本)
php think swoole:server
會顯示如下信息:
Starting swoole server...
Swoole socket server started: <0.0.0.0:9508>
You can exit with `CTRL-C`
這個時候已經在0.0.0.0:9508
啟動一個Websocket
服務。
你可以在瀏覽器中訪問
http://127.0.0.1:9508
會看到類似下面的頁面(后面是一串隨機數)。
守護進程
如果需要使用守護進程方式運行,可以使用
php think swoole:server -d
或者在swoole.php
文件中設置
'daemonize' => true
配置文件
如果需要自定義參數,可以在config/swoole_server.php
中進行配置,包括:
配置參數 | 描述 | 默認值 |
---|---|---|
type | 服務類型(支持socket、http或者留空) | socket |
host | 監聽地址 | 0.0.0.0 |
port | 監聽端口 | 9508 |
mode | 運行模式 | SWOOLE_PROCESS |
sock_type | Socket type | SWOOLE_SOCK_TCP |
daemonize | 守護進程 | false |
注意不要和
swoole.php
文件文件混淆,兩者的作用完全不同。
並且支持swoole
所有的參數,以及支持使用閉包方式定義相關事件回調。
return [
// 擴展自身配置
'host' => '0.0.0.0', // 監聽地址
'port' => 9501, // 監聽端口
'type' => 'socket', // 服務類型 支持 socket http或者留空
'mode' => SWOOLE_PROCESS,
'sock_type' => SWOOLE_SOCK_TCP,
// 可以支持swoole的所有配置參數
'daemonize' => false,
'worker_num' => 4,
// 事件回調定義
'onOpen' => function ($server, $request) {
echo "server: handshake success with fd{$request->fd}\n";
},
'onMessage' => function ($server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$server->push($frame->fd, "this is server");
},
'onRequest' => function ($request, $response) {
$response->end("<h1>Hello Swoole. #" . rand(1000, 9999) . "</h1>");
},
'onClose' => function ($ser, $fd) {
echo "client {$fd} closed\n";
},
];
自定義服務類
如果你需要更高級的自定義事件回調,也可以使用自定義的Swoole
服務類。
<?php
namespace app\http;
use think\swoole\Server;
class Swoole extends Server
{
protected $host = '127.0.0.1';
protected $port = 9502;
protected $serverType = 'socket';
protected $mode = SWOOLE_PROCESS;
protected $sockType = SWOOLE_SOCK_TCP;
protected $option = [
'worker_num'=> 4,
'daemonize' => true,
'backlog' => 128
];
public function onReceive($server, $fd, $from_id, $data)
{
$server->send($fd, 'Swoole: '.$data);
}
}
自定義服務類必須繼承
think\swoole\Server
類,支持swoole
所有的回調方法定義(回調方法必須是public
類型)。
serverType
屬性定義為 socket
或者http
則支持swoole的swoole_websocket_server
和swoole_http_server
然后在swoole_server.php
中增加配置參數:
return [
'swoole_class' => 'app\http\Swoole',
];
定義該參數后,其它配置參數均不再有效。
然后就可以在命令行啟動服務端
php think swoole:server
一樣可以支持使用守護進程模式運行,
php think swoole:server -d
同樣也支持reload
、restart
和stop
操作。
php think swoole:server reload
客戶端代碼的實現有很多,如果你是使用PHP的話,可以用Swoole\Client
類。
<?php
namespace app\index\controller;
use Swoole\Client;
use think\Controller;
class Test extends Controller
{
public function index() {
$client = new Client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
$ret = $client->connect("127.0.0.1", 9501);
if(empty($ret)){
echo 'error!connect to swoole_server failed';
} else {
$client->send('test');
}
}
}
啟動多個swoole
服務
你可以通過命令行的指令啟動多個不同端口的swoole
服務,例如:
php think swoole:server -p 9800
php think swoole:server -p 9700
如果要分別對不同端口的服務進行stop
操作,務必使用
php think swoole:server stop -p 9800
php think swoole:server stop -p 9700
原文地址:https://www.kancloud.cn/thinkphp/think-swoole/722895