30no2's Blog.

swoole+thinkphp从零开始打造高性能直播赛事

字数统计: 5.5k阅读时长: 27 min
2019/11/20 Share

swoole+thinkphp从零开始打造高性能直播赛事

一、swoole简介

1、简介

  • PHP异步网络通信引擎
  • 最终编译为so文件作为PHP扩展

2、应用

  • C编写,消息队列,毫秒定时器,php的异步多线程服务器
  • 支持长连接
  • 移动api服务器、高性能服务器、等

3、目标

  • 学习swoole 实战 系统优化
  • 安装php7和swoole(源码安装)
  • swoole基础:
    • 网络通信引擎TCP UDP WEBSOCKET HTTP
  • swoole进阶
    • 异步mysql
    • 异步redis
    • 异步文件
    • 异步task任务
    • 毫秒定时器
    • 进程、携程、内存
    • 消息队列
  • 实战
    • 登录模块
    • 赛事直播模块
    • 聊天室模块
    • 系统监控
    • 系统调优

二、学习Swoole的准备工作

1、linux开发环境

2、php7 swoole2.1 redis

3、源码安装php7 源码安装swoole

4、如何学习swoole

  • 查看文档
  • 实现swoole特性的功能点
  • 多看看其他现有的swoole的经典代码

三、linux环境下源码安装php

1、官网下载 )php源码包

80-CDFA99-1616-44-FA-A534-302205-CDD71-F-20191121160742.jpg

2、上传到linux服务器

3、开始安装

  • 解压

    1
    tar -xjvf php-7.3.11.tar.bz2
  • configure

    • 安装一些扩展

      • gcc

        1
        yum install gcc
      • autoconf

        1
        yum install autoconf
      • libxml2-devel

        1
        yum install libxml2-devel
    • 安装

      1
      ./configure --prefix=/var/www/php
  • make

    1
    make
  • make install

    1
    make install
  • 测试

    1
    [root@localhost php]# ./bin/php -m

    到php的目录执行命令可以看到默认php安装的一些扩展

  • 配置系统环境变量

    1
    vi ~/.bash_profile
    1
    alias php=/var/www/php/bin/php
    1
    source ~/.bash_profile

    测试

    1
    php -v

4、安装完成后的一些坑

  • 在源码包里,把php.ini-development复制到php的编译目录下并且改名

    1
    2
    cp php.ini-development /var/www/php/etc
    mv php.ini-development php.ini
  • 如果修改php.ini后没有生效,

    1
    2
    [root@localhost etc]# php -i | grep php.ini
    Configuration File (php.ini) Path => /var/www/php/lib
  • 看出默认路径是在lib目录下面,则需要吧php.ini移动到lib目录下面

    1
    mv ./etc/php.ini ./lib/

四、swoole源码安装

1、官网下载源码

  • github下载zip或者git直接下载到soft目录

2、编译安装swoole

  • 准备 安装gcc库

    1
    yum install gcc-c++
  • swoole目录下生成configure–利用php工具phpize

    1
    /var/www/php/bin/phpize
  • 根据php配置文件编译安装

    1
    2
    3
    ./configure --with-php-config=/var/www/php/bin/php-config
    make
    make install
  • 在php相应目录生成swoole.so文件则编译安装成功

    CB49-B733-32-B6-4008-848-C-D82-E7-DA8-B81-C-20191122140455.jpg

3、php 支持swoole

  • 修改php.ini文件–添加如下代码

    1
    extension=swoole
  • 测试——看是否有swoole扩展

    1
    php -m
    • 去swoole安装目录执行——/opt/soft/swoole-src/examples/server

      1
      php echo.php
    • 新开窗口查看9501端口是否监听——如下则成功

      1
      netstat -anp | grep 9501

      CB49-B733-32-B6-4008-848-C-D82-E7-DA8-B81-C-20191122140455.jpg

  • 查看swoole版本

    1
    php --ri swoole

五、swoole服务器介绍–tcp服务

1、tcp服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
//创建Server对象,监听 127.0.0.1:9501端口
$serv = new Swoole\Server("127.0.0.1", 9501);
$serv->set([
'worker_num' => 4, //worker process num
'max_request' => 50,
]);
//监听连接进入事件
/*
* $fd: 客户端链接的唯一标识
* $reactor_id: 线程id
*/
$serv->on('Connect', function ($serv, $fd, $reactor_id) {
echo "Client: {$reactor_id}-{$fd}-Connect.\n";
});

//监听数据接收事件
$serv->on('Receive', function ($serv, $fd, $from_id, $data) {
$serv->send($fd, "Server: {$from_id}--{$fd}--{$data}".$data);
});

//监听连接关闭事件
$serv->on('Close', function ($serv, $fd) {
echo "Client: {$fd}Close.\n";
});

//启动服务器
$serv->start();

