专注于高性能网络应用开发,核心技术包括PHP、Java、GO、NodeJS等后端语言,VUE、UNI、APP等前端开发,服务器运维、数据库、实时通信、AI等领域拥有丰富经验

ThinkPHP框架长连接高并发之:Think-Worker实战指南 轻松构建高性能PHP应用,性能提升50倍

Think-Worker是一个基于Workerman实现的ThinkPHP扩展,专为构建高性能应用和提升现有应用性能而设计。它通过常驻内存运行模式,避免了传统PHP-FPM每次请求重新加载框架的开销,同时支持HTTP、WebSocket和队列处理,特别适合实时通讯、游戏服务器等场景。本文将带你快速掌握Think-Worker的使用方法,并解答常见问题。

什么是Think-Worker?

Think-Worker是一个ThinkPHP框架的扩展,它利用Workerman的强大功能,为PHP应用提供高性能的运行环境。主要优势包括:

  • 高性能长连接 - 基于Workerman实现常驻内存运行,避免传统PHP-FPM每次请求重新加载框架的开销
  • 多协议支持 - 同时支持HTTP、WebSocket和队列处理,适合实时通讯、游戏服务器等场景
  • 无缝集成ThinkPHP - 完全复用ThinkPHP的路由、中间件、ORM等组件,开发体验一致
  • 内置队列处理 - 无需额外进程即可处理队列任务,简化部署和资源管理

第一步:安装和准备

1. 安装扩展

本扩展要求PHP 8.2+和Workerman 5.0+,通过Composer安装:

composer require topthink/think-worker

安装后,会自动在config目录生成worker.php初始配置文件。

2. 启动服务器

php think worker

打开浏览器访问 http://localhost:8080,恭喜你!你的第一个Worker服务器已经运行起来了!

💡 小贴士:如果8080端口被占用,可以在config/worker.php中修改端口号。

第二步:理解基本概念

Worker进程是什么?

传统PHP模式

用户请求 → 启动PHP进程 → 加载框架 → 处理请求 → 返回结果 → 销毁进程

Worker模式

启动Worker进程(一直运行) → 用户请求 → 处理请求 → 返回结果 → 等待下一个请求

Worker模式省去了每次请求都要启动进程和加载框架的时间,这就是性能提升的关键!

第三步:HTTP服务器使用

基础配置

编辑config/worker.php:

return [
    'http' => [
        'enable'     => true,        // 启用 HTTP 服务器
        'host'       => '0.0.0.0',   // 监听所有 IP
        'port'       => 8080,        // 端口号
        'worker_num' => 4,           // 进程数(建议设置为 CPU 核心数)
    ],
    // ... 其他配置
];

使用示例

1. 简单的Hello World

在route/app.php中添加:

Route::get('/hello', function () {
    return 'Hello, Worker!';
});

2. 处理JSON请求

Route::post('/api/user', function (Request $request) {
    $name = $request->post('name');
    $age = $request->post('age');
    
    // 处理业务逻辑...
    
    return json([
        'code' => 200,
        'msg' => '创建成功',
        'data' => [
            'name' => $name,
            'age' => $age,
            'id' => rand(1000, 9999)
        ]
    ]);
});

3. 文件下载

Route::get('/download/:file', function ($file) {
    $path = public_path() . 'downloads/' . $file;
    
    if (!file_exists($path)) {
        return '文件不存在';
    }
    
    return new \think\worker\response\File($path);
});

4. 服务器推送事件(SSE)

Route::get('/sse/time', function () {
    $generator = function () {
        while (true) {
            yield 'data: ' . json_encode([
                'time' => date('Y-m-d H:i:s'),
                'memory' => memory_get_usage()
            ]) . "\n\n";
            
            sleep(1); // 每秒推送一次
        }
    };
    
    return (new \think\worker\response\Iterator($generator()))
        ->header([
            'Content-Type' => 'text/event-stream',
            'Cache-Control' => 'no-cache',
        ]);
});

前端接收:

const eventSource = new EventSource('/sse/time');
eventSource.onmessage = function(event) {
    const data = JSON.parse(event.data);
    console.log('服务器时间:', data.time);
};

第四步:WebSocket实时通信

1. 启用WebSocket

在config/worker.php中:

'websocket' => [
    'enable'        => true,
    'handler'       => \think\worker\websocket\Handler::class,
    'ping_interval' => 25000,    // 心跳间隔(毫秒)
    'ping_timeout'  => 60000,    // 心跳超时(毫秒)
],

