写点什么

【实践】高性能 PHP 应用容器 workerman 快速入门

作者:迷彩
  • 2022 年 8 月 28 日
    广东
  • 本文字数:4878 字

    阅读完需:约 16 分钟

前言

workerman--极简、稳定、高性能、分布式

workerman 是什么

workerman 是一款开源高性能 PHP 应用容器,它大大突破了传统 PHP 应用范围,被广泛的用于互联网、即时通讯、APP 开发、硬件通讯、智能家居、物联网等领域的开发。他是纯 php 实现的,跟 swoole 不一样,Swoole 是一个使用 C++ 语言编写的基于异步事件驱动和协程的并行网络通信引擎,对比来看 workerman 对 PHPer 更加友好,入门门槛更低,而且跨平台性更好,和已有的项目的对接更简单,更快速。因为它本身是 PHP 编写的,所以只要服务器支持 php 运行几乎就可以支持 workerman 的使用,无需更换运行环境或者对代码或者框架进行大幅的修改。集成到常见的框架比如 thinkphp、laravel 也很简单,兼容性好,特别是当服务器使用 windows 系统环境的时候 swoole 的支持不是很友好,这时候 workerman 就更显优势。不过事物都有两面性,有优点肯定也有缺点,最明显的就是 workerman 没有 swoole 强大,毕竟 workerman 是 PHP 实现的至少在运行效率上 swoole 略胜一筹。除了性能,在高并发上 swoole 也有较大的优势。


Workerman 不是重复造轮子,它不是一个 MVC 框架,而是一个更底层更通用的服务框架,你可以用它开发 tcp 代理、梯子代理、做游戏服务器、邮件服务器、ftp 服务器、甚至开发一个 php 版本的 redis、php 版本的数据库、php 版本的 nginx、php 版本的 php-fpm 等等。Workerman 可以说是 PHP 领域的一次创新,让开发者彻底摆脱了 PHP 只能做 WEB 的束缚。


实际上 Workerman 类似一个 PHP 版本的 nginx,核心也是多进程+Epoll+非阻塞 IO。Workerman 每个进程能维持上万并发连接。由于本身常驻内存,不依赖 Apache、nginx、php-fpm 这些容器,拥有超高的性能。同时支持 TCP、UDP、UNIXSOCKET,支持长连接,支持 Websocket、HTTP、WSS、HTTPS 等通讯协议以及各种自定义协议。拥有定时器、异步 socket 客户端、异步 Redis、异步 Http、异步消息队列等众多高性能组件。


为什么选择 workerman

不管使用任何框架,都不会达到最完美的,因为世界本就没有完美的东西。而是要根据自己的需求,有所取舍地去选择合适的框架或者架构,就比如:我们现在要做一个小网站,流量很小,如果我们不做分析,一开始直接就选择分布式架构,考虑高并发,高可用,高性能等三高方案全部考虑进去,对于小网站来说,无非就是入不敷出,付出远远大于回报,完全是一种浪费大量成本,吃力不讨好的操作。所以这时候先选择单机架构,预留扩展的空间即可,等流量起来了再一步一步扩展架构,而不是想着一步到位。因此,选择合适的更重要,不但能解决问题还能节约成本,最重要的是选择从简单架构开始,更容易实现,更快速上线,对应快速占领市场很有优势,如果选择复杂的架构,可能还没上线风都停了。workerman 有以下优势:

1.性能提升

基于常驻内存、epoll 高性能事件循环库、高性能协议解析,workerman 可将基于 php-fpm 的架构应用性能提升十倍甚至近百倍

2.稳定性

经过多年的不断打磨及完善,workerman 早已具备企业级的稳定性,已经被众多公司用在生产环境上

3.兼容性

兼容现有 composer 生态。即将推出的 workerman v5 版本将支持 PHP 自带的 Fiber 协程以及 Swoole、ReactPHP、AmPHP 等协程库

4.易用性

少既是多,workerman 只提供必要的功能接口,在保证 workerman 简约的同时,你会发现它使用真的很简单

5.应用场景广泛

Workerman 不同于传统 MVC 框架,Workerman 不仅可以用于 Web 开发,同时还有更广阔的应用领域,例如即时通讯类、物联网、游戏、服务治理、其它服务器或者中间件


我们上面简单对比了 workerman 和 swoole 的优缺点.简单分析了我们为什么选择 workerman.接下来我们看看 worker 怎么使用.


安装

workerman 从 3.5.3 版本开始同时支持 linux 系统和 windows 系统,不再区分 linux 版本和 windows 版本


环境准备

需要 PHP>=5.4,并配置好 PHP 的环境变量,最新版本的 workerman 需要 PHP>=7.0

