在之前文章中解析provider_admin的start流程时,分析到了最终调用TcpServer的run方法启动Provider应用。这篇开始我们分析TcpServer的相关方法和核心流程体系,TcpServer代码位于dubbo-php-framework-master/provider/core/server/TcpServer.php中。
从TcpServer的继承体系可以看出,TcpServer->BaseServer->IServer,这些类的定义都在和TcpServer同一个目录中,我们按模块的复杂度分析,首先我们分析下IServer。
//核心模块都使用了命名空间,比较规范
namespace com\fenqile\fsof\provider\core\server;
//声明接口
interface IServer
{
function run($setting);
function send($client_id, $data);
function close($client_id);
function setProtocol($protocol);
//当前app是否提供了满足条件的服务
function serviceExist($serviceName, $group, $version);
//获取app中满足条件的服务实例,一个app提供的所有服务都以单实例的形式存于内存中
function getServiceInstance($serviceName, $group, $version);
//获取app的监控器
function getAppMonitor();
}
//申明命名空间
namespace com\fenqile\fsof\provider\core\server;
//TcpServer继承自BaseServer
class TcpServer extends BaseServer
{
public function init()
{
//设置Swoole服务器网络通信模块,这里声明为Tcp类型
$this->sockType = SWOOLE_SOCK_TCP;
//设置Swoole Server的属性信息,这里设置为关闭Tcp nodelay算法
$setting = array(
'open_tcp_nodelay' => 1,
);
$this->setting = array_merge($this->setting, $setting);
}
}
BaseServer的实现过程牵涉模块较多,我们按provider_admin模块中start的过程进行解析,对于剩下的流程单独进行解析,流程如下图代码所示。
$server = new TcpServer($name);
//加载app root目录下的bootstrap.php和provider/$name.provider文件
$server->setRequire(FSOFConfigManager::getProviderAppRoot($name));
//app/conf目录下的$name.deploy文件
$server->loadConfig($config);
//全局fsof.ini文件
$server->loadConfig(FSOFConfigManager::getFSOFIni());
//设置swoole扩展日志文件
$server->setSwooleLogFile($cmd);
//provider启动时初始化consumer
$server->initConsumer();
//初始化server资源
$server->initRunTime('/var/fsof/provider');
//启动
$server->run($cmd);
BaseServer代码量较大,这篇我们只解析BaseServer的构造函数过程(这块开源的代码注释较好,我没自己分析,请谅解),其他的在后面篇章分开讨论。
namespace com\fenqile\fsof\provider\core\server;
use com\fenqile\fsof\common\log\FSOFSystemUtil;
use com\fenqile\fsof\common\file\FileSystemUtil;
use com\fenqile\fsof\common\config\FSOFConstants;
use com\fenqile\fsof\common\config\FSOFConfigManager;
use com\fenqile\fsof\common\protocol\fsof\DubboParser;
use com\fenqile\fsof\common\protocol\fsof\DubboResponse;
use com\fenqile\fsof\consumer\FSOFConsumer;
use com\fenqile\fsof\provider\common\Console;
use com\fenqile\fsof\provider\core\app\AppLauncher;
use com\fenqile\fsof\provider\core\app\AppContext;
use com\fenqile\fsof\provider\core\protocol\IProtocol;
use com\fenqile\fsof\provider\monitor\AppMonitor;
use com\fenqile\fsof\provider\monitor\OverloadMonitor;
abstract class BaseServer implements IServer
{
//定义过载默认参数
const FSOF_SWOOLE_WAITING_TIME_MS = 1500;
const FSOF_SWOOLE_OVERLOAD_NUM_INAROW = 5;
const FSOF_SWOOLE_LOSS_NUM_INAROW = 20;
protected $sw;
protected $processName = 'ProviderServer';
protected $host = '0.0.0.0';
protected $port = 9527;
protected $listen;//监听ip与端口号的array
protected $mode = SWOOLE_PROCESS;
protected $sockType;
protected $config = array(); //服务的配置信息
protected $setting = array();//swoole_server配置
protected $runPath = '/var/fsof/provider';
protected $masterPidFile;
protected $managerPidFile;
protected $user = 'root';
protected $protocol;
protected $rootFile = ''; //deploy中root路径
protected $deployVersion = NULL;//provider发布版本
protected $requireFile = ''; //provider启动文件
protected $serverProviders = NULL; //服务提供者信息
protected $appContext; //服务提供者存储容器
//当发生shutdown时,将错误信息回传给client
protected $cur_fd = -1;
protected $cur_from_id = -1;
protected $request = array();
protected $start_without_registry = false;
//app过载监控对象
protected $overloadMonitor;
private $logger;
public function __construct($name = 'ProviderServer')
{
$this->logger = \Logger::getLogger(__CLASS__);
$this->processName = $name;
// Initialization server startup parameters
$this->setting = array(
'worker_num' => 4, //PHP代码中是全异步非阻塞,worker_num配置为CPU核数的1-4倍即可。如果是同步阻塞,worker_num配置为100或者更高,具体要看每次请求处理的耗时和操作系统负载状况
'max_request' => 5000, //表示worker进程在处理完n次请求后结束运行,设置为0表示不自动重启。在Worker进程中需要保存连接信息的服务,需要设置为0.
'dispatch_mode' => 3, // 1平均分配,2按FD取摸固定分配,3抢占式分配,默认为取摸(dispatch=2)
'task_worker_num' => 0, // task process num
'task_max_request' =>5000,
'task_ipc_mode' =>3, //1 使用unix socket通信 , 2使用消息队列通信, 3使用消息队列通信,并设置为争抢模式,此时task/taskwait将无法指定目标进程ID
'max_conn' => 10000, // 设置Server最大允许维持多少个tcp连接,max_connection默认值为ulimit -n的值为1024,通过ulimit -n 65535更改最大默认值
'daemonize' => TRUE, // 是否开启守护进程
'work_mode' => 3, // 1 base模式,2线程模式,3进程模式
//协议包长度检测,以保证onReceive函数接收到的数据是个完整的包,并且包的最大长度为2M
'open_length_check' => TRUE,
'package_length_offset' => 12,
'package_body_offset' => 16,
'package_length_type' => 'N',
'package_max_length' =>1024*1024*2,
//启用心跳检测,此选项表示每隔多久轮循一次,单位为秒
'heartbeat_idle_time' => 600,
'heartbeat_check_interval' => 60,
//TCP-Keepalive死连接检测,如果对于死链接周期不敏感或者没有实现心跳机制,可以使用操作系统提供的keepalive机制来踢掉死链接
'open_tcp_keepalive' => 1, // 表示启用tcp keepalive
'tcp_keepidle' => 600, // 单位秒,连接在n秒内没有数据请求,将开始对此连接进行探测
'tcp_keepcount' => 3, // 探测的次数,超过次数后将close此连接。
'tcp_keepinterval' => 10, // 探测的间隔时间,单位秒。
);
$this->setHost();
$this->init();
}