2、client php链接tcp服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
//链接swoole tcp 服务
$cilent = new swoole_client(SWOOLE_SOCK_TCP);
if(!$cilent->connect('127.0.0.1',9501)){
echo '链接失败';
exit;
};
//php 内置cli产量
fwrite(STDOUT,'请输入消息');
$msg = trim(fgets(STDIN));
//发送消息给tcp server
$cilent->send($msg);
//接受来自server的数据
$result = $cilent->recv();
echo $result;

9-CD66029-7549-4-FE2-8210-8-EBF42-CC3-D4-C-20191126103137.jpg

3、判断tcp有几个进程

1
ps aft | grep tcp.php

9-CD66029-7549-4-FE2-8210-8-EBF42-CC3-D4-C-20191126103137.jpg

六、swoole服务器–http

1、http服务

1
2
3
4
5
6
7
8
<?php
use Swoole\Http\Server;

$http = new Server("0.0.0.0", 8800);
$http->on('request', function ($request, $response) {
$response->end("<h1>Hello Swoole. #".rand(1000, 9999)"</h1>");
});
$http->start();

2、获取get参数

  • 关键代码
1
2
$array = $request->get;
$get = json_encode($request->get);
  • 示例
1
2
3
4
5
6
7
8
9
10
<?php
use Swoole\Http\Server;

$http = new Server("0.0.0.0", 8800);
$http->on('request', function ($request, $response) {
$array = $request->get;
$get = json_encode($request->get);
$response->end("<h1>Hello Swoole. #".rand(1000, 9999).$get."</h1>");
});
$http->start();

3、保存cookie

  • 关键代码
1
$response->cookie('wwq','scccc',time()+1800);
  • 实例
1
2
3
4
5
6
7
8
9
10
11
12
<?php
use Swoole\Http\Server;

$http = new Server("0.0.0.0", 8800);
$http->on('request', function ($request, $response) {
// print_r($request->get);
$array = $request->get;
$get = json_encode($request->get);
$response->cookie('wwq','scccc',time()+1800);
$response->end("<h1>Hello Swoole. #".rand(1000, 9999).$get."</h1>");
});
$http->start();

4、开启swoole静态资源访问

  • 关键代码
1
2
3
4
$http->set([
'enable_static_handler' => true,
'document_root' => '/var/www/my_swoole/data', // v4.4.0以下版本, 此处必须为绝对路径
]);
  • 实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
use Swoole\Http\Server;

$http = new Server("0.0.0.0", 8811);
$http->set([
'enable_static_handler' => true,
'document_root' => '/var/www/my_swoole/data', // v4.4.0以下版本, 此处必须为绝对路径
]);

$http->on('request', function ($request, $response) {
// print_r($request->get);
$array = $request->get;
$get = json_encode($request->get);
$response->cookie('wwq','scccc',time()+1800);
$response->end("<h1>Hello Swoole. #".rand(1000, 9999).$get."</h1>");
});
$http->start();

686021-DF-B5-FD-47-F6-8-F73-BD9-C3125-FD73-20191126143506.jpg

686021-DF-B5-FD-47-F6-8-F73-BD9-C3125-FD73-20191126143506.jpg

七、swoole服务–websocket

  • WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
  • 为什么需要websocket
    • 缺陷:http的通信只能由客户端发起
  • websocket特点
    • 建立在TCP协议之上
    • 性能开销小通信高效
    • 客户端可以与任意服务器通信
    • 协议标识符ws wss
    • 持久化网络通信协议

1、WebSocket服务

  • 服务端——ws_server.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
$server = new Swoole\WebSocket\Server("0.0.0.0", 8812);
$server->set([
'enable_static_handler' => true,
'document_root' => '/var/www/my_swoole/data', // v4.4.0以下版本, 此处必须为绝对路径
]);
//监听websocket链接打开事件
$server->on('open', 'onOpen');
function onOpen($server,$request){
print_r($request->fd);
}
//监听websocket消息事件
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$server->push($frame->fd, "wwq - push - success!");
});

$server->on('close', function ($ser, $fd) {
echo "client {$fd} closed\n";
});

$server->start();
  • 用户——ws_client.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>ws_client</title>
</head>
<body>
<h1>wwq ws server</h1>
<script>
var wsUrl = "ws://192.168.72.4:8812";
var webSocket = new WebSocket(wsUrl);
webSocket.onopen = new WebSocket(wsUrl);
//实例对象的onopen属性
webSocket.onopen = function (evt) {
webSocket.send('hello wwq');
console.log('content-swoole-success');
}
//实例化onmwssage
webSocket.onmessage = function (evt) {
console.log('ws-server-return-data:'+evt.data);
}
//onclose
webSocket.onclose = function (evt) {
console.log('close');
}
//onerror
webSocket.onerror = function (evt) {
console.log('error:'+evt.data);
}
</script>
</body>
</html>
  • 结果

9-CD66029-7549-4-FE2-8210-8-EBF42-CC3-D4-C-20191126103137.jpg