本文的环境以 PHP7.2 为主

配置环境变量:


workerman 在 windows 和 linux 的区别参考:https://www.workerman.net/windows

workerman 的在 Windows 下与 Linux 下区别

1、win 版本单个进程只支持 200+个连接 2、win 版本 count 属性无效,全部为单进程 3、不支持 start stop reload restart status 命令 4、cmd 命令行启动,后面可接多个文件,例如 php start_web.php start_gateway.php start_worker.php5、无法守护进程,cmd 窗口关掉后服务即停止 6、每个启动文件只能实例化一个容器(Worker/WebServer/Gateway/BusinessWorker),需要实例化多个容器时需要拆成多个文件,例如 start_web.php start_gateway.php start_worker.php 分别初始化 web gateway worker

Windows 版本 workerman 的启动与停止

cmd 命令行中运行 php your_file.php(注意后面可以接多个文件)注意 windows 版本没有 stop、reload、restart、status 命令,启动时直接运行 php 文件.php 即可,停止运行按 ctrl+c


安装很简单,除了 php 的环境配置,跟其他的 php 第三方库的安装一样简单.只需要通过 composer 命令安装即可,或者下载源码放到项目中就可使用

项目源码地址:https://gitee.com/walkor/workerman

composer:https://www.phpcomposer.com(不熟悉 composer 的童鞋可以点击链接跳转了解)

composer 安装命令如下:

composer require workerman/workerman
复制代码

日常生产的流程主要分以下三种情况:

流程一:新项目流程 创建 composer.json,并添加依赖到的扩展包; 运行 composer install,安装扩展包并生成 composer.lock; 提交 composer.lock 到代码版本控制器中,如:git

流程二:项目协作者安装现有项目 克隆项目后,根目录下直接运行 composer install 从 composer.lock 中安装 指定版本 的扩展包以及其依赖

此流程适用于生产环境代码的部署。

流程三:为项目添加新扩展包

使用 composer require vendor/package 添加扩展包; 提交更新后的 composer.json 和 composer.lock 到代码版本控制器中,如:git