2. 创建聊天室示例

创建控制器app/controller/Chat.php:

<?php
namespace app\controller;

use think\worker\response\Websocket;
use think\worker\Websocket as WS;
use think\worker\websocket\Frame;

class Chat
{
    public function index()
    {
        return (new Websocket())
            ->onOpen(function (WS $websocket) {
                // 新用户进入聊天室
                $websocket->join('chat_room');
                
                // 获取连接ID
                $userId = $websocket->getSender();
                
                // 通知所有人
                $websocket->to('chat_room')->push([
                    'type' => 'system',
                    'msg' => "用户{$userId}进入了聊天室",
                    'time' => date('H:i:s')
                ]);
            })
            ->onMessage(function (WS $websocket, Frame $frame) {
                // 收到消息
                $data = json_decode($frame->data, true);
                $userId = $websocket->getSender();
                
                // 广播消息给聊天室所有人
                $websocket->to('chat_room')->push([
                    'type' => 'message',
                    'user' => $userId,
                    'msg' => $data['msg'],
                    'time' => date('H:i:s')
                ]);
            })
            ->onClose(function (WS $websocket) {
                // 用户离开
                $userId = $websocket->getSender();
                
                $websocket->to('chat_room')->push([
                    'type' => 'system',
                    'msg' => "用户{$userId}离开了聊天室",
                    'time' => date('H:i:s')
                ]);
            });
    }
}

路由配置:

Route::get('/chat', 'Chat/index');

3. 前端连接代码

创建一个简单的聊天页面:

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket 聊天室</title>
</head>
<body>
    <div id="messages"></div>
    <input type="text" id="messageInput" placeholder="输入消息...">
    <button onclick="sendMessage()">发送</button>
    <script>
        // 连接 WebSocket
        const ws = new WebSocket('ws://localhost:8080/chat');
        
        // 连接成功
        ws.onopen = function() {
            addMessage('系统', '连接成功!');
        };
        
        // 收到消息
        ws.onmessage = function(event) {
            const data = JSON.parse(event.data);
            
            if (data.type === 'system') {
                addMessage('系统', data.msg);
            } else {
                addMessage(data.user, data.msg);
            }
        };
        
        // 发送消息
        function sendMessage() {
            const input = document.getElementById('messageInput');
            const msg = input.value;
            
            if (msg) {
                ws.send(JSON.stringify({ msg: msg }));
                input.value = '';
            }
        }
        
        // 显示消息
        function addMessage(user, msg) {
            const div = document.getElementById('messages');
            div.innerHTML += `<p><b>${user}:</b> ${msg}</p>`;
            div.scrollTop = div.scrollHeight;
        }
        
        // 回车发送
        document.getElementById('messageInput').addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                sendMessage();
            }
        });
    </script>
</body>
</html>

第五步:队列处理

1. 安装队列组件

composer require topthink/think-queue

2. 配置队列

在config/worker.php中:

'queue' => [
    'enable'  => true,
    'workers' => [
        // 默认队列
        'default' => [
            'delay'      => 0,       // 延迟时间(秒)
            'sleep'      => 3,       // 没有任务时休眠时间(秒)
            'tries'      => 3,       // 失败重试次数
            'timeout'    => 60,      // 任务超时时间(秒)
            'worker_num' => 1,       // 处理进程数
        ],
        // 邮件队列(处理较慢,多开几个进程)
        'email' => [
            'worker_num' => 3,
        ],
        // 紧急队列(优先处理)
        'urgent' => [
            'sleep' => 1,            // 休眠时间短,响应更快
            'worker_num' => 2,
        ],
    ],
],

3. 创建任务类

创建app/job/SendEmail.php:

<?php
namespace app\job;

use think\queue\Job;

class SendEmail
{
    /**
     * 执行任务
     */
    public function fire(Job $job, $data)
    {
        try {
            // 模拟发送邮件
            echo "发送邮件给:{$data['email']}\n";
            echo "主题:{$data['subject']}\n";
            echo "内容:{$data['content']}\n";
            
            // 实际发送邮件的代码...
            // Mail::send(...);
            
            // 任务执行成功,删除任务
            $job->delete();
            
        } catch (\Exception $e) {
            // 任务执行失败
            echo "发送失败:" . $e->getMessage() . "\n";
            
            // 检查是否超过重试次数
            if ($job->attempts() > 3) {
                echo "重试次数过多,放弃任务\n";
                $job->delete();
            } else {
                // 10秒后重试
                $job->release(10);
            }
        }
    }
}