9-CD66029-7549-4-FE2-8210-8-EBF42-CC3-D4-C-20191126103137.jpg

2、服务优化

  • ws.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
/**
* ws优化
* User: 30no2
* Date: 2019/11/26
* Time: 16:56
*/
class Ws{
CONST HOST = "0.0.0.0";
CONST PORT = '8812';
public $ws = null;
public function __construct(){
$this->ws = new swoole_websocket_server("0.0.0.0",self::PORT);
$this->ws->on("open",[$this,'onOpen']);
$this->ws->on("message",[$this,'onMessage']);
$this->ws->on("close",[$this,'onClose']);
$this->ws->start();
}

/**
* 监听ws连接事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:01
*/
public function onOpen($ws,$request){
var_dump($request->fd);
}
/**
* 监听ws消息事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:01
*/
public function onMessage($ws,$frame){
echo "ser-push-message:{$frame->data}\n";
$ws->push($frame->fd,"server-push:".date('Y-m-d H:i:s'));
}

/**
* ws关闭事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:06
*/
public function onClose($ws,$fd){
echo "clientid:{$fd}\n";
}

}
$obj = new Ws();
  • 结果

9-CD66029-7549-4-FE2-8210-8-EBF42-CC3-D4-C-20191126103137.jpg

686021-DF-B5-FD-47-F6-8-F73-BD9-C3125-FD73-20191126143506.jpg

八、task任务

  • 使用场景——执行耗时的操作(发送邮件,广播等)

1、修改wx.php——增加task任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?php
/**
* ws优化
* User: 30no2
* Date: 2019/11/26
* Time: 16:56
*/
class Ws{
CONST HOST = "0.0.0.0";
CONST PORT = '8812';
public $ws = null;
public function __construct(){
$this->ws = new swoole_websocket_server("0.0.0.0",self::PORT);
//新增
$this->ws->set([
'worker_num'=>2,
'task_worker_num'=>2
]);
$this->ws->on("open",[$this,'onOpen']);
$this->ws->on("message",[$this,'onMessage']);
$this->ws->on("task",[$this,'onTask']);//新增
$this->ws->on("finish",[$this,'onFinish']);//新增
$this->ws->on("close",[$this,'onClose']);
$this->ws->start();
}

/**
* 监听ws连接事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:01
*/
public function onOpen($ws,$request){
var_dump($request->fd);
}
/**
* 监听ws消息事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:01
*/
public function onMessage($ws,$frame){
echo "ser-push-message:{$frame->data}\n";
//todo 10s//新增
$data = [
'task'=>1,
'fd'=>$frame->fd
];
$ws->task($data);
$ws->push($frame->fd,"server-push:".date('Y-m-d H:i:s'));
}

/**
* task任务//新增
* @param $serv
* @param $taskId
* @param $workerId
* @param $data
* @return string
*/
public function onTask($serv, $taskId, $workerId, $data){
print_r($data);
//耗时场景10秒
sleep(10);
return "on task finish";//告诉worker进程

}

/**
* finish任务//新增
* @param $serv
* @param $taskId
* @param $data: task进程return的内容
*/
public function onFinish($serv, $taskId, $data){
echo "taskId:{$taskId}\n";
echo "finish-data-sucess:{$data}\n";
}

/**
* ws关闭事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:06
*/
public function onClose($ws,$fd){
echo "clientid:{$fd}\n";
}

}
$obj = new Ws();

2、结果

9241-B305-966-D-4-E62-A43-E-C167-D108-D55-A-20191127113021.jpg

BDBDE549-BEB8-4-C95-9306-C112-C2-B0-A9-DF-20191127113203.jpg

九、swoole 定时器

  • swoole_timer_tick——每间隔一段时间执行某个函数等
  • swoole_timer_after——几秒/几分钟后执行某个函数等

1、增加定时功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<?php
/**
* ws优化
* User: 30no2
* Date: 2019/11/26
* Time: 16:56
*/
class Ws{
CONST HOST = "0.0.0.0";
CONST PORT = '8812';
public $ws = null;
public function __construct(){
$this->ws = new swoole_websocket_server("0.0.0.0",self::PORT);

$this->ws->set([
'worker_num'=>2,
'task_worker_num'=>2
]);
$this->ws->on("open",[$this,'onOpen']);
$this->ws->on("message",[$this,'onMessage']);
$this->ws->on("task",[$this,'onTask']);
$this->ws->on("finish",[$this,'onFinish']);
$this->ws->on("close",[$this,'onClose']);
$this->ws->start();
}

/**
* 监听ws连接事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:01
*/
public function onOpen($ws,$request){
var_dump($request->fd);
//每两秒执行//新增
if($request->fd == 1){
swoole_timer_tick(2000,function ($timer_id){
echo "2s:timerId:{$timer_id}\n";
});
}
}
/**
* 监听ws消息事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:01
*/
public function onMessage($ws,$frame){
echo "ser-push-message:{$frame->data}\n";
//todo 10s
$data = [
'task'=>1,
'fd'=>$frame->fd
];
// $ws->task($data);
//新增
swoole_timer_after(5000,function () use($ws,$frame){
echo "5s-after:\n";
$ws->push($frame->fd,"server-time-after");
});
$ws->push($frame->fd,"server-push:".date('Y-m-d H:i:s'));
}

/**
* task任务
* @param $serv
* @param $taskId
* @param $workerId
* @param $data
* @return string
*/
public function onTask($serv, $taskId, $workerId, $data){
print_r($data);
//耗时场景10秒
sleep(10);
return "on task finish";//告诉worker进程

}

/**
* finish任务
* @param $serv
* @param $taskId
* @param $data: task进程return的内容
*/
public function onFinish($serv, $taskId, $data){
echo "taskId:{$taskId}\n";
echo "finish-data-sucess:{$data}\n";
}

/**
* ws关闭事件
* User: 30no2
* Date: 2019/11/26
* Time: 17:06
*/
public function onClose($ws,$fd){
echo "clientid:{$fd}\n";
}

}
$obj = new Ws();

