一、什么是 APCu(一句话版)
APCu = 给 PHP 用的“进程间共享内存缓存”。
- A = Alternative
- P = PHP
- C = Cache
- u = user(用户态缓存,不是 opcode cache)
👉 核心特性一句话:
APCu 允许 不同 PHP-FPM worker 进程 共享一块内存,用来存 PHP 变量(数组、字符串等),避免每个请求都重新计算或查数据库。
二、没有 APCu 的世界(先理解痛点)
假设你现在的情况(不使用 APCu):
PHP-FPM 典型模型
Nginx
↓
PHP-FPM
├─ worker #1
├─ worker #2
├─ worker #3
└─ worker #8每个 worker 都是:
- 一个独立的 Linux 进程
- 有自己独立的内存空间
- 互相之间看不到变量
举例,如果你这么写:
static $dict = null;
if ($dict === null) {
$dict = load_big_dict_from_db();
}结果是:
- worker #1:查 DB → 构建词库 → 常驻在 #1 的内存
- worker #2:重新查 DB → 再构建一遍
- worker #3:再来一遍
- …
👉 例如有数十万数据的词库,会被“每个 worker 各自构建一份”,数据库压力巨大
三、APCu 出现的意义
APCu 做的事情本质上只有一件:
在 PHP-FPM master 进程创建的一块共享内存中,存放你指定的数据。
使用 APCu 后的结构:
共享内存区(APCu)
└─ dict_v_12_8 (你的词库)
PHP-FPM
├─ worker #1 ──┐
├─ worker #2 ──┼─ apcu_fetch('dict_v_12_8')
├─ worker #3 ──┘
└─ worker #8- 词库只构建一次
- 所有 worker 都能
apcu_fetch()到 - DB 只在“缓存未命中 / 版本变更”时访问
四、APCu 的关键特性(非常重要)
1️⃣ APCu 是“进程间共享”的
这点和 static、global 完全不同。
| 存储方式 | 是否跨 worker | 是否跨请求 |
|---|---|---|
| 普通变量 | ❌ | ❌ |
| static | ❌ | ✅(仅当前 worker) |
| APCu | ✅ | ✅ |
2️⃣ APCu 只存在于一台机器
- ❌ 不会跨服务器
- ❌ 不会像 Redis 那样网络共享
- ✅ 速度比 Redis 快一个数量级(纯内存 + 无网络)
👉 非常适合:
- 词库
- 配置
- 元数据
- 不需要跨机器同步的数据
3️⃣ APCu 在 PHP-FPM 重启时会全部丢失
这是 特性,不是 bug:
- PHP-FPM reload / restart
- 服务器重启
👉 缓存自动清空,下一个请求自动重建即可
非常适合“可再生数据”(你的词库正是)
五、PHP-FPM worker 的运作机制(重点)
1️⃣ PHP-FPM master + workers
启动 PHP-FPM 后:
- 1 个 master 进程
- 多个 worker 子进程
master 负责:
- 创建 worker
- 回收 worker
- 管理 socket
worker 负责:
- 真正执行 PHP 脚本
- 处理 HTTP 请求
2️⃣ 一个请求是怎么跑的?
以 Nginx + PHP-FPM 为例:
- 请求到 Nginx
- Nginx 把请求丢给 PHP-FPM
- PHP-FPM 找一个 空闲 worker
worker 执行:
- 解析 PHP
- 执行你的代码
- 返回结果
- worker 不退出,继续等下一个请求
👉 worker 是“常驻进程”,不是“执行完就死”。
3️⃣ worker 内存会不会一直涨?
正常情况下:
- PHP 的变量在请求结束时会释放
- static 变量会保留
- APCu 内存不在 worker 内,而在共享区
PHP-FPM 有两个关键参数:
pm.max_requests = 500含义:
- worker 处理 500 个请求后
- 自动退出并重建(防内存泄漏)
👉 这也是为什么:
- APCu 不会因为 worker 重启丢数据
- static 缓存会丢(但可从 APCu 重新加载)
六、APCu + static 的“黄金组合”
例如,这样写:
static $local = null;
static $localVer = null;这是 非常经典、非常正确的模式:
第一次请求(某 worker):
static $local === nullapcu_fetch()→ 拿到大数组$local = $dict(放进 worker 私有内存)
后续请求(同一个 worker):
- 完全不访问 APCu
- 直接用
$local
👉 好处:
- 减少 APCu 锁竞争
- 内存复制次数更少
- 性能极稳
七、为什么不用 Redis?
你这个场景下,APCu 明显优于 Redis:
| 项目 | APCu | Redis |
|---|---|---|
| 访问速度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 网络 | 无 | TCP |
| 部署复杂度 | 极低 | 较高 |
| 序列化 | PHP 原生 | 必须 |
| 跨服务器 | ❌ | ✅ |
👉 单机 PHP-FPM 场景:APCu = 最优解
八、你现在这个项目,APCu 的“正确定位”
对你而言,APCu 应该用来缓存:
✅ 词库
✅ tagdict_version
✅ 一些系统配置映射
❌ 用户 session(用 Redis 更好)
❌ 跨服务器共享状态
九、怎么确认你的服务器已经支持 APCu?
1️⃣ 看扩展
php -m | grep apcu2️⃣ 看 phpinfo()
<?php phpinfo(); ?>查:
APCu Support => Enabledapc.enabled => Onapc.enable_cli => Off(CLI 不需要)
十、一句“工程师级”总结
PHP-FPM = 多个长期存活的 worker 进程
APCu = 让这些 worker 共享一份内存数据的唯一官方方案
static + APCu = 高性能 PHP 服务的基础缓存模型
👉 从“脚本思维”升级到“常驻服务思维”
这一步,很多 PHP 程序员一辈子都没跨过去。
本文来自投稿,不代表本站立场,如若转载,请注明出处: