PHP开发:什么是APCu,以及PHP-FPM worker的运作机制

本文阅读 5 分钟
首页 开发运维 正文

一、什么是 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 是“进程间共享”的

这点和 staticglobal 完全不同。

存储方式是否跨 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 为例:

  1. 请求到 Nginx
  2. Nginx 把请求丢给 PHP-FPM
  3. PHP-FPM 找一个 空闲 worker
  4. worker 执行:

    • 解析 PHP
    • 执行你的代码
    • 返回结果
  5. 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):

  1. static $local === null
  2. apcu_fetch() → 拿到大数组
  3. $local = $dict(放进 worker 私有内存)

后续请求(同一个 worker):

  • 完全不访问 APCu
  • 直接用 $local

👉 好处:

  • 减少 APCu 锁竞争
  • 内存复制次数更少
  • 性能极稳

七、为什么不用 Redis?

你这个场景下,APCu 明显优于 Redis

项目APCuRedis
访问速度⭐⭐⭐⭐⭐⭐⭐⭐⭐
网络TCP
部署复杂度极低较高
序列化PHP 原生必须
跨服务器

👉 单机 PHP-FPM 场景:APCu = 最优解


八、你现在这个项目,APCu 的“正确定位”

对你而言,APCu 应该用来缓存:

✅ 词库
✅ tagdict_version
✅ 一些系统配置映射
❌ 用户 session(用 Redis 更好)
❌ 跨服务器共享状态


九、怎么确认你的服务器已经支持 APCu?

1️⃣ 看扩展

php -m | grep apcu

2️⃣ 看 phpinfo()

<?php phpinfo(); ?>

查:

  • APCu Support => Enabled
  • apc.enabled => On
  • apc.enable_cli => Off(CLI 不需要)

十、一句“工程师级”总结

PHP-FPM = 多个长期存活的 worker 进程
APCu = 让这些 worker 共享一份内存数据的唯一官方方案
static + APCu = 高性能 PHP 服务的基础缓存模型

👉 从“脚本思维”升级到“常驻服务思维”
这一步,很多 PHP 程序员一辈子都没跨过去。

本文来自投稿,不代表本站立场,如若转载,请注明出处:
-- 展开阅读全文 --
阿里云服务器带宽计费中的"CDT计费"是什么,与其它计费方式相比的优缺点
« 上一篇 10-11

热门文章

标签TAG