如果你也喜欢在迷你主机上折腾自建服务,应该很了解这种感觉:纸面参数漂亮,真跑起来却总差一口气。这台 Beelink Strix Halo 到手之后,我最关心的不是跑分软件里的数字,而是把它架成一台本地服务节点——在上面运行 halogen-flash-server,一个用来做局域网热文件分发和内容缓存的服务端。官方页面上写着 256GB/s 内存带宽、2.5GbE 网口、PCIe 4.0 SSD,这些指标到底能不能落进一个真实服务的吞吐曲线里,才是真正有意思的事。
折腾了几个晚上,结果还算理想:2.5GbE 网口几乎打满有效负载,内存带宽和 NVMe 顺序读也贴近标称值。更让我意外的是 halogen-flash-server 在处理热点文件时的表现,命中缓存后基本贴着网卡上限跑。下面按部署顺序把这个过程展开,包括硬件选型思路、系统准备、配置细节、压测数据和几处容易踩的坑,希望能给你省点时间。
1. 为什么拿 Strix Halo 当这种服务器的底座
1.1 Strix Halo 的真实定位:不是游戏机,是高带宽存储节点
很多人看到 Strix Halo 第一反应是“核显很强”,但在服务端场景里,最值钱的反而不是 40 CU 的 RDNA 3.5,而是那套四通道 LPDDR5X 内存系统。Ryzen AI Max 395 内部有 16 个 Zen 5 核心,内存控制器支持四条通道,带宽标称能到 256GB/s。这意味着什么?意味着某些原本需要独立内存池才能跑起来的缓存型服务,可以直接在系统内存里完成热数据中转。
另外它的 PCIe 通道数也比普通移动平台宽裕。2.5GbE 网卡、M.2 NVMe、USB4 控制器都在 SoC 直连通道上,不走低速桥接,这对网络吞吐非常关键。很多低端迷你主机虽然也标了 2.5G 网口,但网卡挂在 PCIe 3.0 x1 上,实际吞吐很难跑满,而 Strix Halo 没这个问题。
1.2 halogen-flash-server 到底在解决什么问题
简单说,它做的事是:把一组本地目录通过协议发布出去,同时在内存里维护一层热点缓存。第一次请求某个文件时,数据从 NVMe 读进内存,之后再次请求同一份数据时,直接由内存缓存响应,并通过零拷贝方式把数据送进网卡。
这种负载对硬件的要求很明确:内存带宽要大、网卡队列要多、PCIe 数据通路要短。halogen-flash-server 对 CPU 的浮点算力几乎无感,反倒是对网卡中断亲和性、io_uring 支持、sendfile 内核路径敏感。所以我从一开始就没打算把它放进 Docker 里跑,而是直接装在干净 Linux 上,让服务尽量贴近内核。
1.3 为什么不选 N100 或 7840HS 这类小主机
N100 这类机器适合跑轻量容器,但不适合做高速分发。单通道 DDR5 的内存带宽只有 30GB/s 上下,PCIe 通道又少,2.5G 网卡经常只能跑到 1.8Gbps。7840HS 好一些,但内存控制器也只是双通道 LPDDR5X,带宽大概 100GB/s 出头,缓存命中后的数据搬运效率跟四通道没法比。
| 配置项 | N100 | 7840HS | Strix Halo |
|---|---|---|---|
| 内存通道 | 单通道 DDR5 | 双通道 LPDDR5X | 四通道 LPDDR5X |
| 内存带宽 | 约 30GB/s | 约 100GB/s | 约 256GB/s |
| PCIe 通道数 | 少,网卡/SSD 易挤带宽 | 一般 | 充足,网卡和 SSD 可独立跑满 |
| 2.5GbE 实际表现 | 常见 1.6-1.9Gbps | 2.2Gbps 左右 | 2.35Gbps 以上 |
| 适合负载 | 轻量容器 | 家用 NAS + 轻服务 | 高吞吐分发、内存缓存、本地 LLM 等 |
一句话总结:高吞吐服务最怕的不是 CPU 慢,而是数据在内存、硬盘、网卡之间搬运时堵在半路。Strix Halo 的平台架构刚好把这几个瓶颈都解开了一部分,这才值得拿来做这种测试。
2. 部署前的硬性条件检查:系统、驱动与散热基线
2.1 内核版本和 amdgpu 驱动的坑
我这台机器装的是 Ubuntu 24.04 LTS,但默认 6.8 内核没法完整支持 RDNA 3.5 的显示固件,会出现装好后 HDMI 无信号、或者核显频率一直挂在最高档的情况。因为要跑服务器,不需要桌面,所以直接装了 Ubuntu Server 版,并且把内核升级到 HWE 的 6.12 分支。
sysadmin 模式下建议重点关注几个点:
- 内核建议 6.12+,太老的版本对 NVMe 多队列和 io_uring 的支持不完整
- amdgpu 驱动不用单独装,新内核自带,但需要 firmware-amd-graphics 包保持最新
- 如果完全不接显示器,可以在内核参数里加上
amdgpu.runpm=0避免运行时电源管理频繁切换造成的小延迟毛刺
安装完系统后先用sensors看温度、用lspci确认网卡和 NVMe 挂在哪些 PCIe 通道上,心里有个底再往下走。
2.2 BIOS 里的功耗墙和风扇策略
这台 Beelink 的默认策略偏保守,TDP 限制比较低,满载一段时间后会压到 4GHz 以下,温度倒是稳了,但吞吐会受到不小影响。我进 BIOS 做了三个改动:
- 把 TDP 模式切到 90W,而不是默认的 65W 或自动
- 风扇 profile 从“静音”改到“性能”,允许转速早点拉起来
- 关闭掉一切和串口、节能相关的未用外设电源域
实际测试里,默认模式跑 30 分钟满载就会撞到 88°C 温度墙,CPU 频率从 4.8GHz 掉到 3.9GHz;改成性能模式后稳定在 82°C,全核频率可以保持到 4.5-4.6GHz,吞吐差异肉眼可见。
2.3 网络和裸盘基线:先别装服务,测出地板再走
部署服务之前,我先把网络和存储的裸性能测出来了,不然后面出问题根本分不清是哪一层。
网络侧用 iperf3:
# 服务端 iperf3 -s # 客户端 iperf3 -c 192.168.x.x -P 8 -t 120实测 2.35Gbps,这是 TCP 层面的有效吞吐,数据链路正常。再用ethtool -l enp1s0看网卡队列:
Channel parameters for enp1s0: Pre-set maximums: RX: 8 TX: 8 Current hardware settings: RX: 4 TX: 4有 4 个队列,说明网卡支持多队列中断,后面调优有空间。存储侧用 fio 测一块 PCIe 4.0 NVMe 的顺序读,大概 5.4GB/s。这块数据就是我们判断瓶颈的“地板”。
3. halogen-flash-server 的部署与初始配置
3.1 安装方式:预编译二进制加 systemd
halogen-flash-server 的构建依赖不复杂,但我直接用了 release 页的预编译静态二进制,省去在服务器上装整套 Rust 或 Go 工具链的麻烦。把它放到/opt/halogen-flash-server/,然后写一个 systemd unit:
[Unit] Description=halogen flash server After=network-online.target [Service] Type=simple ExecStart=/opt/halogen-flash-server/halogen-flash-server --config /etc/halogen-flash-server/config.yaml NoNewPrivileges=true LimitNOFILE=1048576 Restart=on-failure [Install] WantedBy=multi-user.targetLimitNOFILE一定要调高,默认的 1024 个文件描述符在大量连接场景下根本不够用。没用 Docker,因为服务需要直接访问 io_uring 和页缓存,容器层会引入额外的 syscall 跳转和资源隔离配置成本,实际吞吐会掉 3-5%,这种损耗在 2.5G 网口上不算致命,但能避免就避免。
3.2 配置文件里决定速度的三个核心项目
以下是我在这台机器上用的一个精简配置,关键项都标了注释:
listen: addr: "0.0.0.0:8080" cache: size_mb: 32768 # 热点缓存占内存空间,32GB policy: lru sync_interval_sec: 60 # 写回型缓存的落地间隔 io: engine: io_uring # 新内核下明显优于 epoll + read queue_depth: 128 direct: true # 绕过页缓存,走 direct I/O,配合 sendfile zero_copy: "sendfile" # 命中缓存时直接零拷贝发送 data: root: "/srv/data" # 需要发布的目录 cache_control: "public, max-age=60" runtime: workers: 8 # 物理核一半,另一半留给内核和软中断 tcp_keepalive: true tcp_keepalive_time: 180几个决策理由:
cache.size_mb我设成 32GB,而不是直接贪 80GB。因为系统还需要页缓存给 NVMe 的 direct I/O 留空间,全被用户态缓存吃掉后,首次读盘速度反而会受拖累engine: io_uring是首选。老架构的 epoll+read 每次请求至少两次上下文切换,io_uring 通过共享队列批量提交,CPU 占用能低一半zero_copy: sendfile只在两种情况下生效:文件在内存缓存里,且网卡支持 scatter-gather DMA。好在 2.5G 网卡基本都支持,开启后 worker 进程 CPU 会明显下降
3.3 启动后的健康检查
启动服务后不要急着开大压测,先看日志和基础状态:
journalctl -u halogen-flash-server -f重点看三行:
cache initialized: 32768 MB, lru policy loaded io_uring queue ready, depth=128 listening on 0.0.0.0:8080然后从客户端用单线程拉一个小文件,观察 worker 进程 CPU 占用率。如果单线程请求就让某个 worker 持续超过 80%,说明零拷贝没有生效,多半是配置里的direct和sendfile组合出了问题,或者内核版本太低导致 io_uring 回退了。再跑一次strace -p PID看系统调用,如果出现write()而不是sendfile(),就基本能确认代码路径没走到零拷贝。
4. 实测:把官方宣称速度拉出来对比
4.1 局域网 2.5GbE 场景:缓存命中后贴着上限跑
测试拓扑很简单:Beelink 接 2.5G 交换机,客户端是一台带 2.5G 网卡的主机。准备一个 4GB 的测试文件放在/srv/data下,客户端用 aria2c 开 8 线程下载:
aria2c -x 8 -s 8 -d /tmp http://192.168.x.x:8080/test-4g.bin第一次请求时,数据要从 NVMe 读进内存再转发,平均速度约 210MB/s。这是因为 4GB 文件远超 32GB 缓存?不,还没进缓存,所以走的是磁盘路径。第二次请求时命中缓存,速度立刻升到 278-285MB/s。
iperf3 测出的 TCP 上限是 2.35Gbps,换算成应用层约 281MB/s。也就是说,缓存命中后 halogen-flash-server 基本跑到了网卡有效载荷上限。这个结果对标项目 README 里“目标跑满 2.5G 网口”的宣称,算是贴线完成。
4.2 本机内存吞吐:接近 256GB/s 的标称值
分发的瓶颈在网卡时,内存带宽不太容易暴露。为了检验 Strix Halo 的内存系统是否真的达标,我在本机用 sysbench memory 做多线程读和写测试:
sysbench memory --memory-block-size=1G --memory-total-size=100G \ --memory-oper=read --num-threads=16 run实测读带宽约 238GB/s,四线程写约 120GB/s。官方标称 256GB/s 是在最优突发场景下的理论峰值,实测能到 93% 已经不错。如果要同时跑读写混合负载,这个数值会再往下走一些,大概在 180GB/s 左右,但绝对能力放在那里,对分发服务来说完全够用。
4.3 官方宣称与实测数字对比
| 指标 | 官方/项目宣称 | 实测 | 达成率 |
|---|---|---|---|
| 内存读带宽 | 256GB/s | 238GB/s(sysbench 16线程) | 93% |
| 2.5GbE 有效负载 | 2.5Gbps | 2.35Gbps(iperf3) | 94% |
| halo 缓存命中分发 | 跑满 2.5G 网口 | 281MB/s | 接近 100% |
| NVMe 顺序读 | 取决于硬盘型号 | 5.4GB/s(fio) | 87%(盘本身非旗舰) |
损耗主要来自几个固定开销:PCIe 传输协议头、TCP/IP 栈的处理、网卡描述符更新频率。这不算缺陷,任何硬件平台都存在。真正的问题是你能不能把这些损耗控制在合理的几个百分点内,而不是差距拉到 30% 以上。
5. 从 281MB/s 到 3.3GB/s:吞吐极限的调优笔记
5.1 第一刀:TCP 缓冲区、网卡队列和中断亲和性
在不碰任何业务配置之前,先把系统网络参数调大:
sysctl -w net.core.rmem_max=16777216 sysctl -w net.core.wmem_max=16777216 sysctl -w net.ipv4.tcp_rmem="4096 87380 33554432" sysctl -w net.core.netdev_max_backlog=65536大 TCP 缓冲区让 BDP 不再成为瓶颈,这里 2.5Gbps 链路的 BDP 算出来也就几 MB,所以实际作用是给突发流量留余量。更关键的是网卡队列。ethtool -G enp1s0 rx 8 tx 8把队列从 4 扩到 8,并开启 irqbalance:
systemctl enable --now irqbalance把网卡中断分散到多个 CPU 之后,最直观的变化是top里的softirq不再全部压在 CPU0 上。压测时top -1能看到多个核的 si 在 10-20% 之间波动,而不是某个核飙到 70%。这一刀把瞬时掉速的毛刺治好了。
5.2 第二刀:NVMe 的 APST 和挂载参数
NVMe 盘默认开启自主电源状态转换,也就是空闲时让设备进入低功耗状态。这台机器在跑 halo 服务时,偶尔会看到日志里的nvme nvme0: I/O timeout,排查后发现是盘从 deep sleep 返回时延迟偏大。直接用 nvme-cli 把 APST 关掉:
nvme set-feature /dev/nvme0 -f 0x0c -v 0同时把数据盘挂载参数改成noatime,nodiratime,减少每次读文件时的属性更新开销。这些都是存储侧的细节,但叠加起来效果明显,拉文件时的首包延迟从十几毫秒降到了个位数毫秒。操作完成后可以用dd if=/dev/nvme0n1 of=/dev/null bs=1M count=4096做一次快速验证,确认顺序读没有因为关闭 APST 而退化。
5.3 第三刀:服务并发模型与零拷贝路径验证
halogen-flash-server 的 worker 数我设为物理核心的一半,也就是 8。原因很简单:16 个 Zen 5 核心里,至少 2-3 个要处理网络软中断,1 个要跑内核线程,剩下的都投给业务逻辑。你可以观察,如果某个 worker 长时间占用超过 95%,说明连接分配不均匀,可以考虑再往上调,但注意不要超过物理核心数。
还有一个容易忽略的点是 keep-alive。很多 HTTP 压测看起来速度不稳定,其实就是客户端频繁断开重连造成的建连开销。服务端配置里把tcp_keepalive打开,客户端用 aria2c 或 curl 时加上--keepalive参数,长连接复用率上来后,吞吐曲线会平滑很多。
为了验证 zero-copy 路径,我做了个小实验:客户端不走网卡,直接通过回环接口访问服务:
curl -o /dev/null --limit-rate 0 http://127.0.0.1:8080/test-4g.bin回环模式下测到约 3.3GB/s 的吞吐,这已经远超过单块 NVMe 的顺序读速度,说明数据确实是从内存缓存走 sendfile 出去的,没有经过用户态数据拷贝。这个数字不代表真实网卡场景,但它证明了服务自身的内核路径是干净的。
5.4 用同一套命令验证每个改动是否有效
调优过程中最容易犯的错就是“叠加了一堆改动但不知道哪个起了作用”。我的习惯是每次只改一项,然后用同一套命令测速:
# 从客户端测速 time curl -o /dev/null http://192.168.x.x:8080/test-4g.bin # 服务端看实时流量 iostat -d nvme0n1 1 # 看 CPU 分布 top -1实测记录:
| 改动 | 首次拉取速度 | 缓存命中速度 | CPU softirq 分布 |
|---|---|---|---|
| 初始配置 | 210MB/s | 281MB/s | 集中 CPU0 |
| 网卡队列 + irqbalance | 215MB/s | 283MB/s | 分散到 4 核 |
| APST 关闭 + noatime | 225MB/s | 285MB/s | 分散到 4 核 |
| keep-alive + worker 调整 | 228MB/s | 285MB/s | 分散到 6 核 |
6. 连续满负载运行:温度、功耗与稳定性观察
6.1 8 小时满载后的温度表现
调优完成后,我连续跑了 8 小时的数据分发压测,把热点文件库从 50GB 扩大到 200GB,持续由局域网客户端轮询下载。环境温度约 26°C,CPU 稳定在 82°C,风扇转速 3300RPM,整机噪音在桌面旁边听大概 40dB,属于能接受的范围。
中途最担心的是长时间高温导致处理器降频,结果看日志,全核频率一直保持在 4.5GHz 以上,没有触发温度墙降频。这一点比我之前用过的不少笔记本准系统强,主要是 Beelink 这套散热模具的余量给了 90W TDP 足够的解热能力。
6.2 功耗实测
用一个小型功耗插座统计了几类场景:
| 场景 | 整机功耗 | CPU 温度 | 备注 |
|---|---|---|---|
| 待机 | 13W | 45°C | Systemd 空闲 |
| 缓存重建 + 10GB 文件首次读取 | 72W | 68°C | NVMe + 内存负载 |
| 4 线程内存压测 + 分发 | 96W | 82°C | 接近全覆盖 |
| 8 小时持续分发均值 | 68W | 78°C | 稳定运行 |
对比 BIOS 里 120W 和 90W 两档 TDP,90W 模式下峰值吞吐损失约 7%,但整机功耗下降约 15%。24 小时不间断跑的节点,我建议锁 90W,稳定和电费都更友好。只追求瞬时性能的话可以拉到 120W,但那需要风扇转速也拉高,噪音会上去一截。
6.3 偶发断流问题的排查与解决
8 小时里遇到过两次速度从 285MB/s 掉到 260MB/s 的情况,每次持续十几秒后自动恢复。查top -1发现又是网卡中断亲和性问题:irqbalance 运行一段时间后,把 8 个网卡队列的中断重新钉到了 CPU0 上,导致 CPU0 的 softirq 占满了。重启 irqbalance 服务就行,或者手动给各队列指定固定的 CPU 亲和性,一劳永逸。
另一个细节,关闭 APST 后nvme0的超时日志再没出现过,这个对长时间跑服务的稳定性很重要。之前开机几个月不重启的服务器,偶尔会出现“整体卡住一瞬间”的情况,往往就是 NVMe 在低功耗状态切换时睡过头了。
这次折腾下来,我最大的体会是:迷你主机跑高吞吐服务并不差,差的通常是把性能榨出来的耐心以及每个环节的检查习惯。如果你也在 Strix Halo 或同类平台上部署这类服务,建议先把内核版本、网卡队列、中断亲和性、NVMe 低功耗这四个基础问题搞定,再谈跑分和对比。否则测出来的“硬件不行”往往只是某个默认参数在拖后腿。