2021年5月24日13:51:59
官方文檔:https://laravel.com/docs/8.x/octane
Laravel Octane
- 介紹
- 安裝
- 服務器先決條件
- RoadRunner
- Swoole
- 為您的應用服務
- 通過 HTTPS 為您的應用程序提供服務
- 通過 Nginx 為您的應用程序提供服務
- 監視文件更改
- 指定工人數量
- 指定最大請求計數
- 重新加載工人
- 停止服務器
- 依賴注入和Octane
- 容器注入
- 請求注入
- 配置庫注入
- 管理內存泄漏
- 並發任務
- Ticks & Intervals
- Octane 緩存
- 表
介紹
Laravel Octane 通過使用高性能應用服務器(包括Swoole和RoadRunner )為您的應用程序提供服務來增強應用程序的性能。Octane 啟動您的應用程序一次,將其保存在內存中,然后以超音速向其發送請求。
安裝
Octane 可以通過 Composer 包管理器安裝:
composer require laravel/octane
安裝 Octane 后,您可以執行octane:install Artisan 命令,這會將 Octane 的配置文件安裝到您的應用程序中:
php artisan octane:install
服務器先決條件
Laravel Octane 需要PHP 8.0+。
RoadRunner
RoadRunner由 RoadRunner 二進制文件提供支持,該二進制文件是使用 Go 構建的。當您第一次啟動基於 RoadRunner 的 Octane 服務器時,Octane 會為您下載並安裝 RoadRunner 二進制文件。
RoadRunner 通過 Laravel Sail
如果你打算使用Laravel Sail開發你的應用程序,你應該運行以下命令來安裝 Octane 和 RoadRunner:
./vendor/bin/sail up
./vendor/bin/sail composer require laravel/octane spiral/roadrunner
接下來,您應該啟動一個 Sail shell 並使用rr可執行文件來檢索 RoadRunner 二進制文件的最新基於 Linux 的構建:
./vendor/bin/sail shell
# Within the Sail shell... ./vendor/bin/rr get-binary
安裝 RoadRunner 二進制文件后,您可以退出 Sail shell 會話。您現在需要調整supervisor.confSail 使用的文件以保持應用程序運行。首先,執行sail:publishArtisan 命令:
./vendor/bin/sail artisan sail:publish
接下來,更新command您的應用程序docker/supervisord.conf文件的指令,以便 Sail 使用 Octane 而不是 PHP 開發服務器為您的應用程序提供服務:
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=roadrunner --host=0.0.0.0 --rpc-port=6001 --port=8000
最后,確保rr二進制文件是可執行的並構建您的 Sail 鏡像:
chmod +x ./rr ./vendor/bin/sail build --no-cache
Swoole
如果你打算使用 Swoole 應用服務器來為你的 Laravel Octane 應用提供服務,你必須安裝 Swoole PHP 擴展。通常,這可以通過 PECL 完成:
pecl install swoole
通過 Laravel Sail Swoole
在通過 Sail 提供 Octane 應用程序之前,請確保您擁有最新版本的 Laravel Sail 並
./vendor/bin/sail build --no-cache在應用程序的根目錄中執行。
或者,您可以使用Laravel Sail開發基於 Swoole 的 Octane 應用程序,Laravel 基於Docker 的官方開發環境。Laravel Sail 默認包含 Swoole 擴展。但是,您仍然需要調整supervisor.conf Sail 使用的文件以保持應用程序運行。首先,執行sail:publish Artisan 命令:
./vendor/bin/sail artisan sail:publish
接下來,更新command您的應用程序docker/supervisord.conf文件的指令,以便 Sail 使用 Octane 而不是 PHP 開發服務器為您的應用程序提供服務:
command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=swoole --host=0.0.0.0 --port=8000
最后,構建您的 Sail 鏡像:
./vendor/bin/sail build --no-cache
為您的應用服務
Octane 服務器可以通過octane:start Artisan 命令啟動。默認情況下,此命令將使用由server應用程序octane配置文件的配置選項指定的服務器:
php artisan octane:start
默認情況下,Octane 將在端口 8000 上啟動服務器,因此您可以通過http://localhost:8000.
通過 HTTPS 為您的應用程序提供服務
默認情況下,通過 Octane 運行的應用程序生成前綴為http://. OCTANE_HTTPS 在您的應用程序的config/octane.php配置文件中使用的環境變量可以在true通過 HTTPS 為您的應用程序提供服務時設置。當此配置值設置為 時true,Octane 將指示 Laravel 為所有生成的鏈接添加前綴https://:
'https' => env('OCTANE_HTTPS', false),
通過 Nginx 為您的應用程序提供服務
如果您還沒有准備好管理自己的服務器配置,或者不習慣配置運行強大的 Laravel Octane 應用程序所需的所有各種服務,請查看Laravel Forge。
在生產環境中,您應該在傳統 Web 服務器(例如 Nginx 或 Apache)后面為 Octane 應用程序提供服務。這樣做將允許 Web 服務器為您的靜態資產(例如圖像和樣式表)提供服務,並管理您的 SSL 證書終止。
在下面的 Nginx 配置示例文件中,Nginx 將向在端口 8000 上運行的 Octane 服務器提供站點的靜態資產和代理請求:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name domain.com;
server_tokens off;
root /home/forge/domain.com/public;
index index.php;
charset utf-8;
location /index.php {
try_files /not_exists @octane;
}
location / {
try_files $uri $uri/ @octane;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/domain.com-error.log error;
error_page 404 /index.php;
location @octane {
set $suffix "";
if ($uri = /index.php) {
set $suffix ?$query_string;
}
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://127.0.0.1:8000$suffix;
}
}
監視文件更改
由於您的應用程序在 Octane 服務器啟動時加載到內存中,因此在您刷新瀏覽器時不會反映對應用程序文件的任何更改。例如,routes/web.php在服務器重新啟動之前,添加到文件中的路由定義不會被反映。為方便起見,您可以使用該--watch標志來指示 Octane 在應用程序中的任何文件更改時自動重新啟動服務器:
php artisan octane:start --watch
在使用此功能之前,您應該確保Node安裝在您的本地開發環境中。此外,您應該在您的 project:library 中安裝Chokidar文件監視庫:
npm install --save-dev chokidar
您可以使用watch應用程序config/octane.php配置文件中的配置選項來配置應該監視的目錄和文件。
指定工人數量
默認情況下,Octane 將為您的機器提供的每個 CPU 內核啟動一個應用程序請求工作程序。然后,這些工作人員將用於在進入您的應用程序時為傳入的 HTTP 請求提供服務。您可以--workers在調用octane:start命令時手動指定要開始使用該選項的工人數量:
php artisan octane:start --workers=4
如果您使用的是 Swoole 應用服務器,您還可以指定您希望啟動多少個“任務工作者”:
php artisan octane:start --workers=4 --task-workers=6
指定最大請求計數
為了幫助防止雜散內存泄漏,Octane 可以在處理了給定數量的請求后優雅地重新啟動工作程序。要指示 Octane 執行此操作,您可以使用以下--max-requests選項:
php artisan octane:start --max-requests=250
重新加載工人
您可以使用該octane:reload命令優雅地重新啟動 Octane 服務器的應用程序工作線程。通常,這應該在部署后完成,以便將新部署的代碼加載到內存中並用於為后續請求提供服務:
php artisan octane:reload
停止服務器
您可以使用octane:stopArtisan 命令停止 Octane 服務器:
php artisan octane:stop
檢查服務器狀態
您可以使用octane:statusArtisan 命令檢查 Octane 服務器的當前狀態:
php artisan octane:status
依賴注入和octane
由於 Octane 引導您的應用程序一次並在處理請求時將其保存在內存中,因此在構建應用程序時您應該考慮一些注意事項。例如,您的應用程序服務提供者的register和boot方法只會在請求工作器最初啟動時執行一次。在后續請求中,將重用相同的應用程序實例。
有鑒於此,在將應用服務容器或請求注入任何對象的構造函數時應特別小心。通過這樣做,該對象可能具有容器的陳舊版本或對后續請求的請求。
Octane 將自動處理在請求之間重置任何第一方框架狀態。但是,Octane 並不總是知道如何重置由您的應用程序創建的全局狀態。因此,您應該了解如何以一種對 Octane 友好的方式構建您的應用程序。下面,我們將討論在使用 Octane 時可能導致問題的最常見情況。
容器注入
一般來說,你應該避免將應用服務容器或 HTTP 請求實例注入到其他對象的構造函數中。例如,以下綁定將整個應用程序服務容器注入到綁定為單例的對象中:
use App\Service; /** * Register any application services. * * @return void */ public function register() { $this->app->singleton(Service::class, function ($app) { return new Service($app); }); }
在此示例中,如果Service在應用程序啟動過程中解析了實例,則容器將被注入到服務中,並且該容器將Service在后續請求中由實例持有。對於您的特定應用程序,這可能不是問題;但是,它可能導致容器意外丟失在引導周期后期或由后續請求添加的綁定。
作為一種解決方法,您可以停止將綁定注冊為單例,或者您可以將容器解析器閉包注入到始終解析當前容器實例的服務中:
use App\Service; use Illuminate\Container\Container; $this->app->bind(Service::class, function ($app) { return new Service($app); }); $this->app->singleton(Service::class, function () { return new Service(fn () => Container::getInstance()); });
全局app助手和Container::getInstance()方法將始終返回應用程序容器的最新版本。
請求注入
一般來說,你應該避免將應用服務容器或 HTTP 請求實例注入到其他對象的構造函數中。例如,以下綁定將整個請求實例注入到綁定為單例的對象中:
use App\Service; /** * Register any application services. * * @return void */ public function register() { $this->app->singleton(Service::class, function ($app) { return new Service($app['request']); }); }
在此示例中,如果Service在應用程序啟動過程中解析了實例,則 HTTP 請求將被注入到服務中,並且該Service實例將在后續請求中保留相同的請求。因此,所有標頭、輸入和查詢字符串數據以及所有其他請求數據都將不正確。
作為一種變通方法,您可以停止將綁定注冊為單例,或者您可以將請求解析器閉包注入到始終解析當前請求實例的服務中。或者,最推薦的方法是在運行時將對象所需的特定請求信息傳遞給對象的方法之一:
use App\Service; $this->app->bind(Service::class, function ($app) { return new Service($app['request']); }); $this->app->singleton(Service::class, function ($app) { return new Service(fn () => $app['request']); }); // Or... $service->method($request->input('name'));
全局request助手將始終返回應用程序當前正在處理的請求,因此可以安全地在您的應用程序中使用。
Illuminate\Http\Request在您的控制器方法和路由閉包上鍵入提示實例是可以接受的。
配置庫注入
通常,您應該避免將配置存儲庫實例注入到其他對象的構造函數中。例如,以下綁定將配置存儲庫注入到綁定為單例的對象中:
use App\Service; /** * Register any application services. * * @return void */ public function register() { $this->app->singleton(Service::class, function ($app) { return new Service($app->make('config')); }); }
在此示例中,如果配置值在請求之間發生更改,則該服務將無法訪問新值,因為它取決於原始存儲庫實例。
作為一種解決方法,您可以停止將綁定注冊為單例,或者您可以將配置存儲庫解析器閉包注入該類:
use App\Service; use Illuminate\Container\Container; $this->app->bind(Service::class, function ($app) { return new Service($app->make('config')); }); $this->app->singleton(Service::class, function () { return new Service(fn () => Container::getInstance()->make('config')); });
全局config將始終返回最新版本的配置存儲庫,因此可以安全地在您的應用程序中使用。
管理內存泄漏
請記住,Octane 在請求之間將您的應用程序保存在內存中;因此,將數據添加到靜態維護的數組將導致內存泄漏。例如,以下控制器存在內存泄漏,因為對應用程序的每個請求都會繼續向靜態$data數組添加數據:
use App\Service; use Illuminate\Http\Request; use Illuminate\Support\Str; /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @return void */ public function index(Request $request) { Service::$data[] = Str::random(10); // ... }
在構建您的應用程序時,您應該特別注意避免產生這些類型的內存泄漏。建議您在本地開發期間監控應用程序的內存使用情況,以確保不會將新的內存泄漏引入應用程序。
並發任務
此功能需要Swoole。
使用 Swoole 時,您可以通過輕量級后台任務並發執行操作。您可以使用 Octane 的concurrently方法完成此操作。您可以將此方法與 PHP 數組解構結合使用,以檢索每個操作的結果:
use App\User; use App\Server; use Laravel\Octane\Facades\Octane; [$users, $servers] = Octane::concurrently([ fn () => User::all(), fn () => Server::all(), ]);
Octane 處理的並發任務利用 Swoole 的“任務工作者”,並在與傳入請求完全不同的進程中執行。可用於處理並發任務的工人數量由命令中的--task-workers指令決定octane:start:
php artisan octane:start --workers=4 --task-workers=6
Ticks & Intervals
此功能需要Swoole。
使用 Swoole 時,您可以注冊將每指定秒數執行的“tick”操作。您可以通過該tick方法注冊“tick”回調。提供給該tick方法的第一個參數應該是一個表示股票代碼名稱的字符串。第二個參數應該是一個將在指定時間間隔調用的可調用對象。
在這個例子中,我們將注冊一個每 10 秒調用一次的閉包。通常,該tick方法應在boot應用程序的服務提供者之一的方法中調用:
Octane::tick('simple-ticker', fn () => ray('Ticking...')) ->seconds(10);
使用該immediate方法,您可以指示 Octane 在 Octane 服務器初始啟動時立即調用 tick 回調,此后每 N 秒:
Octane::tick('simple-ticker', fn () => ray('Ticking...')) ->seconds(10) ->immediate();
Octane 緩存
此功能需要Swoole。
使用 Swoole 時,您可以利用 Octane 緩存驅動程序,它提供高達每秒 200 萬次操作的讀取和寫入速度。因此,對於需要從其緩存層獲得極高讀/寫速度的應用程序,此緩存驅動程序是絕佳選擇。
此緩存驅動程序由Swoole 表提供支持。服務器上的所有工作人員都可以使用緩存中存儲的所有數據。但是,當服務器重新啟動時,緩存的數據將被刷新:
Cache::store('octane')->put('framework', 'Laravel', 30);
Octane 緩存中允許的最大條目數可以在應用程序的
octane配置文件中定義。
緩存間隔
除了 Laravel 緩存系統提供的典型方法之外,Octane 緩存驅動程序還具有基於間隔的緩存。這些緩存會在指定的時間間隔自動刷新,並且應該在boot您的應用程序的服務提供者之一的方法中注冊。例如,以下緩存將每五秒刷新一次:
use Illuminate\Support\Str; Cache::store('octane')->interval('random', function () { return Str::random(10); }, seconds: 5)
表
此功能需要Swoole。
使用 Swoole 時,您可以定義自己的任意Swoole 表並與之交互。Swoole 表提供了極高的性能吞吐量,這些表中的數據可以被服務器上的所有工作人員訪問。但是,當服務器重新啟動時,其中的數據將丟失。
表應該在tables應用程序octane配置文件的配置數組中定義。已經為您配置了一個最多允許 1000 行的示例表。可以通過在列類型后指定列大小來配置字符串列的最大大小,如下所示:
'tables' => [ 'example:1000' => [ 'name' => 'string:1000', 'votes' => 'int', ], ],
要訪問表,您可以使用以下Octane::table方法:
use Laravel\Octane\Facades\Octane; Octane::table('example')->set('uuid', [ 'name' => 'Nuno Maduro', 'votes' => 1000, ]); return Octane::table('example')->get('uuid');
通過Swoole表格支持的列類型:
string,int,和float。