2、结果

9241-B305-966-D-4-E62-A43-E-C167-D108-D55-A-20191127113021.jpg

BDBDE549-BEB8-4-C95-9306-C112-C2-B0-A9-DF-20191127113203.jpg

十、linux 安装mysql

并且网络上的安装教程也非常多,但是对于新手来说,各种不同形式的安装教程,又给新手们带来了要选择哪种方式进行安装的难题,而且很多时候按照教程也没有能够安装成功,安装过程出现各种各样的错误。

下面记录了我在Linux环境下安装Mysql的完整过程,如有错误或遗漏,欢迎指正。

(一) 安装前准备

1、检查是否已经安装过mysql,执行命令

1
[root@localhost /]# rpm -qa | grep mysql

img

从执行结果,可以看出我们已经安装了mysql-libs-5.1.73-5.el6_6.x86_64,执行删除命令

1
[root@localhost /]# rpm -e --nodeps mysql-libs-5.1.73-5.el6_6.x86_64

再次执行查询命令,查看是否删除

1
[root@localhost /]# rpm -qa | grep mysql

img

2、查询所有Mysql对应的文件夹

1
2
3
4
5
[root@localhost /]# whereis mysql
mysql: /usr/bin/mysql /usr/include/mysql
[root@localhost lib]# find / -name mysql
/data/mysql
/data/mysql/mysql

删除相关目录或文件

1
[root@localhost /]#  rm -rf /usr/bin/mysql /usr/include/mysql /data/mysql /data/mysql/mysql

验证是否删除完毕

1
2
3
4
[root@localhost /]# whereis mysql
mysql:
[root@localhost /]# find / -name mysql
[root@localhost /]#

3、检查mysql用户组和用户是否存在,如果没有,则创建

1
2
3
4
5
[root@localhost /]# cat /etc/group | grep mysql
[root@localhost /]# cat /etc/passwd |grep mysql
[root@localhost /]# groupadd mysql
[root@localhost /]# useradd -r -g mysql mysql
[root@localhost /]#

4、从官网下载是用于Linux的Mysql安装包

下载命令:

1
[root@localhost /]#  wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz

也可以直接到mysql官网选择其他版本进行下载。

BDBDE549-BEB8-4-C95-9306-C112-C2-B0-A9-DF-20191127113203.jpg

(二)安装Mysql

1、在执行wget命令的目录下或你的上传目录下找到Mysql安装包:mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz

执行解压命令:

1
2
3
4
[root@localhost /]#  tar -xzvf mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz
[root@localhost /]# ls
mysql-5.7.28-linux-glibc2.12-x86_64
mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz

解压完成后,可以看到当前目录下多了一个解压文件,移动该文件到/usr/local/mysql
执行移动命令:

1
[root@localhost /]# mv mysql-5.7.28-linux-glibc2.12-x86_64 /usr/local/mysql

2、在/usr/local/mysql目录下创建data目录

1
[root@localhost /]# mkdir /usr/local/mysql/data

3、更改mysql目录下所有的目录及文件夹所属的用户组和用户,以及权限

1
2
[root@localhost /]# chown -R mysql:mysql /usr/local/mysql
[root@localhost /]# chmod -R 755 /usr/local/mysql

4、编译安装并初始化mysql,务必记住初始化输出日志末尾的密码(数据库管理员临时密码)

1
2
[root@localhost /]# cd /usr/local/mysql/bin
[root@localhost bin]# ./mysqld --initialize --user=mysql --datadir=/usr/local/mysql/data --basedir=/usr/local/mysql

补充说明:\

此时可能会出现错误:

img

出现该问题首先检查该链接库文件有没有安装使用 命令进行核查

1
2
[root@localhost bin]# rpm -qa|grep libaio   
[root@localhost bin]#

运行命令后发现系统中无该链接库文件

