swoole提供http服务

swoole是一个php的网络通信框架,可以简单支持http服务。按照官方介绍,如果遇到mysql或者广播消息等耗时或阻塞的业务,需要开启task去提供服务,在Finish回调中处理结果(定时器中如果有阻塞任务,会导致work进程无法提供服务)。

(需要安装配置扩展,如果源码编译运行提示glibc版本不兼容,可以用pecl install swoole)

针对一些数据不常变化的部分,我们可以用定时器读取到内存,然后提供服务,这样对mysql压力小了很多。大致示例代码如下:

#!/usr/bin/php
<?php 

date_default_timezone_set("Asia/Shanghai");
class RotateMap
{
	public function __construct ()
	{
		$this->d = array(array(), array());
		$this->idx = 0;
	}
	public function &get ()
	{
		return $this->d[$this->idx];
	}
	public function set ($t)
	{
		$this->d[!$this->idx] = $t;
		$this->swap();
	}
	private function swap ()
	{
		$this->idx = !$this->idx;
	}
	private $d;
	private $idx;
};

class Server
{
	private $serv;

	private $upgrade;
	private $allowurl;
	private $checkurl;

	const RELOAD_SECOND_INTERVAL 	= 1000;
	const RELOAD_MINUTE_INTERVAL 	= 60000;
	const RELOAD_HOUR_INTERVAL 	= 360000;
	const RELOAD_DAY_INTERVAL 	= 86400000;
	const ERROR_LOG = "/tmp/swoole.error.log";
	const LOCAL_TXT = "/tmp/localfile";

	public function __construct ()
	{
		$this->upgrade = new RotateMap();
		$this->allowurl = new RotateMap();
		$this->checkurl = new RotateMap();

		$this->serv = new swoole_http_server("127.0.0.1", 1987);
		$this->serv->set(array('worker_num' =>1,
					'daemonize' => true,
					'max_request' =>10000,
					'dispatch_mode' =>3,
					'debug_mode' =>1,
					'task_worker_num' =>1,
					'log_file' =>'/tmp/swoole.log'));

		$this->serv->on('Start', array($this, 'onStart'));
		$this->serv->on('Request', array($this, 'onRequest'));
		$this->serv->on('Task', array($this, 'onTask'));
		$this->serv->on('Finish', array($this, 'onFinish'));
		$this->serv->on('WorkerStart', array($this, 'onWorkerStart'));
		$this->serv->on('Timer', array($this, 'reloadDB'));

		$this->serv->start();
	}

	public function onStart($serv)
	{
	}

	private function slog($msg){
		echo "[".date('Y-m-d H:i:s')." #".$this->serv->worker_pid.".0]  INFO  ".$msg.PHP_EOL;
	}

	public function onWorkerStart($serv, $worker_id)
	{
		if($serv->taskworker == false){
			//Init Data
			$this->slog("InitData Begin");
			$this->reloadDBUpgrade(true);
			$this->reloadDB1(true);
			$this->reloadDB2(true);
			$this->slog("InitData Done");

			$serv->addtimer(Server::RELOAD_HOUR_INTERVAL);
		}
	}

	private function reloadDBUpgrade($save = false){
		try{
			$dsn='mysql:host=myhost;dbname=mydb;';
			$dbh=new PDO($dsn,"myusername","mypassword");
			$dbh->query('set names utf8;');
			$stmt=$dbh->query('SELECT id,name FROM tb_version ORDER BY id DESC LIMIT 1');

			while($row = $stmt->fetch()){
				$verinfo = array(
						"id" => $row["id"],
						"name" => $row["name"],
						);

				break;
			}
		}
		catch(PDOException $e){
			error_log($e->getMessage(),3,Server::ERROR_LOG);	
		}

		$dbh = null;
		if($save){
			$this->upgrade->set($verinfo);
		}else{
			return $verinfo;
		}
	}

	private function reloadDB1($save = false){
		$handle  = fopen(Server::LOCAL_TXT, "r");
		if(!$handle){
			return;
		}
		$data = array();
		while (!feof ($handle))
		{
			$buffer  = fgets($handle, 1024);
			$domain = trim($buffer);
			if(strlen($domain)>=5){
				array_push($data, $domain);
			}
		}
		fclose ($handle);
		if($save){
			$this->allowurl->set($data);
		}else{
			return $data;
		}
	}

