EasySwoole消息推送9 - 部署压测

概述
在所有的开发准备就绪的时候,开始准备和上线有关的事情:测试和服务部署,测试要注意代码的逻辑严
谨、代码运行的正确,服务稳定,所有的一切都需要用数据做指标,所有的计算机编程归根结底都是数学。
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']]);
                }
            }
        }
    }
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 点我我会动 设计师:白松林 返回首页