Swoole 是一个使用 C++ 语言编写的基于异步事件驱动和协程的并行网络通信引擎,为 PHP 提供协程、高性能网络编程支持。提供了多种通信协议的网络服务器和客户端模块,可以方便快速的实现 TCP/UDP服务、高性能Web、WebSocket服务、物联网、实时通讯、游戏、微服务等,使 PHP 不再局限于传统的 Web 领域。
swoole的优势
常驻内存,避免重复加载带来的性能损耗,提升海量性能
协程异步,提高对 I/O 密集型场景并发处理能力(如:微信开发、支付、登录等)
方便地开发 Http、WebSocket、TCP、UDP 等应用,可以与硬件通信
swoole的安装
1.获取swoole安装包,地址:https://pecl.php.net/package/swoole
2.解压swoole安装包
下载至home目录
cd home
tar –zxvf swoole-4.6.6.tar
3.将解压出来的安装包copy到php容器
#先进容器创建目录
docker exec -it php bash
#没有文件夹的创建文件夹/usr/src/php/ext
mkdir php
#然后退出来 执行
docker cp /home/swoole-4.6.6 php:/usr/src/php/ext/swoole
4.安装swoole
#进php容器后在执行安装
docker-php-ext-install swoole
5.完成安装后,查看swoole信息
php --ri swoole
swoole初步体验
安装好swoole之后,我们可以简单来进行一次体验,也是验证我们是否安装完好swoole以及swoole的扩展。代码如下:
新建一个swoole.php 文件
$http = new swoole\Http\Server('0.0.0.0', 9501);
$http->on('Request', function ($request, $response) {
$response->header('Content-Type', 'text/html; charset=utf-8');
$response->end('Hello Swoole. #'
. rand(1000, 9999) . '');
});
$http->start();
?>
代码解释:
实例化一个swoole的http服务类,并传递监听的端口以及host,HTTP 服务器只需要关注请求响应即可,所以只需要监听一个 onRequest 事件。当有新的 HTTP 请求进入就会触发此事件。事件回调函数有 2 个参数,一个是 $request 对象,包含了请求的相关信息,如 GET/POST 请求的数据。
另外一个是 response 对象,对 request 的响应可以通过操作 response 对象来完成。$response->end() 方法表示输出一段 HTML 内容,并结束此请求
0.0.0.0 表示监听所有 IP 地址,一台服务器可能同时有多个 IP,如 127.0.0.1 本地回环 IP、192.168.1.100 局域网 IP、210.127.20.2 外网 IP,这里也可以单独指定监听一个 IP9501 监听的端口,如果被占用程序会抛出致命错误,中断执行。
测试如下:
先进入docker php里执行swoole.php
再开个窗口
进入php容器内(上面有)
PHP中安装扩展有几个特殊的命令
docker-php-source
docker-php-ext-install
docker-php-ext-enable
docker-php-ext-configure
docker-php-source
此命令,实际上就是在PHP容器中创建一个/usr/src/php的目录,里面放了一些自带的文件而已。我们就把它当作一个从互联网中下载下来的PHP扩展源码的存放目录即可。事实上,所有PHP扩展源码扩展存放的路径: /usr/src/php/ext 里面。
docker-php-source extract | delete
参数说明:
extract : 创建并初始化 /usr/src/php目录
delete : 删除 /usr/src/php目录
docker-php-ext-enable
这个命令,就是用来启动 PHP扩展 的。我们使用pecl安装PHP扩展的时候,默认是没有启动这个扩展的,如果想要使用这个扩展必须要在php.ini这个配置文件中去配置一下才能使用这个PHP扩展。而 docker-php-ext-enable 这个命令则是自动给我们来启动PHP扩展的,不需要你去php.ini这个配置文件中去配置。
docker-php-ext-enable redis
docker-php-ext-install
这个命令,是用来安装并启动PHP扩展的。
命令格式:上面有用到
docker-php-ext-install “源码包目录名”
注意点:
“源码包“需要放在 /usr/src/php/ext 下.
默认情况下,PHP容器没有 /usr/src/php这个目录,需要使用 docker-php-source extract来生成。
docker-php-ext-install 安装的扩展在安装完成后,会自动调用docker-php-ext-enable来启动安装的扩展。
卸载扩展,直接删除/usr/local/etc/php/conf.d 对应的配置文件即可。
docker-php-ext-configure
docker-php-ext-configure 一般都是需要跟 docker-php-ext-install搭配使用的。它的作用就是,当你安装扩展的时候,需要自定义配置时,就可以使用它来帮你做到。
安装redis
进入redis
rm -rf /usr/local/etc/php/conf.d/docker-php-ext-redis.ini 卸载reids
php -m //安装的扩展
curl -L -o /tmp/reids.tar.gz https://codeload.github.com/phpredis/phpredis/tar.gz/5.0.2 //下载reids
cd /tmp
tar -xzf reids.tar.gz //解压
docker-php-source extract //创建目录
mv phpredis-5.0.2 /usr/src/php/ext/phpredis //修改名字
ls -l /usr/src/php/ext | grep redis //检查是否存在
docker-php-ext-install phpredis //安装
php -m | grep redis //检查是否存在
CGI 是一个协议,所以,PHP 有自己对 CGI 的实现,那就是 PHP-CGI。可是呢,随着技术的发展,人们开始意识到,PHP-CGI 的性能不是那么尽如人意。PHP 在运行的时候,是依赖配置文件 php.ini的。所以,每当 PHP-CGI 开始工作的时候,它是完完全全的一个新进程,它需要重新加载配置文件并初始化,这就造成了很大的资源和时间的浪费。
那么怎么解决这个问题呢?
为什么不预先加载好配置,然后,每一个执行的任务只需要复制当前的进程,不就能避免上面的浪费了么。于是, FastCGI 便横空出世。
FastCGI,全称 Fast Common Gateway Interface,中文译作“快速公共网管接口”。没错,这又是个协议。当然,这个协议并不是因为 PHP 才有的。
Apache
对于 PHP 来说,httpd 是通过自身来实现一个 FastCGI 的模块的。它会预先加载好 php.ini 文件中的配置。待到有请求进入需要 PHP 处理时,PHP 就不需要再对 php.ini 重新加载了。这也就是每改动过 php.ini 后都要重启 httpd 服务的原因。
nginx
php-fpm 也是 FastCGI 的一种实现。通常我们是将 Nginx 的 PHP 处理部分代理到 php-fpm 的端口上,交给 php-fpm 来处理。而 php-fpm 同样是通过预先加载配置,然后给到子进程的方式的,它会对进程做一些管理。
http-Server服务,这是服务可以用于web项目开发中、也可以用于对laravel,thinkphp等框架进行加速; 如果想利用swoole加速框架、框架的条件必须是ioc类型因为swoole是常驻内存。
swoole解决的问题
我们用的 PHP 主要用于 web 开发,通过 nginx、apache 等服务端程序调用 php-fpm 处理服务端的业务逻辑,处理完后 php 撤消内存并返回结果。一个 web 请求就要加载一次 php 的全部文件,需要的系统资源开销很大,这是目前 php-fpm 的缺点之一;并且因为 php-fpm 在一次请求结束就释放内存,无法做连接池,也不合适 service 端的开发。
php-fpm 的优缺点:
优点:
部署简单
调试方便
基于传统 php 的项目非常多,易于参考
缺点:
每次 http 请求都要加载全部的项目文件
php-fpm 性能不佳,并发性能不好
核心不支持异步IO处理,IO密集型请求响应变长
对网络通信协议的支持不好,应用场景基本被限制在web领域
swoole是如何解决php-fpm遇到的问题的?
swoole如何避免文件的反复加载:
swoole是完全的长驻内存的,长驻内存一个最大的好处就是可以性能加速。在fpm模式下,我们处理一个请求,通常会有一些空消耗,比如框架共用文件加载,配置文件加载,那么在swoole中,可以在onworkerstart的时候提前一次性把一些必要的文件和配置加载好,不必每次receive重复加载一遍,这样能提升不小的性能。
常驻内存
常驻内存。传统 PHP框架或者单文件,在处理每个请求之前,都要做一遍加载框架文件、配置的操作,请求完成之后会释放所有资源和内存,无须担心内存泄漏。但是如果请求数量上升,并发很高的时候,快速创建资源,又马上释放,会导致 PHP 程序运行效率急剧下降。而使用 Swoole 则没有这个问题:PHP的代码加载到内存后,拥有更长的生命周期,这样建立的数据库连接和其他大的对象,不被释放。每次请求只需要处理很少的代码,而这些代码只在第一次运行时,被 PHP 解析器编译,驻留内存。以后都是直接载入 OPCODE ,让 Zend 引擎直接运行。另外,之前PHP不能实现的,如数据库连接池,缓存连接池都可以在Swoole引擎下实现。系统的运行效率会大大提高。
在 Laravel 应用中使用 Swoole 之前,先通过 Composer 安装 LaravelS 扩展包:
composer require hhxsv5/laravel-s
该扩展包具备自动发现功能(Laravel 5.5 以上版本可用),无需手动在 config/app.php 配置文件中注册,安装完成后,运行如下 Artisan 命令相应脚本和配置文件发布到根目录下:
php artisan laravels publish
该命令会发布配置文件 laravels.php 到 config 目录下,以及脚本文件到 bin 目录下:
你可以在配置文件中对 Swoole 进行一些基本配置,而脚本文件主要用于管理 Swoole 服务的启动、重载、关闭等操作。
配置
也可以在.env 修改工作进程数并重启服务
LARAVELS_LISTEN_IP=0.0.0.0
LARAVELS_LISTEN_PORT=5200
LARAVELS_WORKER_NUM=4
更多配置项: https://github.com/hhxsv5/laravel-s/blob/master/Settings-CN.md
启动 LaravelS
完成上述操作后,就可以通过 php bin/laravels start 命令启动 LaravelS 了:
这样,Swoole 服务就被启动起来,监听 5200 端口,如果有请求发送到这个端口,它就可以进行处理。
此外 php bin/laravels 还支持其它命令对 LaravelS 进行管理:
命令 | 说明 |
---|---|
start | 启动laravelS,展示已启动的进程列表 “ps -ef / grep laravelS” 支持选项 “-d /–daemonize” 以守护进程的方式运行,此选项将覆盖laravels.php中swoole.daemonize设置;支持选项 “-e /–env” 用来指定运行的环境,如 --env=testing将会优先使用配置.env.testing,这个特性要求laravel5.2+ |
stop | 停止laravelS |
restart | 停止laravelS,支持选项 “-d / --daemonize ”和 “-e / --env” |
reload | 平滑重启索引Task/Worker,这些进程包含了你的业务代码,不会重启Master/Manger/Timer/Custom进程 |
info | 显示组件的版本信息 |
help | 显示帮助信息 |
通过 Supervisor 管理 LaravelS
如果是在生产环境使用,推荐使用 Supervisor 对 LaravelS 服务进行管理,从而提供服务的稳定性,相应的配置示例如下:
[program:laravel-s-test]
command=php /www/wwwroot/lms/blog/bin/laravels start -i
numprocs=1
autostart=true
autorestart=true
startretries=3
user=root
redirect_stderr=true
stdout_logfile=/www/wwwroot/lms/blog/storage/logs/supervisord-stdout.log
其中 /www/wwwroot/lms/blog 为 Web 项目的目录,你可以根据自己的项目路径进行修改。
什么是反向代理?
反向代理和正向代理的区别就是:正向代理代理客户端,反向代理代理服务器。
反向代理,其实客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器IP地址。
nginx.conf配置
upstream swoole {
server 172.17.0.3:5200 weight=5 max_fails=3 fail_timeout=30s;
keepalive 16;
}
server {
listen 80;
listen [::]:80;
server_name localhost;
root /docker/www/lmrs-2008/public;
index index.php index.html;
location / {
try_files $uri @laravels;
}
location @laravels {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header Server-Protocol $server_protocol;
proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port;
proxy_pass http://swoole;
}
}
ab压测(可以在准备一份nginx环境的代码进行对比)
如果提示没有可用软件包 supervisor。
错误:无须任何处理
先安装
yum -y install epel-release
yum install -y supervisor
//安装完后 配置在etc目录里
cd etc
cp supervisord.conf supervisord.conf_bak