不能直接在控制器里调用Search::use()执行搜索,因为Webman的HTTP进程是同步阻塞模型,而全文搜索本质是网络IO密集操作,直接调用会导致每个请求独占Worker进程等待响应,引发页面卡顿、超时、内存暴涨及502错误;正确做法是将搜索封装为异步任务或交由独立Worker/Redis队列处理。

为什么不能直接在控制器里调用 Search::use() 执行搜索
常见错误现象:页面加载卡顿、超时、内存暴涨、并发稍高就返回 502。根本原因是 Webman 的 HTTP 进程是同步阻塞模型,而全文搜索(尤其是 Meilisearch/Elasticsearch)本质是网络 IO 密集操作,Search::use() 底层会发起 HTTP 请求,若在 app/controller 中直接调用,每个请求都会独占一个 Worker 进程等待响应,无法释放事件循环。
正确做法只有一类:把搜索请求封装为轻量异步任务或交由独立进程处理。比如用户提交关键词后,控制器只做参数校验和日志记录,然后立即返回「搜索中」状态;真实查询必须剥离到 app/worker 目录下的自定义 Worker 类中运行,或通过 Redis 队列 + 定时轮询方式解耦。
Search::use() 的参数陷阱与连接复用要点
这个方法看似简单,但传参不对会导致连接泄漏、中文乱码、QPS 断崖下跌:
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
-
Search::use('meilisearch', ['id' => 'id', 'index' => 'movies'])中的id必须与实际文档主键字段名完全一致,且该字段值不能含空格或特殊符号,否则 Meilisearch 写入失败但不报错 - 若用 Elasticsearch,
index名必须小写,且不能含下划线开头(如_movies会被拒绝) - 所有搜索引擎客户端实例必须全局复用——不能每次搜索都 new 一个
Search实例,否则 TCP 连接无法复用,DNS 缓存失效,100 QPS 就可能打满连接数 - 中文搜索默认乱码?检查 Meilisearch 的
accept-languageheader 是否被覆盖,或 Elasticsearch 的 analyzer 是否配置了ik_smart
索引更新为何总失败:search:update:index 的三个硬性前提
执行 php webman search:update:index 报错或无反应,大概率是以下条件没满足:
- Meilisearch 服务端必须已启动且密钥匹配(
MEILI_MASTER_KEY要和php webman shopwwi:search生成的密钥一致) - Elasticsearch 索引必须已存在(需先执行
php webman search:create:index),且 mapping 字段类型与写入数据结构严格对应(比如title定义为text,就不能传整数进去) - Xunsearch 的
config/plugin/shopwwi/search/ini/index.ini文件必须存在且权限可读,其中charset=utf-8不可省略,否则中文检索全失效
分布式部署时,Search::create() 写入失败的隐蔽原因
多台 Webman 实例共用同一个 Meilisearch 或 ES 集群时,$search->create($data) 偶发丢数据,不是网络问题,而是:
- 未启用去重机制:同一文档被多个 Worker 并发写入,ES 可能因版本冲突静默丢弃,Meilisearch 默认不校验重复 ID,Xunsearch 则依赖
id字段自动覆盖——但前提是你的$data数组里每个元素都有明确且唯一的id键 - 批量写入大小超标:Meilisearch 默认单次
create最多 1000 条,ES 推荐不超过 10MB payload,超限直接 413;建议拆成每 50–100 条一批,加try/catch捕获MeiliSearchException - Redis 作为队列时,若用 SCAN 遍历任务,高并发下性能崩塌——必须改用 ZSET + score 控制优先级,且消费端用
ZPOPMIN原子取任务
最易被忽略的是:所有搜索引擎客户端的 timeout 参数必须显式设为 3–5 秒,不能依赖默认值。Webman Worker 进程默认最大执行时间 30 秒,但搜索请求一旦卡住,会拖垮整个进程池。


