1
[root@localhost bin]#  yum install  libaio-devel.x86_64

安装成功后,继续运行数据库的初始化命令,此时可能会出现如下错误:

img

执行如下命令后,再次运行数据库的初始化命令:

1
[root@localhost bin]#  yum -y install numactl

5、运行初始化命令成功后,输出日志如下:

img

记录日志最末尾位置root@localhost:后的字符串,此字符串为mysql管理员临时登录密码。

6、编辑配置文件my.cnf,添加配置如下

1
2
3
4
5
6
7
8
9
10
11
[root@localhost bin]#  vi /etc/my.cnf

[mysqld]
datadir=/usr/local/mysql/data
port = 3306
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
symbolic-links=0
max_connections=400
innodb_file_per_table=1
#表名大小写不明感,敏感为
lower_case_table_names=1

7、启动mysql服务器

1
[root@localhost /]# /usr/local/mysql/support-files/mysql.server start

显示如下结果,说明数据库安装成功

img

如果出现如下提示信息

1
Starting MySQL... ERROR! The server quit without updating PID file

查看是否存在mysql和mysqld的服务,如果存在,则结束进程,再重新执行启动命令

1
2
3
4
5
6
7
8
9
#查询服务
ps -ef|grep mysql
ps -ef|grep mysqld

#结束进程
kill -9 PID

#启动服务
/usr/local/mysql/support-files/mysql.server start

img

8、添加软连接,并重启mysql服务

1
2
3
[root@localhost /]#  ln -s /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql 
[root@localhost /]# ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql
[root@localhost /]# service mysql restart

9、登录mysql,修改密码(密码为步骤5生成的临时密码)

1
2
3
[root@localhost /]#  mysql -u root -p
Enter password:
mysql>set password for root@localhost = password('yourpass');

img

10、开放远程连接

1
2
3
mysql>use mysql;
msyql>update user set user.Host='%' where user.User='root';
mysql>flush privileges;

img

11、设置开机自动启动

1
2
3
4
5
6
7
8
1、将服务文件拷贝到init.d下,并重命名为mysql
[root@localhost /]# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
2、赋予可执行权限
[root@localhost /]# chmod +x /etc/init.d/mysqld
3、添加服务
[root@localhost /]# chkconfig --add mysqld
4、显示服务列表
[root@localhost /]# chkconfig --list

十一、异步redis——服务安装

  • redis 服务
  • hiredis库
  • 编译swoole 需要加入——enable-async-redis

1、编译安装redis

  • 官网下载源码包

    83-BD86-CA-951-A-4600-9-BE3-83-B7858-C8-DD2-20191202104434.jpg

  • 解压缩

    ​ tar -zxvf redis-5.0.7.tar.gz

  • 进入redis目录

1
2
make
make install
  • 测试——表示成功
1
redis-server

83-BD86-CA-951-A-4600-9-BE3-83-B7858-C8-DD2-20191202104434.jpg

2、新版本的redis不再支持异步redis——推荐使用携程

  • 4.2.6版本及以后不再需要手动安装和启用async-redis, 而是swoole自带

    • 需要安装一个第三方的异步Redis库hiredis
    1
    2
    3
    sudo make
    sudo make install
    sudo ldconfig
  • v4.3.0以后不再需要添加编译参数, 内置了此依赖

  • 需要在编译时增加--enable-async-redis来开启此功能
  • 请勿同时使用异步回调和协程Redis

1) 代码示例

1
2
3
$redis = new Swoole\Coroutine\Redis();
$redis->connect('127.0.0.1', 6379);
$val = $redis->get('key');

2)defer特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const REDIS_SERVER_HOST = '127.0.0.1';
const REDIS_SERVER_PORT = 6379;


go(function () {
$redis = new Swoole\Coroutine\Redis();
$redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
$redis->setDefer();
$redis->set('key1', 'value');

$redis2 = new Swoole\Coroutine\Redis();
$redis2->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
$redis2->setDefer();
$redis2->get('key1');

$result1 = $redis->recv();
$result2 = $redis2->recv();

var_dump($result1, $result2);
});

3、设定开机启动

1)创建存储redis文件目录

1
mkdir -p /usr/local/redis

2)进入src目录,复制redis-server redis-cli到新建立的文件夹

1
2
cp ./redis-server /usr/local/redis/
cp ./redis-cli /usr/local/redis/

3)复制redis的配置文件

1
2
cd ..
cp redis.conf /usr/local/redis/

4)编辑配置文件

1
2
cd /usr/local/redis/
vim redis.conf

46-F67339-EDD9-46-CE-AD16-F9-DA7-B1457-F9-20191217111414.jpg

    改为yes 后台运行

5)添加开机启动服务

1
vim /etc/systemd/system/redis-server.service
1
2
3
4
5
6
7
8
9
10
11
12
13
 1 [Unit]
