學習路之PHP--easyswoole入門
- 一、框架說明
- 二、常用命令
- 三、文件熱加載
一、框架說明
- 目錄結構
目錄結構
project 項目部署目錄
├─App 應用目錄(可以有多個)
│ ├─HttpController 控制器目錄
│ │ └─Index.php 默認控制器
│ └─Model 模型文件目錄
├─Log 日志文件目錄
├─Temp 臨時文件目錄
├─vendor 第三方類庫目錄
├─composer.json Composer架構
├─composer.lock Composer鎖定
├─EasySwooleEvent.php 框架全局事件
├─easyswoole 框架管理腳本
├─easyswoole.install 框架安裝鎖定文件
├─dev.php 開發配置文件
├─produce.php 生產配置文件
————————————————
- 生命周期
- 配置文件說明 dev.php、produce.php
<?phpreturn ['SERVER_NAME' => "EasySwoole",//服務名'MAIN_SERVER' => ['LISTEN_ADDRESS' => '0.0.0.0',//監聽地址'PORT' => 9501,//監聽端口'SERVER_TYPE' => EASYSWOOLE_WEB_SERVER, //可選為 EASYSWOOLE_SERVER EASYSWOOLE_WEB_SERVER EASYSWOOLE_WEB_SOCKET_SERVER'SOCK_TYPE' => SWOOLE_TCP,//該配置項當為SERVER_TYPE值為TYPE_SERVER時有效'RUN_MODEL' => SWOOLE_PROCESS,// 默認Server的運行模式'SETTING' => [// Swoole Server的運行配置( 完整配置可見[Swoole文檔](https://wiki.swoole.com/wiki/page/274.html) )'worker_num' => 8,//運行的 worker進程數量'max_request' => 5000,// worker 完成該數量的請求后將退出,防止內存溢出'task_worker_num' => 8,//運行的 task_worker 進程數量'task_max_request' => 1000,// task_worker 完成該數量的請求后將退出,防止內存溢出'reload_async' => true,//設置異步重啟開關。設置為true時,將啟用異步安全重啟特性,Worker進程會等待異步事件完成后再退出。'task_enable_coroutine' => true//開啟后自動在onTask回調中創建協程]],'TEMP_DIR' => null,//臨時文件存放的目錄'LOG_DIR' => null,//日志文件存放的目錄'CONSOLE' => [//console控制臺組件配置'ENABLE' => true,//是否開啟'LISTEN_ADDRESS' => '127.0.0.1',//監聽地址'PORT' => 9500,//監聽端口'USER' => 'root',//驗權用戶名'PASSWORD' => '123456'//驗權用戶名],'FAST_CACHE' => [//fastCache組件'PROCESS_NUM' => 0,//進程數,大于0才開啟'BACKLOG' => 256,//數據隊列緩沖區大小],'DISPLAY_ERROR' => true,//是否開啟錯誤顯示];
- 配置操作類
EasySwoole\Config 類
toArray 方法獲取全部配置,load 方法重載全部配置
如果設置了修改,需要更新配置的意思
$instance = \EasySwoole\EasySwoole\Config::getInstance();
// 獲取配置 按層級用點號分隔
$instance->getConf('MAIN_SERVER.SETTING.task_worker_num');
// 設置配置 按層級用點號分隔
$instance->setConf('DATABASE.host', 'localhost');
// 獲取全部配置
$conf = $instance->getConf();
// 用一個數組覆蓋當前配置項
$conf['DATABASE'] = ['host' => '127.0.0.1','port' => 13306
];
$instance->load($conf);
添加用戶配置項
'MYSQL' => ['host' => '192.168.75.1','port' => '3306','user' => 'root','timeout' => '5','charset' => 'utf8mb4','password' => 'root','database' => 'cry','POOL_MAX_NUM' => '20','POOL_TIME_OUT' => '0.1',
],
/*################ REDIS CONFIG ##################*/
'REDIS' => ['host' => '127.0.0.1','port' => '6379','auth' => '','POOL_MAX_NUM' => '20','POOL_MIN_NUM' => '5','POOL_TIME_OUT' => '0.1',
],
二、常用命令
install 安裝easySwoole
start 啟動easySwoole
stop 停止easySwoole(守護模式下使用)
reload 熱重啟easySwoole(守護模式下使用)
restart 重啟easySwoole(守護模式下使用)
守護模式啟動:
php easyswoole start d
線上:
php easyswoole start produce
停止:
php easyswoole stop
重啟服務:
php easyswoole reload 只重啟task進程
php easyswoole reload all 重啟task + worker進程 文件熱加載
生產與開發配置分離:
默認為開發模式,加載 dev.php
生產模式加載 produce.php
php easyswoole start produce
查看啟動情況:
bash netstat -tunlp | grep 9501
可以看到結果:
bash tcp 0 0 0.0.0.0:9501 0.0.0.0:* LISTEN 4015/EasySwoole
kill 4015 //普通關閉進程
kill -9 4015 //強制關閉進程
三、文件熱加載
由于 swoole 常駐內存的特性,修改文件后需要重啟worker進程才能將被修改的文件重新載入內存中
解決:Process的方式實現文件變動自動進行服務重載
- 新建文件 App/Process/HotReload.php 并添加如下內容,也可以放在其他位置,請對應命名空間
<?phpnamespace App\Process;use EasySwoole\Component\Process\AbstractProcess;
use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\Utility\File;
use Swoole\Process;
use Swoole\Table;
use Swoole\Timer;/*** 暴力熱重載* Class HotReload* @package App\Process*/
class HotReload extends AbstractProcess
{/** @var \swoole_table $table */protected $table;protected $isReady = false;protected $monitorDir; // 需要監控的目錄protected $monitorExt; // 需要監控的后綴/*** 啟動定時器進行循環掃描*/public function run($arg){// 此處指定需要監視的目錄 建議只監視App目錄下的文件變更$this->monitorDir = !empty($arg['monitorDir']) ? $arg['monitorDir'] : EASYSWOOLE_ROOT . '/App';// 指定需要監控的擴展名 不屬于指定類型的的文件 無視變更 不重啟$this->monitorExt = !empty($arg['monitorExt']) && is_array($arg['monitorExt']) ? $arg['monitorExt'] : ['php'];if (extension_loaded('inotify') && empty($arg['disableInotify'])) {// 擴展可用 優先使用擴展進行處理$this->registerInotifyEvent();echo "server hot reload start : use inotify\n";} else {// 擴展不可用時 進行暴力掃描$this->table = new Table(512);$this->table->column('mtime', Table::TYPE_INT, 4);$this->table->create();$this->runComparison();Timer::tick(1000, function () {$this->runComparison();});echo "server hot reload start : use timer tick comparison\n";}}/*** 掃描文件變更*/private function runComparison(){$startTime = microtime(true);$doReload = false;$dirIterator = new \RecursiveDirectoryIterator($this->monitorDir);$iterator = new \RecursiveIteratorIterator($dirIterator);$inodeList = array();// 迭代目錄全部文件進行檢查foreach ($iterator as $file) {/** @var \SplFileInfo $file */$ext = $file->getExtension();if (!in_array($ext, $this->monitorExt)) {continue; // 只檢查指定類型} else {// 由于修改文件名稱 并不需要重新載入 可以基于inode進行監控$inode = $file->getInode();$mtime = $file->getMTime();array_push($inodeList, $inode);if (!$this->table->exist($inode)) {// 新建文件或修改文件 變更了inode$this->table->set($inode, ['mtime' => $mtime]);$doReload = true;} else {// 修改文件 但未發生inode變更$oldTime = $this->table->get($inode)['mtime'];if ($oldTime != $mtime) {$this->table->set($inode, ['mtime' => $mtime]);$doReload = true;}}}}foreach ($this->table as $inode => $value) {// 迭代table尋找需要刪除的inodeif (!in_array(intval($inode), $inodeList)) {$this->table->del($inode);$doReload = true;}}if ($doReload) {$count = $this->table->count();$time = date('Y-m-d H:i:s');$usage = round(microtime(true) - $startTime, 3);if (!$this->isReady == false) {// 監測到需要進行熱重啟echo "severReload at {$time} use : {$usage} s total: {$count} files\n";ServerManager::getInstance()->getSwooleServer()->reload();} else {// 首次掃描不需要進行重啟操作echo "hot reload ready at {$time} use : {$usage} s total: {$count} files\n";$this->isReady = true;}}}/*** 注冊Inotify監聽事件*/private function registerInotifyEvent(){// 因為進程獨立 且當前是自定義進程 全局變量只有該進程使用// 在確定不會造成污染的情況下 也可以合理使用全局變量global $lastReloadTime;global $inotifyResource;$lastReloadTime = 0;$files = File::scanDirectory(EASYSWOOLE_ROOT . '/App');$files = array_merge($files['files'], $files['dirs']);$inotifyResource = inotify_init();// 為當前所有的目錄和文件添加事件監聽foreach ($files as $item) {inotify_add_watch($inotifyResource, $item, IN_CREATE | IN_DELETE | IN_MODIFY);}// 加入事件循環swoole_event_add($inotifyResource, function () {global $lastReloadTime;global $inotifyResource;$events = inotify_read($inotifyResource);if ($lastReloadTime < time() && !empty($events)) { // 限制1s內不能進行重復reload$lastReloadTime = time();ServerManager::getInstance()->getSwooleServer()->reload();}});}public function onShutDown(){// TODO: Implement onShutDown() method.}public function onReceive(string $str){// TODO: Implement onReceive() method.}
}
- 添加好后在全局的 EasySwooleEvent.php 中,注冊該自定義進程
use App\Process\HotReload;********************public static function mainServerCreate(EventRegister $register){// TODO: Implement mainServerCreate() method.$swooleServer = ServerManager::getInstance()->getSwooleServer();$swooleServer->addProcess((new HotReload('HotReload', ['disableInotify' => false]))->getProcess());}
- 效果
修改:easyswoole\App\HttpController\Index.php
$this->response()->write('hello2');
不需要重起easyswoole 直接訪問就有效果