PHP信创=鲲鹏ARM64平台PHP高性能部署与协程框架适配
·
---
鲲鹏ARM64平台PHP高性能部署与协程框架适配实战
--- 一、先搞清楚鲲鹏是什么(大白话)
┌───────────────┬─────────────────────────────────────────────────────────────────────────────────┐
│ 概念 │ 大白话解释 │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────┤
│ 鲲鹏920 │ 华为自研ARM服务器CPU,最多128核,指令集ARMv8.2,比飞腾更新一代 │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────┤
│ TaiShan微架构 │ 鲲鹏920的内部微架构代号,GCC里用-mtune=tsv110针对它优化 │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────┤
│ 毕昇编译器 │ 华为基于LLVM专门为鲲鹏优化的编译器,比GCC更懂鲲鹏的流水线 │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────┤
│ NUMA │ 鲲鹏920双路服务器有4个NUMA节点,跨节点访问内存会慢,需要绑核 │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────┤
│ jemalloc │ Facebook开发的内存分配器,替换Linux默认的ptmalloc,减少内存碎片,高并发下快很多 │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────┤
│ 协程 │ 用户态的"轻量线程",一个进程里可以跑几万个协程,遇到IO自动切换,不阻塞 │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────┤
│ Swoole Hook │ 一键把PHP原生的阻塞IO函数(file_get_contents、PDO等)变成协程非阻塞 │
├───────────────┼─────────────────────────────────────────────────────────────────────────────────┤
│ openEuler │ 华为开源的Linux系统,专门针对鲲鹏做了内核优化,是鲲鹏的最佳搭档 │
└───────────────┴─────────────────────────────────────────────────────────────────────────────────┘
鲲鹏920主要型号:
┌──────────┬─────────────┬────────┬────────────┐
│ 型号 │ 核心数 │ 主频 │ 典型场景 │
├──────────┼─────────────┼────────┼────────────┤
│ 920-3226 │ 32核 │ 2.6GHz │ 通用服务器 │
├──────────┼─────────────┼────────┼────────────┤
│ 920-4826 │ 48核 │ 2.6GHz │ 中等负载 │
├──────────┼─────────────┼────────┼────────────┤
│ 920-6426 │ 64核 │ 2.6GHz │ 高并发Web │
├──────────┼─────────────┼────────┼────────────┤
│ 920-7260 │ 64核 │ 2.6GHz │ 数据中心 │
├──────────┼─────────────┼────────┼────────────┤
│ 920-7265 │ 128核(双路) │ 3.0GHz │ 超高并发 │
└──────────┴─────────────┴────────┴────────────┘
---
二、环境确认与系统准备
# 1. 确认架构(必须是 aarch64)
uname -m
# 期望:aarch64
# 2. 确认是鲲鹏CPU
cat /proc/cpuinfo | grep "model name" | head -1
# 期望类似:Kunpeng-920 或 ARMv8 Processor rev 0 (v8l)
# 3. 查看NUMA拓扑(鲲鹏920双路有4个NUMA节点)
numactl --hardware
# 输出示例:
# available: 4 nodes (0-3)
# node 0 cpus: 0 1 2 3 ... 31
# node 0 size: 65536 MB
# node distances:
# node 0 1 2 3
# 0: 10 16 32 33 ← 10=本地最快,数字越大越慢
# 4. 查看操作系统
cat /etc/os-release
# 推荐:openEuler 22.03 LTS 或 EulerOS 2.9
# 5. 查看GCC版本
gcc --version
# 鲲鹏推荐GCC 10+,或使用毕昇编译器
# 6. 查看CPU核心数
nproc
# 鲲鹏920单路64核,双路128核
---
三、安装编译依赖
openEuler / EulerOS(推荐,华为官方优化)
# 更新系统
sudo dnf update -y
# 安装编译工具链
sudo dnf groupinstall -y "Development Tools"
# 安装PHP编译依赖
sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
autoconf \
bison \
re2c \
pkg-config \
numactl \
numactl-devel \
jemalloc \
jemalloc-devel \
libxml2-devel \
openssl-devel \
libcurl-devel \
libpng-devel \
libjpeg-devel \
libwebp-devel \
freetype-devel \
libzip-devel \
zlib-devel \
sqlite-devel \
oniguruma-devel \
readline-devel \
libsodium-devel \
gmp-devel \
libffi-devel \
libicu-devel \
bzip2-devel \
libxslt-devel \
boost-devel
# 安装毕昇编译器(鲲鹏专属,比GCC更优化)
# openEuler源里直接有
sudo dnf install -y bisheng-compiler
# 验证
clang --version # 毕昇基于LLVM/Clang
Ubuntu 20.04/22.04 aarch64(华为云鲲鹏ECS常用)
sudo apt update && sudo apt upgrade -y
sudo apt install -y \
build-essential \
gcc \
g++ \
make \
autoconf \
bison \
re2c \
pkg-config \
numactl \
libnuma-dev \
libjemalloc-dev \
libxml2-dev \
libssl-dev \
libcurl4-openssl-dev \
libpng-dev \
libjpeg-dev \
libwebp-dev \
libfreetype-dev \
libzip-dev \
zlib1g-dev \
libsqlite3-dev \
libonig-dev \
libreadline-dev \
libsodium-dev \
libgmp-dev \
libffi-dev \
libicu-dev \
libbz2-dev \
libxslt-dev \
libboost-context-dev
---
四、安装毕昇编译器(鲲鹏专属加速)
毕昇编译器是华为专门为鲲鹏优化的LLVM编译器。用它编译PHP解释器本身,能让PHP在鲲鹏上跑得更快(因为PHP解释器是C写的,用更
懂鲲鹏流水线的编译器编译,生成的机器码质量更高)。
# openEuler系统直接安装
sudo dnf install -y bisheng-compiler
# 非openEuler系统,从华为鲲鹏社区下载
# https://www.hikunpeng.com/developer/devkit/compilation
# 下载后解压安装
tar -xzf bisheng-compiler-*.tar.gz -C /usr/local/
export PATH=/usr/local/bisheng-compiler/bin:$PATH
# 验证毕昇编译器
clang --version
# 输出类似:BiSheng Compiler version 4.x.x ...
# 设置使用毕昇编译器编译PHP
export CC=clang
export CXX=clang++
# 鲲鹏专属优化标志
export CFLAGS="-O3 -mcpu=tsv110 -march=armv8.2-a+simd+crypto -fstack-protector-strong"
export CXXFLAGS="$CFLAGS"
为什么 -mcpu=tsv110? tsv110 是鲲鹏920的微架构代号(TaiShan
V110),告诉编译器"我就是在鲲鹏上跑的,你按鲲鹏的流水线特性来优化",比通用的 -march=armv8-a 更精准。
---
五、下载PHP源码并编译
5.1 下载源码
mkdir -p /opt/php-build
cd /opt/php-build
PHP_VERSION="8.3.10"
wget "https://www.php.net/distributions/php-${PHP_VERSION}.tar.gz"
tar -xzf "php-${PHP_VERSION}.tar.gz"
cd "php-${PHP_VERSION}"
5.2 鲲鹏专属编译配置
# 方案A:使用毕昇编译器(推荐,性能最优)
export CC=clang
export CXX=clang++
export CFLAGS="-O3 -mcpu=tsv110 -march=armv8.2-a+simd+crypto -fstack-protector-strong -fPIC"
export CXXFLAGS="$CFLAGS"
export LDFLAGS="-Wl,-O2 -Wl,--as-needed"
# 方案B:使用GCC(备选)
# export CC=gcc
# export CXX=g++
# export CFLAGS="-O2 -march=armv8.2-a -mtune=tsv110 -fstack-protector-strong"
./configure \
--prefix=/usr/local/php \
--with-config-file-path=/usr/local/php/etc \
--with-config-file-scan-dir=/usr/local/php/etc/php.d \
--with-libdir=lib64 \
--enable-fpm \
--with-fpm-user=www \
--with-fpm-group=www \
--enable-opcache \
--enable-mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-sqlite \
--with-openssl \
--with-curl \
--with-zlib \
--enable-mbstring \
--enable-bcmath \
--enable-gd \
--with-jpeg \
--with-png \
--with-webp \
--with-freetype \
--with-zip \
--enable-soap \
--enable-xml \
--enable-json \
--enable-ctype \
--enable-tokenizer \
--enable-fileinfo \
--enable-dom \
--enable-simplexml \
--enable-xmlreader \
--enable-xmlwriter \
--enable-phar \
--enable-filter \
--enable-session \
--with-readline \
--enable-sockets \
--enable-pcntl \
--enable-posix \
--with-sodium \
--with-gmp \
--enable-intl \
--enable-calendar \
--with-bz2 \
--with-xsl \
2>&1 | tee /opt/php-build/configure.log
echo "configure退出码: $?"
5.3 编译安装
CORES=$(nproc)
echo "鲲鹏CPU核心数: ${CORES},开始并行编译..."
make -j${CORES} 2>&1 | tee /opt/php-build/make.log
# 检查是否有错误
if grep -qE "^make.*Error" /opt/php-build/make.log; then
echo "编译失败,查看日志: /opt/php-build/make.log"
exit 1
fi
sudo make install
# 配置环境变量
echo 'export PATH=/usr/local/php/bin:/usr/local/php/sbin:$PATH' | sudo tee -a /etc/profile
source /etc/profile
# 验证
php -v
# 期望:PHP 8.3.10 (cli) ...
---
六、PHP核心配置(鲲鹏ARM64优化版)
# 复制生产配置
cp /opt/php-build/php-8.3.10/php.ini-production /usr/local/php/etc/php.ini
mkdir -p /usr/local/php/etc/php.d /var/log/php /tmp/php-opcache
cat > /usr/local/php/etc/php.d/kunpeng-optimize.ini << 'EOF'
; ================================================
; 鲲鹏920 ARM64 PHP性能优化配置
; ================================================
; ===== OPcache 基础配置 =====
opcache.enable=1
opcache.enable_cli=1
; 鲲鹏高内存服务器,给OPcache分配512MB
opcache.memory_consumption=512
; 字符串缓冲区(减少重复字符串内存占用)
opcache.interned_strings_buffer=64
; 最多缓存文件数(含vendor,Laravel约8000个)
opcache.max_accelerated_files=30000
; 生产环境关闭文件变动检查(手动清缓存)
opcache.validate_timestamps=0
opcache.revalidate_freq=0
; 保留注释(框架注解依赖)
opcache.save_comments=1
; 快速关闭
opcache.fast_shutdown=1
; ===== JIT配置(鲲鹏ARM64原生支持)=====
; tracing模式:追踪热点代码路径,最彻底的优化
; 等价于数字1255:C=1 R=2 T=5 O=5
opcache.jit=tracing
; JIT缓冲区256MB(鲲鹏高内存服务器可以给够)
opcache.jit_buffer_size=256M
; ===== 大页(Huge Pages)优化 =====
; 降低TLB缺失率,鲲鹏多核场景效果明显
opcache.huge_code_pages=1
; ===== 文件缓存(重启后不用重新预热)=====
opcache.file_cache=/tmp/php-opcache
opcache.file_cache_consistency_checks=0
; ===== 预加载(PHP 7.4+)=====
; 框架核心文件启动时预编译进内存
; opcache.preload=/var/www/html/preload.php
; opcache.preload_user=www
; ===== 基础性能配置 =====
memory_limit=1G
max_execution_time=60
upload_max_filesize=256M
post_max_size=256M
; 路径缓存(减少stat系统调用)
realpath_cache_size=8192K
realpath_cache_ttl=600
; ===== 错误日志 =====
display_errors=Off
log_errors=On
error_log=/var/log/php/error.log
error_reporting=E_ALL & ~E_DEPRECATED & ~E_STRICT
; ===== 时区 =====
date.timezone=Asia/Shanghai
EOF
---
七、jemalloc内存优化(鲲鹏高并发必做)
大白话解释: Linux默认的内存分配器ptmalloc在多线程高并发下有锁竞争问题,就像一个收银台排长队。jemalloc给每个线程/CPU独
立的内存池,各自结账,互不干扰,高并发下快很多。
# 安装jemalloc
sudo dnf install -y jemalloc jemalloc-devel # openEuler
# 或
sudo apt install -y libjemalloc2 libjemalloc-dev # Ubuntu
# 找到jemalloc的so文件路径
find /usr -name "libjemalloc.so*" 2>/dev/null
# 通常是 /usr/lib64/libjemalloc.so.2 或 /usr/lib/aarch64-linux-gnu/libjemalloc.so.2
# 验证jemalloc可用
LD_PRELOAD=/usr/lib64/libjemalloc.so.2 php -r "echo 'jemalloc OK';"
7.1 PHP-FPM使用jemalloc
# 修改PHP-FPM的systemd服务,注入jemalloc
cat > /etc/systemd/system/php-fpm.service << 'EOF'
[Unit]
Description=PHP FastCGI Process Manager (Kunpeng Optimized)
After=network.target
[Service]
Type=forking
PIDFile=/var/run/php-fpm.pid
# 鲲鹏NUMA绑核 + jemalloc内存优化
# 根据实际numactl --hardware输出调整节点编号
Environment="LD_PRELOAD=/usr/lib64/libjemalloc.so.2"
# jemalloc调优参数:
# narenas=8 → 8个内存arena(鲲鹏多核,减少锁竞争)
# lg_tcache_max=16 → 线程缓存最大对象64KB
# background_thread:true → 后台线程异步回收内存
Environment="MALLOC_CONF=narenas:8,lg_tcache_max:16,background_thread:true"
ExecStart=/usr/bin/numactl --cpunodebind=0,1 --membind=0,1 \
/usr/local/php/sbin/php-fpm \
--fpm-config /usr/local/php/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
PrivateTmp=true
LimitNOFILE=1000000
LimitNPROC=65535
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
---
八、PHP-FPM进程池配置(鲲鹏多核优化)
# 创建www用户
groupadd www 2>/dev/null
useradd -g www -s /sbin/nologin -M www 2>/dev/null
# 复制配置文件
cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf
mkdir -p /var/run/php-fpm
cat > /usr/local/php/etc/php-fpm.d/www.conf << 'EOF'
[www]
user = www
group = www
; Unix socket(比TCP快,减少网络栈开销)
listen = /var/run/php-fpm/www.sock
listen.owner = www
listen.group = www
listen.mode = 0660
; 动态进程管理(适应鲲鹏高核心数)
pm = dynamic
; 进程数计算:
; 鲲鹏920单路64核,绑2个NUMA节点(32核)
; 每个PHP-FPM进程约60-100MB内存
; 绑定节点可用内存约128GB
; max_children = 128GB / 80MB ≈ 1600(取保守值)
pm.max_children = 512
; 启动时进程数(max_children的1/8)
pm.start_servers = 64
; 最少空闲进程
pm.min_spare_servers = 32
; 最多空闲进程
pm.max_spare_servers = 128
; 每个进程处理2000个请求后重启(防内存泄漏)
pm.max_requests = 2000
; 慢日志(超过3秒记录)
request_slowlog_timeout = 3s
slowlog = /var/log/php/www-slow.log
; FPM状态页(监控用)
pm.status_path = /fpm-status
; 进程空闲超时
pm.process_idle_timeout = 60s
; 环境变量传递
env[PATH] = /usr/local/php/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
; 资源限制
php_admin_value[memory_limit] = 1G
php_admin_value[open_basedir] = /var/www/html:/tmp:/usr/local/php
EOF
---
九、系统内核调优(openEuler/鲲鹏专项)
cat > /etc/sysctl.d/99-kunpeng-php.conf << 'EOF'
# ================================================
# 鲲鹏920 PHP高并发内核参数优化
# ================================================
# ===== 网络优化 =====
# TCP连接队列(高并发必须加大)
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# TCP缓冲区(鲲鹏内存带宽大,可以给大)
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
# 开启TCP快速回收(高并发短连接场景)
net.ipv4.tcp_tw_reuse = 1
# TIME_WAIT最大数量
net.ipv4.tcp_max_tw_buckets = 262144
# 本地端口范围
net.ipv4.ip_local_port_range = 1024 65535
# TCP keepalive(及时清理死连接)
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
# 网络设备队列长度
net.core.netdev_max_backlog = 262144
# ===== 内存优化 =====
# 减少swap使用(鲲鹏内存大,尽量不用swap)
vm.swappiness = 10
# 脏页比例(平衡性能和稳定性)
vm.dirty_ratio = 20
vm.dirty_background_ratio = 5
# 大页支持(配合opcache.huge_code_pages)
vm.nr_hugepages = 1024
# ===== 文件系统 =====
# 最大文件描述符数
fs.file-max = 2000000
# inotify监控文件数
fs.inotify.max_user_watches = 524288
# ===== 进程 =====
# 最大进程数
kernel.pid_max = 4194304
EOF
# 立即生效
sysctl -p /etc/sysctl.d/99-kunpeng-php.conf
# 设置系统文件描述符限制
cat >> /etc/security/limits.conf << 'EOF'
www soft nofile 1000000
www hard nofile 1000000
root soft nofile 1000000
root hard nofile 1000000
* soft nproc 65535
* hard nproc 65535
EOF
---
十、协程框架适配:Swoole
10.1 Swoole编译安装(鲲鹏ARM64)
cd /opt/php-build
# Swoole 5.x 原生支持aarch64协程上下文(Boost.Context汇编实现)
# 比ucontext快10倍以上
wget https://github.com/swoole/swoole-src/archive/refs/tags/v5.1.3.tar.gz \
-O swoole-5.1.3.tar.gz
tar -xzf swoole-5.1.3.tar.gz
cd swoole-src-5.1.3
/usr/local/php/bin/phpize
# 鲲鹏ARM64优化编译
CFLAGS="-O3 -mcpu=tsv110 -march=armv8.2-a+simd" \
./configure \
--with-php-config=/usr/local/php/bin/php-config \
--enable-swoole-curl \
--enable-openssl \
--with-openssl-dir=/usr \
--enable-cares \
--enable-swoole-pgsql \
--enable-brotli
make -j$(nproc)
sudo make install
echo "extension=swoole.so" > /usr/local/php/etc/php.d/swoole.ini
# 验证协程上下文实现(鲲鹏上应该是boost asm context)
php --ri swoole | grep -E "context|coroutine|version"
# 期望看到:boost.context ← 这是最快的协程切换实现
为什么Boost.Context比ucontext快? 协程切换就是保存/恢复CPU寄存器状态。Boost.Context用汇编直接操作寄存器,只保存必要的
几个;ucontext是系统调用,要保存全部信号掩码等额外状态,慢10倍以上。
10.2 Swoole HTTP服务器(完整示例)
<?php
// /var/www/html/swoole_server.php
// 鲲鹏ARM64高性能Swoole HTTP服务器
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\Coroutine;
use Swoole\Coroutine\MySQL;
use Swoole\Coroutine\Redis;
// 鲲鹏CPU核心数(自动获取)
$cpuCores = swoole_cpu_num();
$server = new Server('0.0.0.0', 9501, SWOOLE_PROCESS);
$server->set([
// ===== 进程配置 =====
// worker进程数 = CPU核心数(鲲鹏64核就设64)
'worker_num' => $cpuCores,
// task进程数(处理异步任务,如发邮件、写日志)
'task_worker_num' => $cpuCores / 2,
// 每个worker处理10万请求后重启(防内存泄漏)
'max_request' => 100000,
// task进程同上
'max_request_task' => 10000,
// ===== 协程配置 =====
// 开启协程(核心功能)
'enable_coroutine' => true,
// 每个worker最大协程数(鲲鹏内存大,可以给多)
'max_coroutine' => 100000,
// 协程栈大小(默认8KB,复杂业务可加大)
'stack_size' => 8192,
// ===== 网络配置 =====
// 最大连接数
'max_conn' => 100000,
// 监听队列长度
'backlog' => 65535,
// 开启HTTP2
'open_http2_protocol' => true,
// 心跳检测(60秒无数据断开)
'heartbeat_check_interval' => 60,
'heartbeat_idle_time' => 120,
// ===== 缓冲区配置 =====
'socket_buffer_size' => 8 * 1024 * 1024, // 8MB
'buffer_output_size' => 4 * 1024 * 1024, // 4MB
// ===== 日志配置 =====
'log_file' => '/var/log/php/swoole.log',
'log_level' => SWOOLE_LOG_WARNING,
// ===== 钩子标志(一键协程化)=====
// 把PHP原生阻塞IO全部变成协程非阻塞
'hook_flags' => SWOOLE_HOOK_ALL,
]);
// ===== 启动事件 =====
$server->on('start', function (Server $server) use ($cpuCores) {
echo "鲲鹏ARM64 Swoole服务器启动\n";
echo "监听: http://0.0.0.0:9501\n";
echo "Worker进程数: {$cpuCores}\n";
echo "协程上下文: " . (extension_loaded('swoole') ? swoole_version() : 'N/A') . "\n";
// 设置进程名(方便ps查看)
swoole_set_process_name('swoole-master');
});
// ===== Worker启动事件 =====
$server->on('workerStart', function (Server $server, int $workerId) {
// 每个Worker进程初始化连接池
// 注意:连接池必须在workerStart里创建,不能在外面
// MySQL连接池(协程版)
\Swoole\Coroutine\run(function () {
// 这里可以预热连接池
});
swoole_set_process_name("swoole-worker-{$workerId}");
});
// ===== 请求处理 =====
$server->on('request', function (Request $request, Response $response) {
// 设置响应头
$response->header('Content-Type', 'application/json; charset=utf-8');
$response->header('X-Server', 'Kunpeng-ARM64');
$path = $request->server['request_uri'] ?? '/';
switch ($path) {
case '/':
// 简单响应
$response->end(json_encode([
'status' => 'ok',
'server' => 'Kunpeng ARM64 Swoole',
'php' => PHP_VERSION,
'swoole' => SWOOLE_VERSION,
'arch' => php_uname('m'),
'workers' => swoole_cpu_num(),
]));
break;
✻ Baked for 4m 12s
> 继续
✢ Smooshing… ●S继续上面的内容,从 Swoole HTTP服务器请求处理的 switch 语句继续完整写完。
● Web Search("swoole coroutine MySQL connection pool PHP8 鲲鹏 高并发实战")
● Web Search("workerman webman 鲲鹏 aarch64 PHP高性能 协程 部署配置 2024")
●S好,继续完整写完剩余所有内容。
---
10.2 续:Swoole HTTP服务器完整示例
<?php // /var/www/html/swoole_server.php(续上文switch部分)
case '/api/db':
// 协程MySQL查询示例
// SWOOLE_HOOK_ALL已开启,PDO自动变成协程非阻塞
Coroutine::create(function () use ($response) {
try {
$pdo = new PDO(
'mysql:host=127.0.0.1;port=3306;dbname=test;charset=utf8mb4',
'root',
'password',
[PDO::ATTR_TIMEOUT => 3]
);
$stmt = $pdo->query('SELECT NOW() as time, VERSION() as version');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$response->end(json_encode(['db' => $row]));
} catch (\Throwable $e) {
$response->status(500);
$response->end(json_encode(['error' => $e->getMessage()]));
}
});
break;
case '/api/concurrent':
// 协程并发请求示例(同时发起多个IO,等全部完成)
Coroutine::create(function () use ($response) {
// 并发执行3个任务,总耗时 = 最慢那个,而不是三个相加
$results = [];
$wg = new Coroutine\WaitGroup();
// 任务1:查Redis
$wg->add();
Coroutine::create(function () use (&$results, $wg) {
$redis = new Coroutine\Redis();
$redis->connect('127.0.0.1', 6379);
$results['redis'] = $redis->get('test_key') ?: 'empty';
$wg->done();
});
// 任务2:查MySQL
$wg->add();
Coroutine::create(function () use (&$results, $wg) {
$mysql = new Coroutine\MySQL();
$mysql->connect([
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'password' => 'password',
'database' => 'test',
]);
$results['mysql'] = $mysql->query('SELECT 1+1 as val');
$wg->done();
});
// 任务3:HTTP请求(协程非阻塞)
$wg->add();
Coroutine::create(function () use (&$results, $wg) {
$client = new Coroutine\Http\Client('httpbin.org', 80);
$client->get('/get');
$results['http_status'] = $client->statusCode;
$wg->done();
});
// 等待全部完成(协程挂起,不阻塞其他请求)
$wg->wait(3.0); // 最多等3秒
$response->end(json_encode([
'concurrent_results' => $results,
'note' => '三个IO并发执行,总耗时=最慢那个',
]));
});
break;
default:
$response->status(404);
$response->end(json_encode(['error' => 'Not Found']));
}
});
// ===== Task处理(异步任务,不阻塞主请求)=====
$server->on('task', function (Server $server, int $taskId, int $srcWorkerId, $data) {
// 处理耗时任务:发邮件、写日志、推送消息等
switch ($data['type'] ?? '') {
case 'send_email':
// 发邮件逻辑(不阻塞HTTP响应)
mail($data['to'], $data['subject'], $data['body']);
break;
case 'write_log':
file_put_contents('/var/log/php/app.log', $data['content'] . "\n", FILE_APPEND);
break;
}
return ['task_id' => $taskId, 'status' => 'done'];
});
$server->on('finish', function (Server $server, int $taskId, $data) {
// task完成回调(可选)
});
$server->start();
10.3 Swoole连接池(鲲鹏高并发核心)
大白话: 传统PHP每次请求都新建MySQL连接,就像每次打电话都要重新拨号。连接池是提前建好一批连接放着,请求来了直接拿,用
完还回去,省去了握手时间。
<?php
// /var/www/html/Pool/MySQLPool.php
// 基于Swoole Channel实现的MySQL连接池
namespace App\Pool;
use Swoole\Coroutine\MySQL;
use Swoole\Coroutine\Channel;
class MySQLPool
{
private Channel $pool;
private array $config;
private int $size;
public function __construct(array $config, int $size = 32)
{
$this->config = $config;
$this->size = $size;
// Channel就是协程安全的队列,容量=连接池大小
$this->pool = new Channel($size);
}
// 初始化连接池(在workerStart里调用)
public function init(): void
{
for ($i = 0; $i < $this->size; $i++) {
$conn = $this->createConnection();
if ($conn) {
$this->pool->push($conn);
}
}
}
// 从池里取一个连接(协程挂起等待,不阻塞)
public function get(float $timeout = 3.0): ?MySQL
{
// pop会协程挂起,直到有连接可用或超时
$conn = $this->pool->pop($timeout);
if ($conn === false) {
// 超时,连接池耗尽
throw new \RuntimeException('连接池已满,获取连接超时');
}
// 检查连接是否还活着
if (!$conn->connected) {
$conn = $this->createConnection();
}
return $conn;
}
// 用完归还连接
public function put(MySQL $conn): void
{
if ($conn->connected) {
$this->pool->push($conn);
} else {
// 连接断了,补充一个新的
$newConn = $this->createConnection();
if ($newConn) {
$this->pool->push($newConn);
}
}
}
// 创建一个新连接
private function createConnection(): ?MySQL
{
$conn = new MySQL();
$result = $conn->connect($this->config);
if (!$result) {
error_log("MySQL连接失败: " . $conn->connect_error);
return null;
}
return $conn;
}
// 获取当前池中可用连接数
public function available(): int
{
return $this->pool->length();
}
}
<?php
// /var/www/html/Pool/RedisPool.php
// Redis连接池
namespace App\Pool;
use Swoole\Coroutine\Redis;
use Swoole\Coroutine\Channel;
class RedisPool
{
private Channel $pool;
private array $config;
public function __construct(array $config, int $size = 64)
{
$this->config = $config;
$this->pool = new Channel($size);
}
public function init(): void
{
$size = $this->pool->capacity;
for ($i = 0; $i < $size; $i++) {
$conn = new Redis();
$conn->connect($this->config['host'], $this->config['port']);
if (!empty($this->config['password'])) {
$conn->auth($this->config['password']);
}
if (!empty($this->config['db'])) {
$conn->select($this->config['db']);
}
$this->pool->push($conn);
}
}
public function get(float $timeout = 3.0): Redis
{
$conn = $this->pool->pop($timeout);
if ($conn === false) {
throw new \RuntimeException('Redis连接池耗尽');
}
return $conn;
}
public function put(Redis $conn): void
{
$this->pool->push($conn);
}
}
<?php
// /var/www/html/swoole_server_with_pool.php
// 带连接池的完整Swoole服务器(鲲鹏生产级)
require_once __DIR__ . '/vendor/autoload.php';
use App\Pool\MySQLPool;
use App\Pool\RedisPool;
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
$server = new Server('0.0.0.0', 9501, SWOOLE_PROCESS);
$server->set([
'worker_num' => swoole_cpu_num(),
'task_worker_num' => 4,
'enable_coroutine' => true,
'max_coroutine' => 100000,
'max_request' => 100000,
'hook_flags' => SWOOLE_HOOK_ALL,
'log_file' => '/var/log/php/swoole.log',
'log_level' => SWOOLE_LOG_WARNING,
]);
// 每个Worker进程独立的连接池(不跨进程共享)
$mysqlPool = null;
$redisPool = null;
$server->on('workerStart', function (Server $server, int $workerId) use (&$mysqlPool, &$redisPool) {
// 在协程环境里初始化连接池
\Swoole\Coroutine\run(function () use (&$mysqlPool, &$redisPool) {
// MySQL连接池:每个Worker 32个连接
$mysqlPool = new MySQLPool([
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'password' => 'your_password',
'database' => 'your_db',
'charset' => 'utf8mb4',
'timeout' => 3,
], 32);
$mysqlPool->init();
// Redis连接池:每个Worker 64个连接
$redisPool = new RedisPool([
'host' => '127.0.0.1',
'port' => 6379,
'password' => '',
], 64);
$redisPool->init();
echo "Worker #{$GLOBALS['workerId']} 连接池初始化完成\n";
});
});
$server->on('request', function (Request $request, Response $response)
use (&$mysqlPool, &$redisPool)
{
$response->header('Content-Type', 'application/json');
$path = $request->server['request_uri'] ?? '/';
if ($path === '/api/user') {
$userId = (int)($request->get['id'] ?? 1);
// 先查Redis缓存
$redis = $redisPool->get();
try {
$cached = $redis->get("user:{$userId}");
} finally {
// 无论成功失败都归还连接(finally保证执行)
$redisPool->put($redis);
}
if ($cached) {
$response->end($cached);
return;
}
// 缓存没有,查MySQL
$mysql = $mysqlPool->get();
try {
$stmt = $mysql->prepare('SELECT id, name, email FROM users WHERE id = ?');
$stmt->execute([$userId]);
$user = $stmt->fetchAll();
} finally {
$mysqlPool->put($mysql);
}
$json = json_encode(['user' => $user, 'from' => 'mysql']);
// 写入Redis缓存,过期时间300秒
$redis2 = $redisPool->get();
try {
$redis2->setex("user:{$userId}", 300, $json);
} finally {
$redisPool->put($redis2);
}
$response->end($json);
return;
}
$response->status(404);
$response->end(json_encode(['error' => 'not found']));
});
$server->start();
---
十一、协程框架适配:Workerman + Webman
Workerman是纯PHP实现的异步框架,不依赖任何C扩展,在鲲鹏ARM64上兼容性极好。Webman是基于Workerman的高性能Web框架,性能接
近Swoole。
11.1 安装Webman
# 创建项目目录
mkdir -p /var/www/webman
cd /var/www/webman
# 用Composer安装(需要先装Composer)
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
# 创建Webman项目
composer create-project workerman/webman .
# 安装Redis、数据库等扩展
composer require illuminate/database
composer require symfony/var-dumper
11.2 Webman配置(鲲鹏多核优化)
<?php
// /var/www/webman/config/server.php
// Webman服务器配置(鲲鹏ARM64优化版)
return [
// 监听地址
'listen' => 'http://0.0.0.0:8787',
// ===== 进程配置 =====
// worker进程数 = CPU核心数(鲲鹏64核就设64)
// Workerman是多进程模型,每个进程独立,充分利用多核
'count' => cpu_count(),
// 用户(安全原则)
'user' => 'www',
'group' => 'www',
// 守护进程模式(生产环境)
'daemonize' => false, // 由systemd管理,这里设false
// 标准输出重定向
'stdout_file' => '/var/log/php/webman_stdout.log',
// PID文件
'pid_file' => '/var/run/webman.pid',
// 状态文件
'status_file' => '/var/run/webman.status',
// 日志文件
'log_file' => '/var/log/php/workerman.log',
// 事件驱动(推荐libevent,比select快很多)
// 需要安装:pecl install event
'event_loop' => '', // 留空自动选择最优
// 停止超时
'stop_timeout' => 2,
// 最大包大小(上传文件等)
'max_package_size' => 10 * 1024 * 1024, // 10MB
];
<?php
// /var/www/webman/config/process.php
// 自定义进程配置(鲲鹏多核充分利用)
return [
// 主Web服务进程
'webman' => [
'handler' => support\App::class,
'listen' => 'http://0.0.0.0:8787',
'count' => cpu_count(),
'user' => 'www',
'group' => 'www',
'reusePort'=> true, // 端口复用,多进程共享端口,减少惊群效应
'context' => [],
],
// 定时任务进程(单独一个进程跑定时任务)
'monitor' => [
'handler' => process\Monitor::class,
'count' => 1,
'reloadable' => false,
],
// 队列消费进程(异步任务处理)
'queue' => [
'handler' => process\QueueConsumer::class,
'count' => 4, // 4个进程消费队列
'user' => 'www',
],
];
11.3 Webman控制器示例
<?php
// /var/www/webman/app/controller/ApiController.php
namespace app\controller;
use support\Request;
use support\Response;
use support\Redis;
use support\Db;
class ApiController
{
// GET /api/status
public function status(Request $request): Response
{
return json([
'status' => 'ok',
'server' => 'Kunpeng ARM64 Webman',
'php' => PHP_VERSION,
'arch' => php_uname('m'),
'workers' => cpu_count(),
'memory' => round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB',
]);
}
// GET /api/user?id=1
public function user(Request $request): Response
{
$id = (int)$request->get('id', 1);
// 查Redis缓存
$cacheKey = "user:{$id}";
$cached = Redis::get($cacheKey);
if ($cached) {
return json(json_decode($cached, true) + ['from' => 'cache']);
}
// 查数据库(Webman使用Laravel的Eloquent ORM)
$user = Db::table('users')->where('id', $id)->first();
if (!$user) {
return json(['error' => 'User not found'], 404);
}
$data = (array)$user;
// 写缓存
Redis::setex($cacheKey, 300, json_encode($data));
return json($data + ['from' => 'db']);
}
// POST /api/user
public function create(Request $request): Response
{
$data = $request->post();
// 简单验证
if (empty($data['name']) || empty($data['email'])) {
return json(['error' => '缺少必填字段'], 422);
}
$id = Db::table('users')->insertGetId([
'name' => $data['name'],
'email' => $data['email'],
'created_at' => date('Y-m-d H:i:s'),
]);
return json(['id' => $id, 'message' => '创建成功'], 201);
}
}
11.4 Webman systemd服务(NUMA绑核)
cat > /etc/systemd/system/webman.service << 'EOF'
[Unit]
Description=Webman PHP Framework (Kunpeng NUMA Optimized)
After=network.target mysql.service redis.service
[Service]
Type=forking
PIDFile=/var/run/webman.pid
User=root
# 鲲鹏NUMA绑核 + jemalloc内存优化
Environment="LD_PRELOAD=/usr/lib64/libjemalloc.so.2"
Environment="MALLOC_CONF=narenas:8,lg_tcache_max:16,background_thread:true"
# 绑定到NUMA node 0和1(同一socket内,内存访问最快)
ExecStart=/usr/bin/numactl --cpunodebind=0,1 --membind=0,1 \
/usr/local/php/bin/php /var/www/webman/start.php start -d
ExecStop=/usr/local/php/bin/php /var/www/webman/start.php stop
ExecReload=/usr/local/php/bin/php /var/www/webman/start.php reload
LimitNOFILE=1000000
LimitNPROC=65535
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable webman
systemctl start webman
---
十二、Nginx反向代理配置(鲲鹏多核优化)
# 编译Nginx(鲲鹏ARM64优化)
cd /opt
wget http://nginx.org/download/nginx-1.26.2.tar.gz
tar -xzf nginx-1.26.2.tar.gz
cd nginx-1.26.2
./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--with-http_realip_module \
--with-stream \
--with-stream_ssl_module \
--with-cc-opt="-O3 -mcpu=tsv110 -march=armv8.2-a" \
--with-ld-opt="-Wl,-rpath,/usr/local/lib"
make -j$(nproc) && sudo make install
# /usr/local/nginx/conf/nginx.conf(鲲鹏多核优化版)
user www;
# 鲲鹏64核,worker数设为核心数
worker_processes 64;
# 自动绑核(Nginx 1.9.10+)
worker_cpu_affinity auto;
# 每个worker最大文件描述符
worker_rlimit_nofile 1000000;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
# 每个worker最大连接数(鲲鹏内存大,可以给高)
worker_connections 65535;
use epoll;
multi_accept on;
# 接受互斥锁(高并发下关闭,减少延迟)
accept_mutex off;
}
http {
include mime.types;
default_type application/octet-stream;
# 日志格式(含响应时间,方便排查慢请求)
log_format main '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent $request_time '
'"$http_user_agent"';
access_log /var/log/nginx/access.log main buffer=64k flush=5s;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 10000;
# Gzip压缩
gzip on;
gzip_comp_level 4;
gzip_min_length 1024;
gzip_types text/plain text/css application/json
application/javascript text/xml application/xml;
# 上游:PHP-FPM(传统模式)
upstream php_fpm {
least_conn;
server unix:/var/run/php-fpm/www.sock;
keepalive 512;
}
# 上游:Swoole服务(协程模式)
upstream swoole_backend {
least_conn;
# 鲲鹏多核,可以跑多个Swoole实例
server 127.0.0.1:9501 weight=1;
server 127.0.0.1:9502 weight=1;
keepalive 1024;
}
# 上游:Webman服务
upstream webman_backend {
least_conn;
server 127.0.0.1:8787;
keepalive 512;
}
# ===== PHP-FPM站点 =====
server {
listen 80;
server_name fpm.example.com;
root /var/www/html;
index index.php;
location ~ \.php$ {
fastcgi_pass php_fpm;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 60;
fastcgi_buffer_size 128k;
fastcgi_buffers 8 128k;
}
# FPM状态监控
location = /fpm-status {
allow 127.0.0.1;
deny all;
fastcgi_pass php_fpm;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
include fastcgi_params;
}
}
# ===== Swoole站点 =====
server {
listen 80;
server_name swoole.example.com;
location / {
proxy_pass http://swoole_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
}
# ===== Webman站点 =====
server {
listen 80;
server_name webman.example.com;
location / {
proxy_pass http://webman_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
---
十三、性能压测与验证
13.1 安装压测工具
# wrk:高性能HTTP压测工具(比ab更准确)
sudo dnf install -y wrk # openEuler
# 或从源码编译
git clone https://github.com/wg/wrk.git
cd wrk && make -j$(nproc) && cp wrk /usr/local/bin/
# ab:Apache自带的压测工具
sudo dnf install -y httpd-tools
13.2 压测脚本
#!/bin/bash
# /usr/local/bin/kunpeng-benchmark.sh
# 鲲鹏PHP环境性能基准测试
echo "=============================================="
echo " 鲲鹏ARM64 PHP性能基准测试"
echo "=============================================="
TARGET_HOST="${1:-127.0.0.1}"
# 测试1:PHP-FPM(传统模式)
echo ""
echo "【测试1】PHP-FPM + Nginx(传统模式)"
echo "并发100,持续30秒..."
wrk -t8 -c100 -d30s --latency \
"http://${TARGET_HOST}/index.php" 2>&1 | tail -10
# 测试2:Swoole(协程模式)
echo ""
echo "【测试2】Swoole HTTP服务器(协程模式)"
echo "并发1000,持续30秒..."
wrk -t16 -c1000 -d30s --latency \
"http://${TARGET_HOST}:9501/" 2>&1 | tail -10
# 测试3:Webman
echo ""
echo "【测试3】Webman(多进程模式)"
echo "并发500,持续30秒..."
wrk -t8 -c500 -d30s --latency \
"http://${TARGET_HOST}:8787/api/status" 2>&1 | tail -10
echo ""
echo "=============================================="
echo " 测试完成"
echo "=============================================="
13.3 PHP内置性能验证脚本
<?php
// /usr/local/bin/kunpeng-php-check.php
// 鲲鹏PHP环境完整检查
declare(strict_types=1);
$line = str_repeat('=', 54);
echo "{$line}\n";
echo " 鲲鹏ARM64 PHP运行环境检查报告\n";
echo "{$line}\n";
// 1. 硬件信息
echo "\n【1】硬件环境\n";
echo " CPU架构 : " . php_uname('m') . "\n";
echo " CPU核心 : " . (int)shell_exec('nproc') . " 个\n";
$cpuModel = trim(shell_exec("grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2") ?: '未知');
echo " CPU型号 : {$cpuModel}\n";
$memTotal = trim(shell_exec("grep MemTotal /proc/meminfo | awk '{print $2}'") ?: '0');
echo " 物理内存 : " . round((int)$memTotal / 1024 / 1024, 1) . " GB\n";
// 2. NUMA信息
echo "\n【2】NUMA拓扑\n";
$numaOutput = shell_exec('numactl --hardware 2>/dev/null');
if ($numaOutput) {
preg_match('/available: (\d+) nodes/', $numaOutput, $m);
echo " NUMA节点数: " . ($m[1] ?? '未知') . "\n";
// 显示各节点内存
preg_match_all('/node (\d+) size: (\d+) MB/', $numaOutput, $nodes);
foreach ($nodes[1] as $i => $nodeId) {
echo " Node {$nodeId}: " . round((int)$nodes[2][$i] / 1024, 1) . " GB\n";
}
} else {
echo " numactl未安装\n";
}
// 3. PHP版本
echo "\n【3】PHP环境\n";
echo " PHP版本 : " . PHP_VERSION . "\n
<?php
// 续上文 kunpeng-php-check.php
// 3. PHP版本(续)
echo " PHP版本 : " . PHP_VERSION . "\n";
echo " PHP路径 : " . PHP_BINARY . "\n";
echo " PHP位数 : " . (PHP_INT_SIZE * 8) . " bit\n";
// 4. OPcache和JIT
echo "\n【4】OPcache / JIT 状态\n";
if (!extension_loaded('opcache')) {
echo " OPcache : 未启用(请检查编译参数)\n";
} else {
$status = opcache_get_status(false);
echo " OPcache : 已启用\n";
echo " 内存使用 : " . round($status['memory_usage']['used_memory'] / 1024 / 1024, 2) . " MB\n";
echo " 内存空闲 : " . round($status['memory_usage']['free_memory'] / 1024 / 1024, 2) . " MB\n";
echo " 缓存文件 : " . $status['opcache_statistics']['num_cached_scripts'] . " 个\n";
echo " 命中率 : " . round($status['opcache_statistics']['opcache_hit_rate'], 2) . "%\n";
// JIT状态
$jit = $status['jit'] ?? null;
if ($jit) {
$jitKinds = [0 => '禁用', 1 => 'Function JIT', 2 => 'Tracing JIT'];
$kindName = $jitKinds[$jit['kind']] ?? '未知';
echo " JIT状态 : " . ($jit['enabled'] ? "已启用 ({$kindName})" : '未启用') . "\n";
echo " JIT缓冲 : " . round(($jit['buffer_size'] ?? 0) / 1024 / 1024, 0) . " MB\n";
} else {
echo " JIT状态 : 不可用(PHP版本或配置问题)\n";
}
}
// 5. 内存分配器检测
echo "\n【5】内存分配器\n";
$mallocLib = trim(shell_exec('cat /proc/' . getmypid() . '/maps | grep -E "jemalloc|tcmalloc" | head -1') ?: '');
if (strpos($mallocLib, 'jemalloc') !== false) {
echo " 分配器 : jemalloc(已优化)\n";
} elseif (strpos($mallocLib, 'tcmalloc') !== false) {
echo " 分配器 : tcmalloc(已优化)\n";
} else {
echo " 分配器 : ptmalloc(默认,建议换jemalloc)\n";
}
// 6. 扩展检查
echo "\n【6】关键扩展\n";
$extensions = [
'opcache' => 'OPcache字节码缓存',
'swoole' => 'Swoole协程框架',
'redis' => 'Redis客户端',
'pdo_mysql' => 'MySQL PDO驱动',
'pdo_pgsql' => 'PostgreSQL PDO驱动',
'gd' => 'GD图像处理',
'mbstring' => '多字节字符串',
'curl' => 'cURL HTTP客户端',
'zip' => 'ZIP压缩',
'sodium' => 'Sodium加密',
'intl' => '国际化',
'bcmath' => '高精度数学',
];
foreach ($extensions as $ext => $desc) {
$loaded = extension_loaded($ext);
$mark = $loaded ? '✓' : '✗';
$ver = $loaded && function_exists('phpversion') ? (phpversion($ext) ?: '') : '';
printf(" %s %-12s: %s %s\n", $mark, $ext, $desc, $ver ? "({$ver})" : '');
}
// 7. Swoole详情
if (extension_loaded('swoole')) {
echo "\n【7】Swoole详情\n";
$swooleInfo = [];
ob_start();
phpinfo(INFO_MODULES);
$phpinfoStr = ob_get_clean();
// 提取协程上下文实现
if (preg_match('/coroutine context.*?=>\s*(.+)/i', $phpinfoStr, $m)) {
echo " 协程上下文: " . trim($m[1]) . "\n";
}
echo " Swoole版本: " . SWOOLE_VERSION . "\n";
echo " CPU核心数 : " . swoole_cpu_num() . "\n";
// 检查是否是boost asm context(最快的协程切换)
$riOutput = shell_exec('/usr/local/php/bin/php --ri swoole 2>/dev/null');
if ($riOutput && preg_match('/boost\.context\s*=>\s*(\w+)/i', $riOutput, $m)) {
$boostCtx = strtolower($m[1]) === 'enabled' ? '已启用(最优)' : '未启用';
echo " Boost.Context: {$boostCtx}\n";
}
}
// 8. 性能基准测试
echo "\n【8】PHP性能基准\n";
// 测试1:整数运算(受益于JIT)
$start = hrtime(true);
$sum = 0;
for ($i = 0; $i < 10_000_000; $i++) {
$sum += $i;
}
$t1 = round((hrtime(true) - $start) / 1_000_000, 2);
echo " 1000万次整数累加 : {$t1} ms\n";
// 测试2:浮点运算(ARM SIMD加速)
$start = hrtime(true);
$val = 1.0;
for ($i = 0; $i < 1_000_000; $i++) {
$val = sqrt($val + $i) * M_PI;
}
$t2 = round((hrtime(true) - $start) / 1_000_000, 2);
echo " 100万次浮点sqrt : {$t2} ms\n";
// 测试3:字符串操作
$start = hrtime(true);
$str = '';
for ($i = 0; $i < 50_000; $i++) {
$str .= "Kunpeng ARM64 PHP {$i} ";
}
$t3 = round((hrtime(true) - $start) / 1_000_000, 2);
echo " 5万次字符串拼接 : {$t3} ms\n";
// 测试4:数组排序
$start = hrtime(true);
$arr = range(1, 100_000);
shuffle($arr);
sort($arr);
$t4 = round((hrtime(true) - $start) / 1_000_000, 2);
echo " 10万元素数组排序 : {$t4} ms\n";
// 测试5:JSON编解码
$start = hrtime(true);
$data = array_fill(0, 1000, ['id' => 1, 'name' => 'test', 'value' => 3.14]);
for ($i = 0; $i < 1000; $i++) {
json_decode(json_encode($data), true);
}
$t5 = round((hrtime(true) - $start) / 1_000_000, 2);
echo " 1000次JSON编解码 : {$t5} ms\n";
// 9. 服务状态
echo "\n【9】服务状态\n";
$services = ['php-fpm', 'nginx', 'webman', 'redis', 'mysql'];
foreach ($services as $svc) {
$active = trim(shell_exec("systemctl is-active {$svc} 2>/dev/null") ?: 'unknown');
$mark = $active === 'active' ? '✓' : '✗';
printf(" %s %-10s: %s\n", $mark, $svc, $active);
}
// 10. 大页状态
echo "\n【10】系统大页(Huge Pages)\n";
$hugeTotal = (int)trim(shell_exec("grep HugePages_Total /proc/meminfo | awk '{print \$2}'") ?: '0');
$hugeFree = (int)trim(shell_exec("grep HugePages_Free /proc/meminfo | awk '{print \$2}'") ?: '0');
$hugeSize = (int)trim(shell_exec("grep Hugepagesize /proc/meminfo | awk '{print \$2}'") ?: '2048');
echo " 大页总数 : {$hugeTotal} 页(" . round($hugeTotal * $hugeSize / 1024, 0) . " MB)\n";
echo " 空闲大页 : {$hugeFree} 页\n";
if ($hugeTotal === 0) {
echo " 建议 : echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages\n";
}
echo "\n{$line}\n";
echo " 检查完成\n";
echo "{$line}\n";
---
十四、OPcache预加载脚本
<?php
// /var/www/html/preload.php
// PHP-FPM/Swoole启动时预编译框架核心文件进内存
// 效果:消除冷启动延迟,首次请求响应时间从200ms降到20ms
declare(strict_types=1);
// 要预加载的目录列表(按实际框架调整)
$preloadDirs = array_filter([
// Laravel框架核心
__DIR__ . '/vendor/laravel/framework/src/Illuminate/Support',
__DIR__ . '/vendor/laravel/framework/src/Illuminate/Http',
__DIR__ . '/vendor/laravel/framework/src/Illuminate/Routing',
__DIR__ . '/vendor/laravel/framework/src/Illuminate/Container',
__DIR__ . '/vendor/laravel/framework/src/Illuminate/Database',
__DIR__ . '/vendor/laravel/framework/src/Illuminate/Cache',
// Symfony组件(Laravel依赖)
__DIR__ . '/vendor/symfony/http-foundation/src',
__DIR__ . '/vendor/symfony/routing/src',
// ThinkPHP核心(如果用ThinkPHP)
// __DIR__ . '/vendor/topthink/framework/src',
// Webman核心
// __DIR__ . '/vendor/workerman/webman-framework/src',
], 'is_dir');
$compiled = 0;
$failed = 0;
foreach ($preloadDirs as $dir) {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
if ($file->getExtension() !== 'php') {
continue;
}
$path = $file->getPathname();
// 跳过测试文件(节省内存,测试代码不需要预加载)
if (preg_match('#/(test|tests|Test|Tests|spec|Spec)/#', $path)) {
continue;
}
// 跳过命令行工具文件
if (preg_match('#/(console|Console|command|Command)/#', $path)) {
continue;
}
if (opcache_compile_file($path)) {
$compiled++;
} else {
$failed++;
error_log("预加载失败: {$path}");
}
}
}
error_log("OPcache预加载完成:成功 {$compiled} 个,失败 {$failed} 个");
; 在 kunpeng-optimize.ini 中启用预加载
opcache.preload=/var/www/html/preload.php
opcache.preload_user=www
---
十五、完整一键部署脚本
#!/bin/bash
# /opt/deploy_php_kunpeng.sh
# 鲲鹏ARM64 PHP 8.3 完整一键部署脚本
# 包含:编译PHP、配置OPcache/JIT、jemalloc、NUMA绑核、systemd服务
# 使用:chmod +x deploy_php_kunpeng.sh && sudo bash deploy_php_kunpeng.sh
set -euo pipefail
# ===== 配置变量 =====
PHP_VERSION="8.3.10"
INSTALL_DIR="/usr/local/php"
BUILD_DIR="/opt/php-build"
PHP_USER="www"
CORES=$(nproc)
ARCH=$(uname -m)
# NUMA节点绑定(根据 numactl --hardware 输出调整)
NUMA_NODES="0,1"
# jemalloc路径(安装后确认)
JEMALLOC_SO=""
for path in /usr/lib64/libjemalloc.so.2 \
/usr/lib/aarch64-linux-gnu/libjemalloc.so.2 \
/usr/local/lib/libjemalloc.so.2; do
[ -f "$path" ] && JEMALLOC_SO="$path" && break
done
# 颜色
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERRO]${NC} $1"; exit 1; }
# ===== 前置检查 =====
info "架构: ${ARCH},核心数: ${CORES}"
[ "$ARCH" != "aarch64" ] && warn "非aarch64架构,部分优化参数可能不适用"
# ===== 安装依赖 =====
info "安装编译依赖..."
if command -v dnf &>/dev/null; then
dnf install -y gcc gcc-c++ make autoconf bison re2c pkg-config \
numactl numactl-devel jemalloc jemalloc-devel \
libxml2-devel openssl-devel libcurl-devel libpng-devel \
libjpeg-devel libwebp-devel freetype-devel libzip-devel \
zlib-devel sqlite-devel oniguruma-devel readline-devel \
libsodium-devel gmp-devel libffi-devel libicu-devel \
bzip2-devel libxslt-devel 2>/dev/null || true
elif command -v apt &>/dev/null; then
apt install -y build-essential autoconf bison re2c pkg-config \
numactl libnuma-dev libjemalloc-dev \
libxml2-dev libssl-dev libcurl4-openssl-dev libpng-dev \
libjpeg-dev libwebp-dev libfreetype-dev libzip-dev \
zlib1g-dev libsqlite3-dev libonig-dev libreadline-dev \
libsodium-dev libgmp-dev libffi-dev libicu-dev \
libbz2-dev libxslt-dev 2>/dev/null || true
fi
# 重新检测jemalloc路径
for path in /usr/lib64/libjemalloc.so.2 \
/usr/lib/aarch64-linux-gnu/libjemalloc.so.2 \
/usr/local/lib/libjemalloc.so.2; do
[ -f "$path" ] && JEMALLOC_SO="$path" && break
done
[ -z "$JEMALLOC_SO" ] && warn "未找到jemalloc,将使用默认ptmalloc"
# ===== 下载PHP源码 =====
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
if [ ! -f "php-${PHP_VERSION}.tar.gz" ]; then
info "下载 PHP ${PHP_VERSION}..."
wget -q "https://www.php.net/distributions/php-${PHP_VERSION}.tar.gz"
fi
[ ! -d "php-${PHP_VERSION}" ] && tar -xzf "php-${PHP_VERSION}.tar.gz"
cd "php-${PHP_VERSION}"
# ===== 选择编译器 =====
if command -v clang &>/dev/null && clang --version 2>&1 | grep -qi "bisheng\|BiSheng"; then
info "使用毕昇编译器(BiSheng)"
export CC=clang CXX=clang++
export CFLAGS="-O3 -mcpu=tsv110 -march=armv8.2-a+simd+crypto -fstack-protector-strong -fPIC"
else
info "使用GCC编译器"
export CC=gcc CXX=g++
export CFLAGS="-O2 -march=armv8.2-a -mtune=tsv110 -fstack-protector-strong -fPIC"
fi
export CXXFLAGS="$CFLAGS"
export LDFLAGS="-Wl,-O2 -Wl,--as-needed"
# ===== configure =====
info "运行configure..."
./configure \
--prefix="$INSTALL_DIR" \
--with-config-file-path="${INSTALL_DIR}/etc" \
--with-config-file-scan-dir="${INSTALL_DIR}/etc/php.d" \
--with-libdir=lib64 \
--enable-fpm \
--with-fpm-user="$PHP_USER" \
--with-fpm-group="$PHP_USER" \
--enable-opcache \
--enable-mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-mysqli=mysqlnd \
--with-pdo-sqlite \
--with-openssl \
--with-curl \
--with-zlib \
--enable-mbstring \
--enable-bcmath \
--enable-gd \
--with-jpeg \
--with-zip \
--enable-soap \
--enable-xml \
--enable-intl \
--enable-sockets \
--enable-pcntl \
--enable-posix \
--with-sodium \
--with-gmp \
--with-readline \
--enable-calendar \
--with-bz2 \
--with-xsl \
2>&1 | tee "${BUILD_DIR}/configure.log"
# ===== 编译安装 =====
info "编译中(${CORES}核并行)..."
make -j"$CORES" 2>&1 | tee "${BUILD_DIR}/make.log"
grep -qE "^make.*Error" "${BUILD_DIR}/make.log" && error "编译失败,查看 ${BUILD_DIR}/make.log"
info "安装PHP..."
make install
# ===== 创建用户和目录 =====
id "$PHP_USER" &>/dev/null || { groupadd "$PHP_USER"; useradd -g "$PHP_USER" -s /sbin/nologin -M "$PHP_USER"; }
mkdir -p "${INSTALL_DIR}/etc/php.d" /var/log/php /var/run/php-fpm /tmp/php-opcache
chown www:www /var/run/php-fpm /tmp/php-opcache /var/log/php
# ===== 配置文件 =====
cp "${BUILD_DIR}/php-${PHP_VERSION}/php.ini-production" "${INSTALL_DIR}/etc/php.ini"
cp "${INSTALL_DIR}/etc/php-fpm.conf.default" "${INSTALL_DIR}/etc/php-fpm.conf"
cp "${INSTALL_DIR}/etc/php-fpm.d/www.conf.default" "${INSTALL_DIR}/etc/php-fpm.d/www.conf"
# ===== 写入鲲鹏优化配置 =====
cat > "${INSTALL_DIR}/etc/php.d/kunpeng-optimize.ini" << 'INIEOF'
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=512
opcache.interned_strings_buffer=64
opcache.max_accelerated_files=30000
opcache.validate_timestamps=0
opcache.save_comments=1
opcache.fast_shutdown=1
opcache.jit=tracing
opcache.jit_buffer_size=256M
opcache.huge_code_pages=1
opcache.file_cache=/tmp/php-opcache
opcache.file_cache_consistency_checks=0
memory_limit=1G
max_execution_time=60
upload_max_filesize=256M
post_max_size=256M
realpath_cache_size=8192K
realpath_cache_ttl=600
date.timezone=Asia/Shanghai
display_errors=Off
log_errors=On
error_log=/var/log/php/error.log
INIEOF
# ===== 系统大页 =====
info "配置系统大页..."
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
grep -q "vm.nr_hugepages" /etc/sysctl.conf || echo "vm.nr_hugepages=1024" >> /etc/sysctl.conf
# ===== 环境变量 =====
grep -q "${INSTALL_DIR}/bin" /etc/profile || \
echo "export PATH=${INSTALL_DIR}/bin:${INSTALL_DIR}/sbin:\$PATH" >> /etc/profile
# ===== systemd服务 =====
info "创建systemd服务..."
EXEC_START_CMD="/usr/local/php/sbin/php-fpm --fpm-config /usr/local/php/etc/php-fpm.conf"
# 如果有numactl,加上NUMA绑核
if command -v numactl &>/dev/null; then
EXEC_START_CMD="numactl --cpunodebind=${NUMA_NODES} --membind=${NUMA_NODES} ${EXEC_START_CMD}"
fi
cat > /etc/systemd/system/php-fpm.service << SVCEOF
[Unit]
Description=PHP FastCGI Process Manager (Kunpeng ARM64 Optimized)
After=network.target
[Service]
Type=forking
PIDFile=/var/run/php-fpm.pid
$([ -n "$JEMALLOC_SO" ] && echo "Environment=\"LD_PRELOAD=${JEMALLOC_SO}\"")
$([ -n "$JEMALLOC_SO" ] && echo "Environment=\"MALLOC_CONF=narenas:8,lg_tcache_max:16,background_thread:true\"")
ExecStart=${EXEC_START_CMD}
ExecReload=/bin/kill -USR2 \$MAINPID
PrivateTmp=true
LimitNOFILE=1000000
LimitNPROC=65535
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
SVCEOF
systemctl daemon-reload
systemctl enable php-fpm
systemctl start php-fpm
# ===== 完成 =====
source /etc/profile 2>/dev/null || true
info "=================================================="
info "鲲鹏ARM64 PHP ${PHP_VERSION} 部署完成!"
info ""
info "PHP路径 : ${INSTALL_DIR}/bin/php"
info "编译器 : ${CC}"
info "NUMA绑核 : node ${NUMA_NODES}"
info "jemalloc : ${JEMALLOC_SO:-未启用}"
info ""
info "验证命令:"
info " source /etc/profile && php -v"
info " php /usr/local/bin/kunpeng-php-check.php"
info "=================================================="
---
十六、三种部署模式对比与选型
鲲鹏ARM64 PHP部署模式选型指南
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
模式一:Nginx + PHP-FPM(传统模式)
┌─────────────────────────────────────────────────────┐
│ 请求 → Nginx → FastCGI → PHP-FPM Worker进程 │
│ │
│ 优点:稳定成熟,Laravel/ThinkPHP直接跑,运维简单 │
│ 缺点:每个请求独占一个进程,并发受进程数限制 │
│ 适合:普通Web应用、CMS、后台管理系统 │
│ 鲲鹏优化:NUMA绑核 + jemalloc + OPcache预加载 │
│ 参考QPS:单机 5,000 ~ 20,000(视业务复杂度) │
└─────────────────────────────────────────────────────┘
模式二:Swoole HTTP服务器(协程模式)
┌─────────────────────────────────────────────────────┐
│ 请求 → Nginx反代 → Swoole Worker(协程调度) │
│ │
│ 优点:协程并发,一个进程处理数万请求,IO不阻塞 │
│ 缺点:需要改造代码,全局变量有污染风险 │
│ 适合:高并发API、实时通信、微服务、长连接 │
│ 鲲鹏优化:Boost.Context协程 + 连接池 + NUMA绑核 │
│ 参考QPS:单机 50,000 ~ 200,000 │
└─────────────────────────────────────────────────────┘
模式三:Workerman + Webman(多进程模式)
┌─────────────────────────────────────────────────────┐
│ 请求 → Workerman Worker进程(事件驱动) │
│ │
│ 优点:纯PHP实现,兼容性最好,代码改造量小 │
│ 缺点:协程需借助Swoole,内存管理需注意 │
│ 适合:快速迁移现有项目、WebSocket、信创环境 │
│ 鲲鹏优化:多进程充分利用64核 + jemalloc │
│ 参考QPS:单机 30,000 ~ 100,000 │
└─────────────────────────────────────────────────────┘
---
十七、总结:鲲鹏PHP调优核心四板斧
第一斧:毕昇编译器 + 鲲鹏专属编译标志
CC=clang(BiSheng)
CFLAGS="-O3 -mcpu=tsv110 -march=armv8.2-a+simd+crypto"
→ PHP解释器本身的机器码质量更高,所有PHP代码都受益
第二斧:JIT + OPcache(ARM64原生支持)
opcache.jit=tracing
opcache.jit_buffer_size=256M
opcache.huge_code_pages=1
→ 热点代码直接编译成ARM机器码,CPU密集型提升30-100%
第三斧:jemalloc替换ptmalloc
LD_PRELOAD=/usr/lib64/libjemalloc.so.2
MALLOC_CONF=narenas:8,background_thread:true
→ 高并发下内存分配无锁竞争,减少内存碎片
第四斧:NUMA绑核(鲲鹏多路服务器必做)
numactl --cpunodebind=0,1 --membind=0,1 php-fpm
→ 消除跨NUMA内存访问,QPS提升可达2-4倍
→ 这是鲲鹏平台最大的性能杠杆,优先级最高
---
┌────────────────┬───────────────┬─────────────────────┬────────────────────┐
│ 优化项 │ 龙芯LoongArch │ 飞腾FT │ 鲲鹏920 │
├────────────────┼───────────────┼─────────────────────┼────────────────────┤
│ JIT │ 必须禁用 │ 可开启 │ 可开启,效果最好 │
├────────────────┼───────────────┼─────────────────────┼────────────────────┤
│ 编译器优化标志 │ 无特殊 │ -march=armv8-a+simd │ -mcpu=tsv110专属 │
├────────────────┼───────────────┼─────────────────────┼────────────────────┤
│ 专属编译器 │ 无 │ 无 │ 毕昇BiSheng │
├────────────────┼───────────────┼─────────────────────┼────────────────────┤
│ NUMA节点数 │ 通常1个 │ 最多16个 │ 4个(双路) │
├────────────────┼───────────────┼─────────────────────┼────────────────────┤
│ jemalloc │ 建议 │ 建议 │ 强烈建议 │
├────────────────┼───────────────┼─────────────────────┼────────────────────┤
│ 协程框架 │ Swoole 5.0.3+ │ Swoole 5.x │ Swoole 5.x原生最优 │
├────────────────┼───────────────┼─────────────────────┼────────────────────┤
│ 大页支持 │ 支持 │ 支持 │ 支持,效果明显 │
└────────────────┴───────────────┴─────────────────────┴────────────────────┘
更多推荐



所有评论(0)