4. 投递任务

在控制器或其他地方:

use think\facade\Queue;

// 立即执行
Queue::push('app\job\SendEmail', [
    'email' => 'user@example.com',
    'subject' => '欢迎注册',
    'content' => '感谢您注册我们的网站!'
], 'email');

// 延迟10秒执行
Queue::later(10, 'app\job\SendEmail', [
    'email' => 'user@example.com',
    'subject' => '注册成功',
    'content' => '您的账号已经创建成功!'
], 'email');

第六步:生产环境部署

1. 使用Supervisor管理进程

安装Supervisor:

sudo apt-get install supervisor

创建配置文件/etc/supervisor/conf.d/think-worker.conf:

[program:think-worker]
command=php /path/to/your/project/think worker
directory=/path/to/your/project
autostart=true
autorestart=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/think-worker.log

启动:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start think-worker

2. Nginx反向代理

server {
    listen 80;
    server_name your-domain.com;
    
    # 静态文件
    location ~ \.(jpg|png|gif|js|css|ico|html)$ {
        root /path/to/your/project/public;
    }
    
    # HTTP 请求
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    # WebSocket
    location /chat {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Think-Worker的核心优势

性能对比数据

测试项目PHP-FPMthink-worker性能提升
Hello World QPS3,000150,000+50倍
复杂业务接口200 QPS8,000 QPS40倍
WebSocket连接数不支持100,000+-
内存占用(100并发)2GB800MB节省60%
数据库查询耗时5ms(含连接)1ms(连接池)快5倍

核心技术优势

1. 智能内存管理 - Sandbox沙盒机制

think-worker使用创新的沙盒机制,每个请求都在独立的应用副本中运行:

// 自动清理机制
- ClearInstances: 清理单例实例
- ResetConfig: 重置配置状态
- ResetEvent: 清理事件监听
- ResetService: 重置服务状态
- ResetModel: 清理模型缓存
- ResetPaginator: 重置分页器

// 自定义清理器
class MyResetter implements ResetterInterface
{
    public function handle(App $app, Sandbox $sandbox)
    {
        // 清理你的自定义状态
        MyCache::clear();
        MyGlobal::reset();
    }
}

2. 进程间通信 - Conduit系统

独特的Conduit系统实现高效的进程间数据共享:

$conduit = app('think.worker.conduit');

// 原子操作
$conduit->inc('counter'); // 原子递增
$conduit->set('key', 'value'); // 设置值
$conduit->get('key'); // 获取值

// 集合操作
$conduit->sAdd('online_users', $userId);
$conduit->sMembers('online_users');

// 发布订阅
$conduit->publish('channel', $message);
$conduit->subscribe('channel', function($message) {
    // 处理消息
});

// 实现分布式锁
if ($conduit->inc('lock:resource') === 1) {
    try {
        // 执行临界区代码
    } finally {
        $conduit->set('lock:resource', 0);
    }
}

3. FlexHttp协议 - 一端口多协议

同一端口同时支持HTTP和WebSocket:

// 自动识别协议,无需额外配置
// HTTP: http://localhost:8080/api
// WebSocket: ws://localhost:8080/chat

总结

恭喜你!现在你已经掌握了think-worker的核心功能:

✅ HTTP高性能服务器
✅ WebSocket实时通信
✅ 队列异步处理
✅ 生产环境部署

相比传统PHP-FPM,think-worker能让你的应用:

  • 响应速度提升10-100倍
  • 支持长连接和实时推送
  • 更高效地处理并发请求
  • 更好地利用服务器资源

记住:think-worker不是魔法,而是一种更高效的运行方式。它特别适合:

  • 需要实时通信的应用(聊天、游戏、协作)
  • 高并发的API服务
  • 需要推送通知的系统
  • IoT物联网应用

虽然think-worker原生不支持分布式,但通过本教程提供的方案,你可以轻松扩展到多服务器部署。选择合适的方案,让你的应用飞起来!

相关文章

一些编程语言学习心得

作为一名专注于PHP、Go、Java和前端开发(JavaScript、HTML、CSS)的开发者,还得会运维、会谈客户....不想了,都是泪,今天说说这些年学习编程语言的一些体会,不同编程语言在...