2 Description=The redis-server Process Manager
3 After=syslog.target network.target
4
5 [Service]
6 Type=simple
7 PIDFile=/var/run/redis_6379.pid
8 ExecStart=/usr/local/redis/redis-server /usr/local/redis/redis.conf
9 ExecReload=/bin/kill -USR2 $MAINPID
10 ExecStop=/bin/kill -SIGINT $MAINPID
11
12 [Install]
13 WantedBy=multi-user.target

6)设置开机启动

1
2
3
1 systemctl daemon-reload
2 systemctl start redis-server.service
3 systemctl enable redis-server.service

7)检查是否安装成功

46-F67339-EDD9-46-CE-AD16-F9-DA7-B1457-F9-20191217111414.jpg

8)创建redis命令软连接

1
ln -s /usr/local/redis/redis-cli /usr/bin/redis

9)测试redis

46-F67339-EDD9-46-CE-AD16-F9-DA7-B1457-F9-20191217111414.jpg

完成安装!

10)如果不成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
1.编写配置脚本 [** vim /etc/init.d/redis** ]
#!/bin/sh
# chkconfig: 2345 10 90
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.

REDISPORT=6379
EXEC=/usr/local/redis/redis-server #redis-server路径
CLIEXEC=/usr/local/redis/redis-cli #redis-cli路径

PIDFILE=/var/run/redis_${REDISPORT}.pid #redis_${REDISPORT}.pid路径
CONF="/usr/local/redis/redis.conf" #redis.conf路径
AUTH="School1502" #redis 密码

case "$1" in
start)
if [ -f $PIDFILE ]
then
echo "$PIDFILE exists, process is already running or crashed"
else
echo "Starting Redis server..."
$EXEC $CONF
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo "$PIDFILE does not exist, process is not running"
else
PID=$(cat $PIDFILE)
echo "Stopping ..."
$CLIEXEC -p $REDISPORT shutdown
while [ -x /proc/${PID} ]
do
echo "Waiting for Redis to shutdown ..."
sleep 1
done
echo "Redis stopped"
fi
;;
*)
echo "Please use start or stop as first argument"
;;
esac

2.修改redis.conf,打开后台运行选项
daemonize yes
3.修改文件执行权限
chmod +x /etc/init.d/redis
4.设置开机启动
# 尝试启动或停止 redis
service redis start
service redis stop
# 开启服务自启动
chkconfig redis on
5.reboot

11)如果还是不行的话

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1. 解压缩
tar -zxf redis-5.0.7.tar.gz
2.移动到/usr/local/ (个人爱好)
mv redis-5.0.7 /usr/local
cd /usr/local
mv redis-5.0.7/ redis
cd redis/src
make
make install
3.到usr/local/redis目录下
mkdir etc
mkdir bin
4.进入src目录
mv mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-server /usr/local/redis/bin/
5.启动redis
cd /usr/local/redis/bin/redis-server
6.修改redis.conf
cd etc/
vim redis.conf
daemonize no 改成daemonize yes
7.再次启动redis并且指定服务配置文件
redis-server /usr/local/redis/etc/redis.conf

————————————————————上面的事情做完后

#新建目录
mkdir /etc/redis

#移动配置文件并重命名 名字必须是 6379 和配置文件里一致(下面的配置文件不改,所以这里就必须写成6379)
mv redis.conf /etc/redis/6379.conf
find / -name redis_init_script
#复制、移动文件并重命名
cp redis_init_script /etc/init.d/redis



#修改脚本
vim /etc/init.d/redis

在首行注释!bin/sh下面添加如下两行注释:
# chkconfig: 2345 10 90
# description: Start and Stop redis

#修改redis服务路径,改成你自己的路径(上面说的把四个文件复制到一个目录里的那个路径)
EXEC=/usr/local/redis/redis-server
CLIEXEC=/usr/local/redis/redis-cli

A249-CA06-DF3-F-4-B8-B-99-B9-99-EAA6-A24-A67-20191209143520.jpg

1
2
3
4
5
6
7
#设置开机启动
chkconfig redis on
#然后可以使用命令 来开启或者关闭redis了
service redis start/stop
ps -ef | grep redis
/usr/local/redis/redis-cli//
vi ~/.bash_profile

A249-CA06-DF3-F-4-B8-B-99-B9-99-EAA6-A24-A67-20191209143520.jpg

1
source ~/.bash_profile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 将 Redis 注册成为服务
[root@localhost init.d]# chkconfig --add redis
注意: 如果报 reids不支持chkconfig 错误
解决方案: vim /ect/init.d/redis
按i,进入编辑模式
在文档头部添加#chkconfig:2345 80 90

如:
# chkconfig: 2345 90 10

# description: Redis is a persistent key-value database
保存后: 输入 [root@localhost init.d]# chkconfig --add redis

kill redis || kill -9 0000 //停止redis

//重启
ps -ef | grep redis

12)关键

由于我之前安装过redis配置了开机启动。后来就一直不成功

