基于上一篇文章swoole+tp5異步多線程,發現很多問題,所以深入理解一下swoole的進程模型
想探討一下swoole,swoole在大流量生產環境下需要哪些特別注意的地方, 求指導,聯系我就可以
運行環境linux? 服務開啟命令? php think Tcp
namespace app\swoole\command;
use app\common\cache\Redis;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;
use think\Log;
class Tcp extends Command{
TP5命令行使用方法,手冊可以查到,原理是加載文件并執行文件
? ? protected function configure(){
? ? ? ? $this->setName('Tcp')->setDescription('OK ');
? ? }
? ? public function execute(Input $input, Output $output){
參數配置
? ? ? ? $serv = new \swoole_server("0.0.0.0", 9501);
? ? ? ? $serv->set([
? ? ? ? ? ? 'reactor_num' => 1,//同服務器核心數
? ? ? ? ? ? 'worker_num' => 2,//同服務器核心數或1--4倍服務器核心數
? ? ? ? ? ? 'task_worker_num' => 4,//當task繁忙導致server沒有響應請求時,可以適當增加num,具體根據官方文檔和試運行情況修改
? ? ? ? ? ? 'backlog' => 128,
? ? ? ? ? ? 'daemonize' => 0,//加入此參數后,執行php server.php將轉入后臺作為守護進程運行
? ? ? ? ? ? 'max_conn' => 10000,//此參數用來設置Server最大允許維持多少個tcp連接。超過此數量后,新進入的連接將被拒絕。
? ? ? ? ? ? 'max_request' => 2000,//此參數表示worker進程在處理完n次請求后結束運行。manager會重新創建一個worker進程。此選項用來防止worker進程內存溢出。
//? ? ? ? ? 'log_file' => '/data/log/Swoole.log',//指定swoole錯誤日志文件。在swoole運行期發生的異常信息會記錄到這個文件中。默>認會打印到屏幕。
? ? ? ? ? ? 'heartbeat_check_interval' => 30,//每隔多少秒檢測一次,單位秒,Swoole會輪詢所有TCP連接,將超過心跳時間的連接關閉掉
? ? ? ? ? ? 'heartbeat_idle_time' => 60,//TCP連接的最大閑置時間,單位s , 如果某fd最后一次發包距離現在的時間超過? ? heartbeat_idle_time必須大于或等于heartbeat_check_interval
? ? ? ? ? ? 'task_max_request' => 100,//設置task進程的最大任務數。一個task進程在處理完超過此數值的任務后將自動退出。這個參數是為了防止PHP進程內存溢出。如果不希望進程自動退出可以設置為0。
? ? ? ? ? ? 'open_cpu_affinity' => 1,//啟用CPU親和性設置。在多核的硬件平臺中,啟用此特性會將swoole的reactor線程/worker進程綁定到固定的一個核上。可以避免進程/線程的運行時在多個核之間互相切換,提高CPU Cache的命中率。
? ? ? ? ]);
常用方法的回調函數
? ? ? ? $serv->on('start', function ($serv){
? ? ? ? ? ? $this->timter();
? ? ? ? ? ? echo "第一步master進程被拉起\n";
? ? ? ? });
注意:如果manager進程和worker進程存在多個,請不要在manager和worker進程中開啟全局任務
? ? ? ? $serv->on('ManagerStart', function ($serv){
? ? ? ? ? ? echo "第二步指定數目的調度reactor進程被拉起\n";
? ? ? ? });
? ? ? ? $serv->on('WorkerStart', function ($serv){
? ? ? ? ? ? echo "第三步指定數目的worker進程被拉起\n";
? ? ? ? });
? ? ? ? $serv->on('WorkerStop', function (){
? ? ? ? ? ? echo "第四步指定數目的worker進程被kill\n";
? ? ? ? });
? ? ? ? $serv->on('ManagerStop', function (){
? ? ? ? ? ? echo "第五步指定數目的reactor進程被kill\n";
? ? ? ? });
? ? ? ? $serv->on('shutdown', function (){
? ? ? ? ? ? echo "第六步master進程被kill\n";
? ? ? ? });
? ? ? ? $serv->on('receive', function($serv, $fd, $from_id, $data) {
? ? ? ? ? ? if(intval($data) == '9501'){
? ? ? ? ? ? ? ? $serv->reload();//觸發worker進程的stop方法
//? ? ? ? ? ? ? ? $serv->shutdown();//觸發所有進程的stop及shutdown方法
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? ? ? //投遞異步任務
? ? ? ? ? ? $task_id = $serv->task($data);
? ? ? ? ? ? echo "任務".$task_id."開始\n";
? ? ? ? });
? ? ? ? //模擬處理異步任務
? ? ? ? $serv->on('task', function ($serv, $task_id, $from_id, $data) {
? ? ? ? ? ? $begin = intval($data);
? ? ? ? ? ? $insertAll = [];
? ? ? ? ? ? for ($i = $begin; $i < $begin+20000; $i++){
? ? ? ? ? ? ? ? $insert = array();
? ? ? ? ? ? ? ? $insert['value'] = $i.mt_rand($i, $i+1000);
? ? ? ? ? ? ? ? $insert['addtime'] = time();
? ? ? ? ? ? ? ? $insert['from_id'] = $from_id;
? ? ? ? ? ? ? ? $insert['task_id'] = $task_id;
? ? ? ? ? ? ? ? $insertAll[] = $insert;
//? ? ? ? ? ? ? ? Db::table('test')->insert($insert);
? ? ? ? ? ? }
? ? ? ? ? ? Db::table('test')->insertAll($insertAll);
? ? ? ? ? ? //返回任務執行的結果
? ? ? ? ? ? unset($insertAll);
? ? ? ? ? ? $serv->finish("ID".$task_id);
? ? ? ? });
? ? ? ? //處理異步任務的結果
? ? ? ? $serv->on('finish', function ($serv, $task_id, $data) {
? ? ? ? ? ? echo "任務".$data."結束\n";
? ? ? ? });
? ? ? ? $serv->start();
? ? }
定時器調用方法
? ? private function timter(){
? ? ? ? \swoole_timer_tick(3000, function () {
? ? ? ? ? ? //30S一次
? ? ? ? ? ? echo 1;
? ? ? ? ? ? $this->checkPort();
? ? ? ? });
? ? }
監聽系統服務php-fpm/nginx/swoole
? ? private function checkPort(){
? ? ? ? $res = exec('netstat -apn | grep 9501');
? ? ? ? if(!$res){
? ? ? ? ? ? Log::write(time().'|9501|swooleStop');
? ? ? ? ? ? $this->sendEmail();
? ? ? ? }
? ? ? ? $res = exec('netstat -apn | grep 9000');
? ? ? ? if(!$res){
? ? ? ? ? ? Log::write(time().'|9000|fpmStop');
? ? ? ? ? ? $this->sendEmail();
? ? ? ? }
? ? ? ? $res = exec('netstat -apn | grep 80');
? ? ? ? if(!$res){
? ? ? ? ? ? Log::write(time().'|80|nginxStop');
? ? ? ? ? ? $this->sendEmail();
? ? ? ? }
}
郵件提醒
? ? private function sendEmail(){
? ? ? ? $email='xbc@gmail.com';
? ? ? ? $subject='線上提醒';
? ? ? ? $content='服務器出現問題請及時處理';
? ? ? ? send_email($email,$subject,$content);
? ? }
}