我的伪代码,使用是 thinkphp5.0
public function __construct()
{
$this->redis = new redis();
}
public function fire(Job $job, $data)
{
if ($job->attempts() > 2) {
$this->redis->setHear($data);
$job->delete();
} else {
$this->send($data);
$job->delete();
}
}
/**
* 根据消息中的数据进行实际的业务处理
* @param array|mixed $data 发布任务时自定义的数据
* @return boolean 任务执行的结果
*/
private function send($data)
{
try {
$result = CURLRequest($data['weburl'], $data, 'POST', $this->header);
} catch (\Exception $e) {
echo $e->getMessage();
return false;
}
if (empty($result)) {
echo json_encode(['errcode' => 1, 'msg' => '服务器异常:' . $data['SN'], 'data' => $result, 'url' => $data['weburl']], JSON_UNESCAPED_SLASHES);
return false; //请求异常尝试重试
} else {
echo json_encode(['errcode' => 1, 'msg' => $data['SN'] . ' ' . date("Y-m-d H:i:s") . '' . "心跳 ok", 'data' => $result, 'url' => $weburl], JSON_UNESCAPED_SLASHES);
return true; //请求成功退出
}
}
function CURLRequest($url, $params = [], $http_method = 'GET', $Header = [])
{
$SSL = substr($url, 0, 8) == "https://" ? true : false; //判断是否 https 连接
$httpInfo = array();
$ch = curl_init(); //初始化 CURL 会话
//设置 CURL 传输选项
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
//设置响应头头文件的信息作为数据流输出
curl_setopt($ch, CURLOPT_HEADER, 1); //返回 response 头部信息
curl_setopt($ch, CURLINFO_HEADER_OUT, true); //TRUE 时追踪句柄的请求字符串,从 PHP 5.1.3 开始可用。这个很关键,就是允许你查看请求 header
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 返回 response_header, 该选项非常重要,如果不为 true, 只会获得响应的正文
curl_setopt($ch, CURLOPT_HEADER, true);
if ($http_method == 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
} else {
if (count($params) >= 1) {
$pstr = '?';
foreach ($params as $pkey=>$pv) {
$pstr .= $pstr == '?' ? $pkey.'='.$pv : '&'.$pkey.'='.$pv;
}
$url .= $pstr;
}
}
curl_setopt($ch, CURLOPT_URL, $url);
if (!empty($Header)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $Header);//设置请求头信息
}
if ($SSL) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
}
$response = curl_exec($ch); //执行 CURL 会话
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') {
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);
}
curl_close($ch); //关闭会话
list($header, $body) = explode("\r\n\r\n", $response, 2);
$headers = explode("\r\n", $header);
$headList = array();
foreach ($headers as $head) {
$value = explode(':', $head);
if(isset($value[1])) $headList[$value[0]] = $value[1];
}
$result = json_decode($body, true);//返回解析后的数据
if ($response === FALSE OR empty($response)) { //错误返回 false
$result = false;
}
return ['header' => $headList, 'result' => $result, 'raw_result' => $body];//header 响应头数据,格式化数组,原始数据
}
服务器配置
4G 8 核 5M
使用场景
物联网设备会通过 Http 方式回调心跳 30 秒一次,我搭建了中转服务器承担转发心跳,那么每次中转服务器同时间收到的请求可能是 1000 次,或者 500 次不等,这时又同时需要转发 1000 次或者 500 次不等
我的疑问
1.为何服务器重启后,CPU 会长时间占用率 100%,而且有队列不停的死循环,几百万次,我删除队列后,它依然不停增长到百万次,是不是队列中有异常,我没有捕获到
2.如果我分批转发心跳,它服务器能正常运行,比如 A B C D E F G 客户物联设备都关机,然后让客户再依次按顺序开机,中转服务器能正常运行
3.php 如何应对这种瞬间请求多的方式
你需要一个 worker 在背后干这种事,不要在页面里面转发,而是用 worker 去转发。
你页面接收消息后塞入队列,用 worker 去队列读消息,然后完成转发。因为 work 可以用多线程或者携程去处理并发转发,而不是多进程。
2 ,curl 要并发请求,需要用到 curl_multi_init 。