概述
在所有的开发准备就绪的时候,开始准备和上线有关的事情:测试和服务部署,测试要注意代码的逻辑严
谨、代码运行的正确,服务稳定,所有的一切都需要用数据做指标,所有的计算机编程归根结底都是数学。
0.系统初始化
0.1 Mysql 数据表初始化
需要如果在自定义进程或者自定义命令中需要使用到连接池,否则会报错:Fatal error: Uncaught Swoole\Error: API must be called in the coroutine
//创建一个协程调度器
$scheduler = new \Swoole\Coroutine\Scheduler();
$scheduler->add(function () {
$builder = new \EasySwoole\Mysqli\QueryBuilder();
$builder->raw('select version()');
\EasySwoole\ORM\DbManager::getInstance()->query($builder, true);
//这边重置ORM连接池的pool,避免链接被克隆到子进程,造成链接跨进程公用。
//DbManager如果有注册多库链接,请记得一并getConnection($name)获取全部的pool去执行reset
//其他的连接池请获取到对应的pool,然后执行reset()方法
\EasySwoole\ORM\DbManager::getInstance()->getConnection()->getClientPool()->reset();
});
//执行调度器内注册的全部回调
$scheduler->start();
//清理调度器内可能注册的定时器,不要影响到swoole server 的event loop
\Swoole\Timer::clearAll();
0.2 分离配置文件
bootstrap.php
中定义开发环境定义开关,分离加载文件,在加载时使用。
//环境变量开关 0本地,1测试 2线上
define('PUSHENV', 0);
PUSHENV
使用
/**
* 加载自定义配置文件
*/
public static function loadConf()
{
if(0 == PUSHENV){
$ConfPath = EASYSWOOLE_ROOT . '/App/Conf/Dev';
}else if(1 == PUSHENV){
$ConfPath = EASYSWOOLE_ROOT . '/App/Conf/Test';
}else if(2 == PUSHENV){
$ConfPath = EASYSWOOLE_ROOT . '/App/Conf/Online';
}
$Conf = Config::getInstance();
$files = File::scanDirectory($ConfPath);
if (!is_array($files['files'])) {
return;
}
foreach ($files['files'] as $file) {
$data = require_once $file;
$Conf->setConf(strtolower(basename($file, '.php')), (array)$data);
}
}
1.Nginx 部署服务
和部署普通的服务一样,监听9501端口,用IP哈希的算法去代理服务。
# 配置EasySwoole节点 至少需要一个
upstream stark {
# 将负载均衡模式设置为IP hash,作用:不同的客户端每次请求都会与同一节点进行交互。
ip_hash;
server 127.0.0.1:9501;
}
server {
listen 80;
server_name websocket.stark.com;
location / {
# websocket的header
proxy_http_version 1.1;
# 升级http1.1到websocket协议
proxy_set_header Upgrade websocket;
proxy_set_header Connection "Upgrade";
# 将客户端host及ip信息转发到对应节点
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
# 客户端与服务端60s之内无交互,将自动断开连接。
proxy_read_timeout 60s ;
# 代理访问真实服务器
proxy_pass http://stark;
}
}
2.基于Jmeter的WebSocket压力测试
下载Jmeter需要的WebSocket组件,进行压测,根据下面的步骤,在这里我就不做赘述了。
操作的时候有点心急,还是犯了一点点小错误,遇到问题首先做到的是要冷静,然后想方法,不能烦躁和蛮干,切记!
参考Url:
https://help.aliyun.com/document_detail/93627.html#title-kz3-0y7-7lr
https://help.aliyun.com/document_detail/91788.html?spm=a2c4g.11186623.2.30.681e1058OW8OxH
模块化使用、隔离和解耦
微服务之前被好多人提及,但是仔细想想它又是为了解决一个什么问题而出现的呢?
在处理中我们使用了如下几个步骤:
1.当有新增消息时,远程请求Api服务接口,接收数据写入缓存,异步写入数据库
2.在Crontab中推送消息,当推送成功后将消息移除队列
下面话不多说,看代码:
public function message(){
$method = $this->request()->getMethod();
if( 'post' !== strtolower($method) ){
return $this->writeJson(Status::CODE_METHOD_NOT_ALLOWED,[],Status::getReasonPhrase(Status::CODE_METHOD_NOT_ALLOWED));
}
if( isset($this->params['uid']) && !empty($this->params['uid']) &&
isset($this->params['msg']) && !empty($this->params['msg'])
){
$noce_ack = $this->getNoceAck();
$pushMsg = [
'noce_ack' => $noce_ack,
'to_uid' => $this->params['uid'],
'is_sent' => 1,
'is_read' => 0, #消息未读
'msg_type' => 4,
'client_type' => 0,
'msg_extend' => $this->params['msg'],
'create_time' => time(),
'update_time' => 0
];
$redis = $this->getRedisObject();
$redis->lPush(self::PUSH_MSG_COMMENT_LISTS, json_encode($pushMsg));
$this->addAsyncMysql($pushMsg,$this->params['uid']);
return $this->writeJson(Status::CODE_OK,[],Status::getReasonPhrase(Status::CODE_OK));
}else{
return $this->writeJson(Status::CODE_REQUESTED_RANGE_NOT_SATISFIABLE,[],Status::getReasonPhrase(Status::CODE_REQUESTED_RANGE_NOT_SATISFIABLE));
}
}
2.Crontab 消费代码
$number = 300;
$data = $redis->lRange(self::PUSH_MSG_COMMENT_LISTS, 0, $number );
if (!empty($data) && is_array($data)){
$pushLists = [];
$lRemList = [];
foreach ($data as $value){
$msgPushInfo = json_decode($value,true);
var_dump('msgPushInfo:'.$msgPushInfo);
if(isset($msgPushInfo['to_uid']) && !empty($msgPushInfo['to_uid'])){
$lRemList[$msgPushInfo['to_uid']] = $value;
$pushLists[$msgPushInfo['to_uid']]['uid'] = $msgPushInfo['to_uid'];
$pushLists[$msgPushInfo['to_uid']]['noce_ack'] = $msgPushInfo['noce_ack'];
$pushLists[$msgPushInfo['to_uid']]['msg_extend'] = json_decode($msgPushInfo['msg_extend'],true);
}
}
if(isset($pushLists) && !empty($pushLists)){
foreach ($pushLists as $value){
$comment_msg = [
'msg_type' => 4,
'code' => 200,
'body' => json_encode($value['msg_extend']),
'msg' => 'SUCCESS',
'noce_ack' => $value['noce_ack']
];
$fd = $redis->hGet(self::PUSH_MSG_USER_LOGIN,$value['uid']);
if(isset($fd) && !empty($fd)){
$ret = $server->push($fd,json_encode($comment_msg));
//推送成功后,移除元素
if($ret){
$redis->lRem(self::PUSH_MSG_COMMENT_LISTS,1,$lRemList[$value['uid']]);
}
}
}
}
}