	private function reloadDB2($save = false){
		$handle  = fopen(Server::CHECK_TXT, "r");
		if(!$handle){
			return;
		}
		$data = array();
		while (!feof ($handle))
		{
			$buffer  = fgets($handle, 1024);
			$info = explode("|",trim($buffer));
			if(count($info)==2){
				$domain = $info[0];
				$sortid = $info[1];
				if(strlen($domain)>=5 && is_numeric($sortid)){
					$data[$domain] = $sortid;
				}
			}
		}
		fclose ($handle);
		if($save){
			$this->checkurl->set($data);
		}else{
			return $data;
		}
	}

	public function reloadDB($serv, $interval)
	{
		switch($interval)
		{
			case Server::RELOAD_HOUR_INTERVAL:
				$param = array("job", "reload");
				$serv->task($param);
				break;
		}
	}

	public function onRequest (swoole_http_request $request,
			swoole_http_response $response)
	{
		$code = 200;
		$request_uri = $request->server["request_uri"];
		$request_method = $request->server["request_method"];
		$remote_addr = $request->server["remote_addr"]; 
		$getdata = $postdata = '{}';
		if(isset($request->get)){
			$getdata = json_encode($request->get);
		}
		if(isset($request->post)){
			$postdata = json_encode($request->post);
		}
		$this->slog("$remote_addr $request_method $request_uri $getdata $postdata");
		switch($request_uri){
			case '/url1':
				$id =isset($request->get["id"])?$request->get["id"]:null;
				if($id == null){
					$code = 400;
					$res = "400 bad request";
				}else{
					$data = &$this->upgrade->get();
					if($id == $data["id"]){
						$res = array("hasNewVersion"=>false);
					}else{
						$res = array("hasNewVersion"=>true,"versionInfo"=>$this->upgrade->get());
					}
				}
				$res = json_encode($res, JSON_UNESCAPED_SLASHES);
				break;
			case '/url2':
				$host = isset($request->post["host"])?$request->post["host"]:null;
				$referer = isset($request->post["referer"])?$request->post["referer"]:null;

				$v1 = 1;
				$v2 = 1;
				$data = &$this->allowurl->get();
				if($host){
					$info = explode(".", $host);
					if(count($info)>=2){
						$host = $info[count($info)-2].".".$info[count($info)-1];
					}

					if(in_array($host,$data)){
						$v1 = 0;
					}	
				}
				if($referer){
					$info = explode(".", $referer);
					if(count($info)>=2){
						$referer = $info[count($info)-2].".".$info[count($info)-1];
					}
					if(in_array($referer,$data)){
						$v2 = 0;
					}	
				}
				$res = "$v1|$v2";
				break;
			case '/url3':
				$host = isset($request->post["host"])?$request->post["host"]:null;
				$url = isset($request->post["url"])?$request->post["url"]:null;

				$data = &$this->checkurl->get();
				$v1 = 0;
				if($host){
					$info = explode(".", $host);
					if(count($info)>=2){
						$host = $info[count($info)-2].".".$info[count($info)-1];
					}
					if(array_key_exists($host,$data)){
						$v1 = $data[$host];
					}
				}

				$res = $v1;
				break;
			default:
				$code = 404;
				$res = "404 not found";

		}
		$response->status($code);
		$response->header("Server", "nginx");
		$response->header("Content-Type", "text/html");
		$response->end($res);
	}

	public function onTask ($serv, $task_id, $from_id, $data)
	{
		$this->slog("ReloadData Begin");
		$ret = array();
		$ret["upgrade"] = $this->reloadDBUpgrade();
		$ret["allowurl"] = $this->reloadDB1();
		$ret["checkurl"] = $this->reloadDB2();
		$this->slog("ReloadData Done");
		return $ret;
	}

	public function onFinish ($serv, $task_id, $data)
	{
		if(count($data["allowurl"])>0){
			$this->allowurl->set($data["allowurl"]);
		}else{
			error_log("load allowurl error",3,Server::ERROR_LOG);	
		}
		if(count($data["checkurl"])>0){
			$this->checkurl->set($data["checkurl"]);
		}else{
			error_log("load checkurl error",3,Server::ERROR_LOG);	
		}
		$this->upgrade->set($data["upgrade"]);
	}
}

$server = new Server ();
?>

猜你喜欢

转载自ciaos.iteye.com/blog/2246578