composer install - 如有 composer.lock 文件,直接安装,否则从 composer.json 安装最新扩展包和依赖

  • composer update - 从 composer.json 安装最新扩展包和依赖

  • composer update vendor/package - 从 composer.json 或者对应包的配置,并更新到最新

  • composer require new/package - 添加安装 new/package, 可以指定版本,如: composer require new/package ~2.7


  • 安装步骤:

    1. 新建项目文件夹 wmtest

    2. 进入项目根目录

    3. 初始化项目

    4. 执行上面的命令或者 composer init

    新建的文件还是空的:

    方法 1:

    我们这个是新项目执行composer init对项目进行初始化,执行操作如下图:


    一直下一步等待安装完成即可

    方法 2:

    进入项目目录执行composer require workerman/workerman

    执行过程如下:


    安装完成之后项目目录会增加三个文件,如下图

    vendor 就是 composer 安装所有依赖的文件夹.现在里面有我们刚安装的 workerman 依赖:

    从 composer.json 的内容中也可以看到安装了哪些依赖

    从上图可以看出,我们只安装了 workerman4.0 的依赖

    安装完接下来就是使用了

    workerman 的简单使用

    WorkerMan 开发与普通 PHP 开发的不同之处

    • 普通 PHP 开发一般是基于 HTTP 应用层协议,WebServer 已经帮开发者完成了协议的解析

    • WorkerMan 支持各种协议,目前内置了 HTTP、WebSocket 等协议。WorkerMan 推荐开发者使用更简单的自定义协议通讯

    • PHP 在 Web 应用中一次请求过后会释放所有的变量与资源

    • WorkerMan 开发的应用程序在第一次载入解析后便常驻内存,使得类的定义、全局对象、类的静态成员不会释放,便于后续重复利用

    • 由于 WorkerMan 会缓存编译后的 PHP 文件,所以要避免多次 require/include 相同的类或者常量的定义文件。建议使用 require_once/include_once 加载文件。

    • 由于 WorkerMan 是常驻内存的,php 类即函数的定义加载一次后便常驻内存,不会再次读取磁盘加载,所以每次修改完业务代码需要重启才能生效。

    • WorkerMan 运行在 PHP 命令行模式下,当调用 exit、die 退出语句时,会导致当前进程退出。虽然子进程退出后会立刻重新创建一个的相同的子进程继续服务,但是还是可能对业务产生影响。

    • 由于 WorkerMan 不会在每次请求后释放全局对象及类的静态成员,在数据库等单例模式中,往往会将数据库实例(内部包含了一个数据库 socket 连接)保存在数据库静态成员中,使得 WorkerMan 在进程生命周期内都复用这个数据库 socket 连接。需要注意的是当数据库服务器发现某个连接在一定时间内没有活动后可能会主动关闭 socket 连接,这时再次使用这个数据库实例时会报错,(错误信息类似 mysql gone away)。WorkerMan 提供了数据库类,有断开重连的功能,开发者可以直接使用。


    注意事项:有必要注意下代码是运行在主进程还是子进程,一般来说在Worker::runAll();调用前运行的代码都是在主进程运行的,onXXX 回调运行的代码都属于子进程。注意写在Worker::runAll();后面的代码永远不会被执行


    下面我们使用 workerman 编写一些简单的例子

    利用 workerman 实现 Http server

    文件:test.php

    <?phpuse Workerman\Worker;use Workerman\Connection\TcpConnection;use Workerman\Protocols\Http\Request;require_once __DIR__ . '/vendor/autoload.php';
    // 创建一个Worker监听2345端口,使用http协议通讯$http_worker = new Worker("http://0.0.0.0:2345");
    // 启动4个进程对外提供服务$http_worker->count = 4;
    // 接收到浏览器发送的数据时回复hello world给浏览器$http_worker->onMessage = function(TcpConnection $connection, Request $request){ // 向浏览器发送hello world $connection->send('你好,欢迎使用workerman~');};
    // 运行workerWorker::runAll();
    复制代码


    打开命令行,执行以下命令然后访问http://127.0.0.1:2345/

    php test.php start
    复制代码

    执行效果如下:


    利用 workerman 实现 WebSocket

    文件:ws_test.php

    <?phpuse Workerman\Worker;use Workerman\Connection\TcpConnection;require_once __DIR__ . '/vendor/autoload.php';
    // 注意:这里与上个例子不同,使用的是websocket协议$ws_worker = new Worker("websocket://0.0.0.0:2000");
    // 启动4个进程对外提供服务$ws_worker->count = 4;
    // 当收到客户端发来的数据后返回hello $data给客户端$ws_worker->onMessage = function(TcpConnection $connection, $data){ // 向客户端发送hello $data $connection->send('你好,欢迎你找我聊天哦! ' . $data);};
    // 运行workerWorker::runAll();
    复制代码

    通过前端进行请求.创建 testws.html

    <html> <head>   <title>测试Websocket</title>   <style> body { margin: 0; } canvas { width: 100%; height: 100% } </style>  </head>  <body>   <script>	ws = new WebSocket("ws://127.0.0.1:2000");	ws.onopen = function() {		console.log("连接成功");		ws.send('李白');		console.log("给服务端发送一个字符串:你好!我来了");	};	ws.onmessage = function(e) {		console.log("收到服务端的消息:" + e.data);	};
    </script> </body></html>
    复制代码

    执行结果:


    前端返回结果:


    利用 workerman 实现直接使用 TCP 传输数据

    文件:tcp_test.php

    <?phpuse Workerman\Worker;use Workerman\Connection\TcpConnection;require_once __DIR__ . '/vendor/autoload.php';
    // 创建一个Worker监听2347端口,不使用任何应用层协议$tcp_worker = new Worker("tcp://0.0.0.0:2347");
    // 启动4个进程对外提供服务$tcp_worker->count = 4;
    // 当客户端发来数据时$tcp_worker->onMessage = function(TcpConnection $connection, $data){ // 向客户端发送hello $data $connection->send('你好,数据传输成功' . $data);};
    // 运行workerWorker::runAll();
    复制代码

    执行结果:

    启动 tcp 服务

    测试 tcp 服务

    telnet 127.0.0.1 2347
    复制代码

    执行结果:


    这里只是利用简单的例子抛转引玉,workman 还有更多更好玩,更强大的用法等你探索.需要掌握 workerman 支持的各种通讯协议的用法.workerman 目前已经支持 HTTP、websocket、text 协议、frame 协议,ws 协议,需要基于这些协议通讯时可以直接使用,使用方法为:在初始化 Worker 时指定协议,比如使用$tcp_worker = new Worker("tcp://0.0.0.0:2347");创建 tcp 服务.当 workerman 自带的通讯协议满足不了开发需求时,还可以可以根据需求定制自己的通讯协议.所以要想玩好 workerman 一定要熟悉掌握各种通讯协议的使用

    发布于: 刚刚阅读数: 8
    用户头像

    迷彩

    关注

    我的工作是常年写bug|公众号:编程架构之美 2020.06.18 加入

    修bug的菜鸟~公众号:“互联网有啥事”已改名为“编程架构之美”

    评论

    发布
    暂无评论
    【实践】高性能PHP应用容器workerman快速入门_即时通讯_迷彩_InfoQ写作社区