1
2
3
find / -name redis-server
rm -rf /etc/systemd/system/multi-user.target.wants/redis.service
rm -rf /usr/lib/systemd/system/redis.service

终于成功了!

redis.jpg

十二、进程

  • 进程就是正在运行的程序的一个实例

1、process.php

1
2
3
4
5
6
7
8
9
<?php
$process = new swoole_process(function (swoole_process $pro){
//todo
$pro->exec('/var/php/bin/php',[__DIR__.'/../server/http_server.php']);
},true);
$pid = $process->start();
echo $pid.PHP_EOL;

swoole_process::wait();

2、查看进程数

1
yum install psmisc
1
php process.php

B42-DF5-A4-E3-BD-4-B5-C-83-CF-2-D820396-E00-C-20191203170634.jpg

1
pstree -p 1753

B42-DF5-A4-E3-BD-4-B5-C-83-CF-2-D820396-E00-C-20191203170634.jpg

1
ps aft | grep http_server

B42-DF5-A4-E3-BD-4-B5-C-83-CF-2-D820396-E00-C-20191203170634.jpg

3、使用场景

  • curl.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
echo "process_start_time".date('Ymd H:i:s').PHP_EOL;
$workers = [];
$urls = [
'http://www.baidu.com',
'http://www.qq.com',
'https://www.baidu.com/s?wd=11',
'https://www.baidu.com/s?wd=22',
'https://www.baidu.com/s?wd=33',
'https://www.baidu.com/s?wd=44',
'https://www.baidu.com/s?wd=55',
];
//foreach ($urls as $url){
// $content[] = file_put_contents($url);
//}
for ($i=0;$i<6;$i++){
//子进程
$process = new swoole_process(function (swoole_process $worker) use($i,$urls){
//curl
$connect = curlData($urls[$i]);
echo $connect.PHP_EOL;


},true);
$pid = $process->start();
$workers[$pid] = $process;
}

foreach ($workers as $process){
echo $process->read();
}
/**
* 模拟请求url内容
* User: 30no2
* Date: 2019/12/3
* Time: 17:22
*/
function curlData($url){
sleep(1);
return $url.'success'.PHP_EOL.'<br/>';
}

echo "process_end_time".date('Ymd H:i:s').PHP_EOL;
  • 结果

191-DC93-E-5-ED1-42-B8-8974-93501-E0-C7454-20191204093250.jpg

十三、swoole内存

  • lock
  • buffer
  • table
  • atomic
  • mmap
  • channel
  • serialize

1、swoole table

  • swoole_table是一个基于共享内存和锁实现的超高性能,并发数据结构

1)table.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
//创建内存表
$table = new swoole_table(1024);
//内存表增加一列
$table->column('id',$table::TYPE_INT,8);
$table->column('name',$table::TYPE_STRING,255);
$table->column('age',$table::TYPE_INT,6);
$table->create();

$table->set('wwq_test',[
'id'=>1,
'name'=>'wwq',
'age'=>35,
]);

print_r($table->get('wwq_test'));

2)结果

191-DC93-E-5-ED1-42-B8-8974-93501-E0-C7454-20191204093250.jpg

3)一些基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
//创建内存表
$table = new swoole_table(1024);
//内存表增加一列
$table->column('id',$table::TYPE_INT,8);
$table->column('name',$table::TYPE_STRING,255);
$table->column('age',$table::TYPE_INT,6);
$table->create();

$table->set('wwq_test',[
'id'=>1,
'name'=>'wwq',
'age'=>35,
]);
$table['wwq_test2'] = [
'id'=>2,
'name'=>'wwq2',
'age'=>36,
];
//$table->incr('wwq_test2','age',3);//加操作
$table->decr('wwq_test2','age',3);//减操作
print_r($table['wwq_test2']);
print_r('del starting....');
$table->del('wwq_test2');//删除操作
print_r($table['wwq_test2']);

十四、swoole 携程

  • swoole 携程只能在回调函数中使用。

1、coroutine redis.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$http = new swoole_http_server('0.0.0.0',8001);
$http->on('request',function ($request,$response){
//redis
$redis = new Swoole\Coroutine\Redis();
$redis->connect('127.0.0.1',6379);
$value = $redis->get($request->get['a']);
//mysql....等等


//总用时为以上逻辑用时的最大值
$response->header("Content-Type","text/plain");
$response->end($value);
});
$http->start();

2、结果

A482-BD4-B-71-DC-4-E3-A-87-E6-E1-CC766-CCB92-20191205130610.jpg

十五、swoole 实战

1、知识点

  • 框架——thinkphp5.1
  • swoole特性使用
  • 赛事直播平台
  • nginx负载均衡
  • redis
  • 系统监控+性能优化
CATALOG
  1. 1. swoole+thinkphp从零开始打造高性能直播赛事
    1. 1.1. 一、swoole简介
      1. 1.1.1. 1、简介
      2. 1.1.2. 2、应用
    2. 1.2. 3、目标
    3. 1.3. 二、学习Swoole的准备工作
      1. 1.3.1. 1、linux开发环境
      2. 1.3.2. 2、php7 swoole2.1 redis
      3. 1.3.3. 3、源码安装php7 源码安装swoole
      4. 1.3.4. 4、如何学习swoole
    4. 1.4. 三、linux环境下源码安装php
      1. 1.4.1. 1、官网下载 )php源码包
      2. 1.4.2. 2、上传到linux服务器
      3. 1.4.3. 3、开始安装
      4. 1.4.4. 4、安装完成后的一些坑
    5. 1.5. 四、swoole源码安装
      1. 1.5.1. 1、官网下载源码
      2. 1.5.2. 2、编译安装swoole
      3. 1.5.3. 3、php 支持swoole
    6. 1.6. 五、swoole服务器介绍–tcp服务
      1. 1.6.1. 1、tcp服务
      2. 1.6.2. 2、client php链接tcp服务
      3. 1.6.3. 3、判断tcp有几个进程
    7. 1.7. 六、swoole服务器–http
      1. 1.7.1. 1、http服务
      2. 1.7.2. 2、获取get参数
      3. 1.7.3. 3、保存cookie
      4. 1.7.4. 4、开启swoole静态资源访问
    8. 1.8. 七、swoole服务–websocket
      1. 1.8.1. 1、WebSocket服务
      2. 1.8.2. 2、服务优化
    9. 1.9. 八、task任务
      1. 1.9.1. 1、修改wx.php——增加task任务
      2. 1.9.2. 2、结果
    10. 1.10. 九、swoole 定时器
      1. 1.10.1. 1、增加定时功能
      2. 1.10.2. 2、结果
    11. 1.11. 十、linux 安装mysql
      1. 1.11.1. (一) 安装前准备
        1. 1.11.1.1. 1、检查是否已经安装过mysql,执行命令
        2. 1.11.1.2. 2、查询所有Mysql对应的文件夹
        3. 1.11.1.3. 3、检查mysql用户组和用户是否存在,如果没有,则创建
        4. 1.11.1.4. 4、从官网下载是用于Linux的Mysql安装包
      2. 1.11.2. (二)安装Mysql
        1. 1.11.2.1. 1、在执行wget命令的目录下或你的上传目录下找到Mysql安装包:mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz
        2. 1.11.2.2. 2、在/usr/local/mysql目录下创建data目录
        3. 1.11.2.3. 3、更改mysql目录下所有的目录及文件夹所属的用户组和用户,以及权限
        4. 1.11.2.4. 4、编译安装并初始化mysql,务必记住初始化输出日志末尾的密码(数据库管理员临时密码)
        5. 1.11.2.5. 5、运行初始化命令成功后,输出日志如下:
        6. 1.11.2.6. 6、编辑配置文件my.cnf,添加配置如下
        7. 1.11.2.7. 7、启动mysql服务器
        8. 1.11.2.8. 8、添加软连接,并重启mysql服务
        9. 1.11.2.9. 9、登录mysql,修改密码(密码为步骤5生成的临时密码)
        10. 1.11.2.10. 10、开放远程连接
        11. 1.11.2.11. 11、设置开机自动启动
    12. 1.12. 十一、异步redis——服务安装
      1. 1.12.1. 1、编译安装redis
      2. 1.12.2. 2、新版本的redis不再支持异步redis——推荐使用携程
        1. 1.12.2.1. 1) 代码示例
        2. 1.12.2.2. 2)defer特性
      3. 1.12.3. 3、设定开机启动
        1. 1.12.3.1. 1)创建存储redis文件目录
        2. 1.12.3.2. 2)进入src目录,复制redis-server redis-cli到新建立的文件夹
        3. 1.12.3.3. 3)复制redis的配置文件
        4. 1.12.3.4. 4)编辑配置文件
        5. 1.12.3.5. 5)添加开机启动服务
        6. 1.12.3.6. 6)设置开机启动
        7. 1.12.3.7. 7)检查是否安装成功
        8. 1.12.3.8. 8)创建redis命令软连接
        9. 1.12.3.9. 9)测试redis
        10. 1.12.3.10. 10)如果不成功
        11. 1.12.3.11. 11)如果还是不行的话
        12. 1.12.3.12. 12)关键
    13. 1.13. 十二、进程
      1. 1.13.1. 1、process.php
      2. 1.13.2. 2、查看进程数
      3. 1.13.3. 3、使用场景
    14. 1.14. 十三、swoole内存
      1. 1.14.1. 1、swoole table
        1. 1.14.1.1. 1)table.php
        2. 1.14.1.2. 2)结果
        3. 1.14.1.3. 3)一些基本操作
    15. 1.15. 十四、swoole 携程
      1. 1.15.1. 1、coroutine redis.php
      2. 1.15.2. 2、结果
    16. 1.16. 十五、swoole 实战
      1. 1.16.1. 1、知识点