
分类: 随笔
迁移博客到 VPS
在上篇文章优化了博客网站的性能过后,我对页面加载速度仍感到不太满意,Cloudflare 显示大部分页面仍需要等待接近 2 秒才能完成响应。一想到我之前在 cPanel 上执行了一些比较重的操作,网页的加载速度就会下降,所以可能之前的 Host Provider 并没有给我分配多少资源来折腾,这大概率就是网页访问速度慢的重要原因之一。
为了验证这个观点,我尝试在 Homelab 中的 N100 主机上部署了一个 WordPress,并将博客网站复制了一份到这台服务器上。我发现在缺少 Cloudflare 缓存的情况下,就算是通过 Cloudflare Connector 从公网访问家庭内网中的网站都比我线上的博客网站要快 😂。
确认了是 Host Provider 的性能问题后,我决定将博客网站迁移到我的一台 VPS 上,那么这篇文章的重点终于开始了。
我的 Word Press 实例一开始就是通过 Host Provider 建立的,之前在不同的 Provider 之间迁移时,主要也是通过管理面板上提供的一键迁移功能完成操作。但我没想到的是,这些一键迁移功能所涉及的插件都是付费的,之前之所以能顺畅的使用,大概率是 Host Provider 已经为这些功能付过了钱。
虽然插件市场中也有免费的备份恢复插件,但要么是备份出来之后不让恢复,要么是恢复备份会出错, 更离谱的是有些插件备份出来的数据竟然是加密的。
不过好在管理面板提供了一个简单的 Full Backup 功能,可以将 WordPress 目录连同整个数据库 Dump 一起打包。
在我的 VPS 上,出于方便我一直没安装任何面板,唯一的管理工具是 CapRover ,你将其简单的理解为自部署版 heroku。他自带的 WordPress 的部署模板,只要简单替换一下变量,就可以快速启动一个 WordPress 容器:

在这里,需要注意的 WordPress 的 Docker 镜像默认不包含 WP-CLI,需要使用
6.9.0-cli标签才能部署带 WP-CLI 的镜像。由于 CapRover 的限制,部署好的 WordPress 只能通过 CapRover 的 Nginx 网关访问,而 Nginx 网关已经处理了 TLS,所以转发到 WordPress 的流量只有 HTTP。
如果你从零使用 Docker 创建 WordPress 实例,上述的情况不会影响你,但如果使用从其他地方复制过来的 WordPress 实例,就会遇到无限重定向的问题。具体表现为访问
/wp-admin时,会响应当前重定向到当前 URL 。这时,就需要在wp-config.php的最顶部,添加下面的代码:if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) $_SERVER['HTTPS']='on'; else $_SERVER['HTTPS']='off';后记
上面就是迁移博客过程中比较大的坑点了,其实就算花 $9.9 买一个一键迁移插件可能也无法避开。但如果我在原来的 Provider 上加钱升级配置,可能也就不需要这次的迁移了。根据基本的经济学原理,我今天下午工作的价值就是下一档配置的 3 年订阅费,大概 $300,又省到钱了~
优化博客网站的性能
昨天收到了 Google Search Console 的提醒,我的博客网站有部分网页响应速度太慢了,影响用户体验。性能差我很早就有体会,不过当时将其归咎于我本地的网络环境没配置好。现在连 Google 都抱怨我的博客网站慢,那就不太可能是我的网络环境问题了。
当我们从地址栏输入网址并按下回车后,哪些地方最容易出现性能问题?电脑网卡、家庭路由器、社区网关、服务器网卡还是应用程序代码?
由于 Google 的报告,我快速排除了服务器网卡之前的选项,范围缩小到了服务器网卡问题跟应用程序代码慢之间。我在网上找到了一个 WordPress 插件 Code Profiler ,可以用来分析处理请求过程中的插件执行耗时。
我随机抽取了一篇很少被访问的博文,加上了禁用缓存的查询参数后,插件性能分析结果如下:

可以看到整个请求完成时间接近 1s,其中的 Jetpack 耗时接近 300ms。喷气背包可能在反向喷气。
根据这篇文章的介绍,我关闭了所有的 Jetpack 模块,但对响应速度没有太多影响。只有在彻底关闭 Jetpack 后,请求响应时间降到了 500ms 以内。这对于只有 1C1G 的共享空间来说,已经可以接受了。除此之外,内存开销、文件读写数量也都降低了15%。

当然,关闭 Jetpack 有一些代价,对我影响最大的是评论区不能支持 Markdown 了,发布新博文不能同步创建一个长毛象嘟嘟了。
总而言之,对我在使用的这台非常弱鸡的服务器来说,Jetpack 有些过于沉重了。
解决 Qsirch 无法搜索文件夹的问题
最近在整理家里的一些电子文件的时候,发现 QNAP 提供的 Qsirch 搜索功能无法搜索
/Public目录下的文件了,不管是文件名还是文件内容,都查询不到搜索结果。在网络上搜索了一番,Reddit 中有网友提到可以在 Multimedia Console 中重建索引,然后去 Appcenter 中重启 Qsirch 应用。不过我试下来,发现并没有什么卵用。
折腾半天,感觉实在没办法了,只能求助客服,在等待客服回复的过程中,突然想到,我之前通过 NFS 共享过
/Public目录,当时似乎从 Docker 中访问时,弄乱过目录的访问权限。所以,会不会是因为目录权限错误,导致 Qsirch 无法对文件建立索引?为了验证我的猜想,SSH 登录 QNAP 后,发现
/Public目录的权限果然有问题,该目录属于一个未知的 group,手动修改 Owner 为admin/administrators后,Qsirch 开始运行建立索引的后台任务了。等待索引建立完成,Qsirch 已经能够检索/Public目录的文件了~N100 小主机遭遇 NVMe 硬盘故障:一次系统的诊断与反思
我的 N100 小主机最近陷入了无响应的困境,一次系统级的卡顿,让我不得不深入诊断底层硬件问题。最终,故障源头被锁定在一块出现问题的 NVMe 硬盘上。
故障的发生与初步判断
故障最初表现为:系统在日常运行中,当需要读取某些特定数据时,NVMe 硬盘会陷入无响应状态。这直接导致相关进程卡滞在
D状态(不可中断睡眠状态)。当这类进程累积过多时,整个操作系统陷入僵局,无法响应任何其他请求。首次尝试解决,我选择了重启。然而,系统通常能坚持不到十分钟,便会在 CPU 占用率不高的正常负载情况下再次卡死。这表明问题并非偶发,而是存在深层原因。
精准定位故障源头
为了区分软件与硬件故障,我启动了 SystemRescue Live CD。在 Live CD 环境下,我开始使用
smartctl工具检查硬盘的健康状况。令人惊讶的是,仅仅执行smartctl -x /path/to/disk这样的详细健康状况检查命令,就能稳定复现系统卡死的故障。这一现象直接排除了操作系统层面的复杂问题,将故障的矛头清晰地指向了 NVMe 硬盘本身。
为了进一步验证,我将这块故障硬盘从 N100 小主机上取下,安装到另一台笔记本电脑上进行测试。结果,同样的卡死问题依然能够重现。这最终确认了硬盘是故障的根本原因,而非 N100 主机的 PCIe 接口或其他主机侧问题。
数据与保修:选择与取舍
这块 NVMe 硬盘尚未过保,这意味着我可以直接申请售后换新。然而,更换新硬盘的代价是硬盘上的所有数据。这块硬盘主要保存着我部署在 Docker 上的应用数据以及一些从网络下载的影片。
幸运的是,Docker 应用的关键数据每天都通过 restic 进行备份。因此,更换新硬盘对我来说,影响微乎其微,核心应用数据和配置都得以安全保存。至于影片文件,虽然会丢失,但并非不可恢复。
突发状况的应急预案
这次故障也促使我思考关键服务的紧急应对措施。我的 N100 宿主机上运行着一个软路由虚拟机,这意味着一旦宿主机故障,全屋的网络将随之瘫痪。
发生故障时,我的临时解决方案是:使用一根网线连接器,将 N100 主机上原本连接 LAN 与 WAN 的网线直连起来,并让家中的光猫直接充当网关。这样可以在最短时间内恢复主要的网络连接,保障家庭网络的正常运行。这为后续的故障排查与修复争取了宝贵的时间。
重要的经验教训
尽管 Docker 应用数据有定期备份,但这次经历也暴露了一个疏漏:我却忽略了软路由虚拟机磁盘映象(VM Disk Image)的备份。软路由的配置和运行状态都包含在这个映象文件中,一旦丢失,重建起来会相当耗时。
好在这次运气眷顾,通过 Live CD 成功抢救回了这份重要的虚拟机映象文件,避免了额外的麻烦。
外接显示器 EDID 损坏如何处理
上周五,我的外置显示器突然在一次热插拔后无法被笔记本电脑识别 4K 分辨率了,在排查了笔记本电脑、线材问题后,基本可以确定是显示器本身出了问题。
从内核日志来看,系统无法读取显示器 EDID 信息:
[ 174.781913] EDID has corrupt header [ 174.781923] amdgpu 0000:65:00.0: [drm] *ERROR* EDID checksum invalid. [ 178.681809] EDID has corrupt header [ 178.681819] amdgpu 0000:65:00.0: [drm] *ERROR* EDID checksum invalid. [ 232.892047] EDID has corrupt header [ 232.892057] amdgpu 0000:65:00.0: [drm] *ERROR* EDID checksum invalid. [ 235.172080] EDID has corrupt header [ 235.172091] amdgpu 0000:65:00.0: [drm] *ERROR* EDID checksum invalid. [ 623.720346] EDID has corrupt header [ 623.720359] amdgpu 0000:65:00.0: [drm] *ERROR* EDID checksum invalid. [ 625.949958] EDID has corrupt header [ 625.949969] amdgpu 0000:65:00.0: [drm] *ERROR* EDID checksum invalid.EDID 是一份显示器能力识别数据,包含生产厂商、支持的分辨率、刷新率等信息。EDID 一般存储在显示器的芯片内,如果显示器有多个输入端口,那么每个端口上的 EDID 通常会被分别存储在独立的芯片内。当电脑连接显示器时,会通过 DDC 读取显示器上存储的 EDID 信息,从而能够让电脑正确识别显示器的型号并输出显示器支持的视频信号。
当 EDID 存储器损坏导致电脑无法读取时,我们可以主动向操作系统提供某个视频输出端口的 EDID 信息。这样以来,解决问题的思路就导向了寻找一份可用的 EDID 文件。
幸好我的显示器有多个输入端口——一个 HDMI 2.0 以及 两个 HDMI 1.4 ,可以尝试读取 HDMI 1.4 端口的 EDID 文件,然后用 EDID 编辑器为其添加 4K@60Hz 的输出设置,作为 HDMI 2.0 接口的 EDID 文件。
读取显示器上的 EDID 文件
在 ArchLinux 上,可以使用
eedid-tool (AUR)读取并保存 EDID 信息。# 扫描已连接的显示器 i2c bus $ eedid-tool -s Bus 11 has EDID, mfg BOE 1 EDID(s) found. $ eedid-tool -r -b 11 > ./edid_hdmi1.4.bin由于 HDMI 1.4 不支持 4K 60Hz 的输入规格,所以需要手动尝试为其添加。
修改 EDID 文件
为了魔改刚刚导出的 EDID 文件,我使用了 AW EDID Editor,这款软件可以完美地通过 Bottles (Wine)运行,打开 AW EDID Editor 后,选择要修改 EDID 文件,稍等片刻后,你将看到这样的界面。

点击 CEA Extension 下面的 Add new CEA Block,选择 Detailed Timing Descriptor。

这时你会看到一个输入框全是 0 的配置界面。

接着点击 Use predefined format,选择希望添加的分辨率规格即可,对于我的显示器来说,需要选择 3840×2160 60Hz。


当配置界面被填充满各种数据后,就可以点击左上角的 File 菜单,保存修改后的 EDID 文件。

设置自动加载 EDID 文件
首先需要将修改后的 EDID 文件保存到
/usr/lib/firmware/edid/目录下,Linux 固件相关的二进制文件通常都放在这里。接着,我采用了下面的 systemd 文件来自动加载 EDID:
[Unit] Description=Override HDMI EDID for Koios Monitor After=sys-kernel-debug.mount Requires=sys-kernel-debug.mount [Service] Type=oneshot # 关键:告诉 systemd 即使脚本跑完了,服务也被视为"active",这样才能执行 stop RemainAfterExit=yes # --- 启动时执行 (应用 EDID) --- # 1. 写入自定义 EDID ExecStart=/bin/sh -c 'cat /usr/lib/firmware/edid/koios_hdmi2.0.bin > /sys/kernel/debug/dri/1/HDMI-A-1/edid_override' # 2. 触发热插拔,让内核应用更改 ExecStart=/bin/sh -c 'echo 1 > /sys/kernel/debug/dri/1/HDMI-A-1/trigger_hotplug' # --- 停止时执行 (撤销修改) --- # 1. 清空 override 文件 ExecStop=/bin/sh -c 'echo -n reset > /sys/kernel/debug/dri/1/HDMI-A-1/edid_override' # 2. 再次触发热插拔,让内核读取显示器原本的真实 EDID ExecStop=/bin/sh -c 'echo 1 > /sys/kernel/debug/dri/1/HDMI-A-1/trigger_hotplug' [Install] WantedBy=multi-user.target由于我经常只会用到这一台显示器,所以还设置了自动启动服务,当需要连接其他显示器时,就可以通过停止这个服务,让操作系统直接读取该显示器提供的 EDID 。
参考链接
在解决这个问题的过程中,参考了 Gemini 3 Pro 生成的回复,不过其中有不少事实性错误,仍应参考 Arch Wiki 的文档:
https://wiki.archlinux.org/title/Kernel_mode_setting#Forcing_modes_and_EDID
另外,为了防止笔记本内置显示器的 EDID 在未来也发生了无法读取的情况,以及方便其他拥有跟我同型号显示器的人需要 EDID 文件,我将这些 EDID 上传到了 IPFS 网络:
- 机械革命无界 15X Pro 暴风雪的 EDID
QmRYhQDg645VqcRknCWK6ucVsmn3iWBp5j4RAE16oufAHL - KOIOS K2419UB 的 EDID
QmRKseLcqduk41bxvPSfBPDCYaZoyP4uRQUKB6nV4Kpq5c
- 机械革命无界 15X Pro 暴风雪的 EDID
How to switch GitHub CLI account automatically
Working with multiple GitHub accounts on the same machine can be tricky, but we can automate account switching when changing workspaces. Here’s my solution using Fish Shell and Direnv.
Prerequisites
Install
direnv, this handy tool automatically loads environment variables when youcdinto directories.The Setup
Add this function to your Fish Shell configuration:
function __gh_auth_switch_gh_account --on-variable GH_ACCOUNT if test -n "$GH_ACCOUNT" gh auth switch --user "$GH_ACCOUNT" end endHow it works
Let’s break down the snippet:
--on-variabletells Fish Shell to run this function when the variableGH_ACCOUNTchanges value.test -n $GH_ACCOUNTreturns true if the length ofGH_ACCOUNTis non-zero.gh auth switch --user "$GH_ACCOUNT"switches the active account to$GH_ACCOUNT.
For example, if we need to switch to
gh-user-1underpath/to/company/. We can add a.envrcfile underpath/to/company:export GH_ACCOUNT=gh-user-1When we cd into
path/to/company/project1, direnv will set the GH_ACCOUNT variable automatically, and the callback function__gh_auth_switch_gh_accountwill be invoked by the Fish Shell to makegh-user-1active.似乎修复了唤醒后键盘短暂失效的问题
之前一篇文章的评论区有人提到过机械革命15XPro 暴风雪在唤醒后键盘会短暂失效的问题,往往需要重新睡眠再唤醒才能激活键盘。经过我的排查后发现,在该问题出现时,有两个比较重要的 Log 线索:
Aug 27 09:04:52 arch kernel: atkbd serio0: Failed to deactivate keyboard on isa0060/serio0 Aug 27 09:04:52 zarch kernel: atkbd serio0: Failed to enable keyboard on isa0060/serio0根据 Claude 以及互联网上相关的讨论,这个问题大概率跟内置键盘的驱动有关,通常可以通过尝试不同的 i8042/atkbd 相关参数来解决。
跟 Claude 讨论一番过后,我决定添加如下 kernel parameters:
i8042.reset=1 i8042.nomux=1 i8042.nopnp i8042.noloop atkbd.reset=1实际体验下来,键盘失效的问题已经一周多都没有复现了。
性能与公平:解决 Linux 桌面无响应的取舍之道
已经记不得从什么时候开始,我的 Linux 桌面偶尔会遇到无响应的问题,这个问题经常跟比较重的磁盘读写相关,例如更新 JetBrains IDE,JetBrains IDE 创建索引。之所以会把无响应的问题归结到磁盘读写上,是因为卡顿往往跟内存占用、CPU 使用率、进程数无关。卡顿的表现为:鼠标可以移动,但是 KDE 桌面包括状态栏无法更新;Kitty 可以创建新的 Tab,但是 Fish 启动会卡住;已有终端下虽然可以流畅输入命令,但是执行命令会卡住。这个周末因为成都一直在下雨,不太方便出门,决定来尝试解决卡顿问题。
我的电脑配置如下:

出现问题的固态硬盘型号是 KINGSTON SNVS1000G, SMART 信息如下:
# nvme smart-log /dev/nvme1 Smart Log for NVME device:nvme1 namespace-id:ffffffff critical_warning : 0 temperature : 89 °F (305 K) available_spare : 100% available_spare_threshold : 10% percentage_used : 31% endurance group critical warning summary: 0 Data Units Read : 61665672 (31.57 TB) Data Units Written : 171536497 (87.83 TB) host_read_commands : 967548759 host_write_commands : 2052988968 controller_busy_time : 75703 power_cycles : 79989 power_on_hours : 15798 unsafe_shutdowns : 241 media_errors : 0 num_err_log_entries : 0 Warning Temperature Time : 0 Critical Composite Temperature Time : 0 Thermal Management T1 Trans Count : 0 Thermal Management T2 Trans Count : 0 Thermal Management T1 Total Time : 0 Thermal Management T2 Total Time : 0在官网上查到这块固态硬盘的设计 TBW 是 240TB,目前写入了 87.83TB,按照这篇文章的估算方法,这块硬盘正值壮年,属于如果挂掉了会令人惋惜的状态。既然硬盘是健康的,那么就需要从软件的角度来排查问题了。
复现问题
根据我的日常使用经验,卡顿往往伴随高磁盘 IO,故可以使用硬盘跑分工具测试来复现问题:
fio --filename=/path/to/no_cow_test.fio --size=8GB --direct=1 --rw=randrw --bs=4k --ioengine=libaio --iodepth=256 --runtime=120 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1fio运行时,可以通过htop的 IO Tab 看到有明显的磁盘读写,这时如果运行不太常用的命令,比如前端切图仔电脑上的rustc --version,就可以观察到明显的延迟。通过这种方式比较稳定地复现问题场景后,就可以继续接下来的排查了。检查日志
journalctl -b -p err --no-pager跟dmsg -T展示的错误日志通常对排查问题非常重要,但是在我的卡顿问题复现时却没有记录下任何错误信息。问题的排查一度陷入僵局,这时就得靠 Gemini 大师帮我排查一下有哪些设置会影响存储设备的性能了。脏页
在 Linux 系统中,当应用程序向文件写入数据时,这些数据通常不会立即被写入到物理磁盘上。相反,它们首先被写入到内存中的一个缓冲区(称为「页缓存」或「page cache」)。这些已经修改但尚未写入磁盘的内存页就被称为「脏页」。
脏页机制可以有效提升磁盘性能,但为了防止脏页无限增长,我们可以设定
vm.dirty_ratio参数限制脏页数据占总内存的百分比,更多介绍请看 Wiki。对于我的配置而言,如果 dirty_ratio 过大,比如 20%,意味着脏页数据量最高达到 6GB,不仅会挤占其他应用的可用内存空间,还可能由于操作系统需要一次性写入大量数据造成卡顿。
但在我的测试下,将
vm.ditry_ratio以及相关参数调小一些带来的效果并不明显,所以还得向其他的方向上挖掘。IO 调度器
IO 调度器是 Linux 内核的一个组件,它的主要任务是优化对存储设备(如硬盘、SSD、NVMe)的读写请求顺序。
对于 SSD 设备来说,IO 调度器可以帮助确保每个进程都能获得合理的 IO 访问机会,避免某些进程被「饿死」,另外不同的调度算法会在数据吞吐量与请求延迟之间有不同的取舍,以适应不同的应用场景。
在默认情况下,Linux 不会为 NVME 设备设置 IO 调度器,它假设这类设备上的控制器有自己的优化机制,不需要额外的软件层面调度。我们可以通过下面的命令查看当前在使用的调度器(被方括号包围):
cat /sys/block/nvme1n1/queue/scheduler [none] mq-deadline kyber bfq然而在调度器的选择上,Gemini 跟 Arch Wiki 出现了分歧,Gemini 认为 NVME 以及 SSD 就应该选择
none作为 io scheduler,但 Arch Wiki 认为it depends:The best choice of scheduler depends on both the device and the exact nature of the workload. Also, the throughput in MB/s is not the only measure of performance: deadline or fairness deteriorate the overall throughput but may improve system responsiveness. Benchmarking may be useful to indicate each I/O scheduler performance.
考虑到我的日常使用场景是桌面应用,NVME 上自带的控制器完全不可能知道我正在使用的窗口应用,也就没法保障我主要使用场景下的响应速度,于是我决定采用 Pop_OS 的推荐,使用 Kyber 调度器。
重试问题场景后,卡顿的情况缓解了一些,但跟我的预期还有很大偏差,很多命令可能需要 10s 以上才能输出结果。于是又尝试了使用 BFQ scheduler,终于
rustc --version可以在后台运行重 IO 程序的情况下在 1s 内输出结果了。使用下面的 udev rule 就可以持久化设置 IO 调度器。# /etc/udev/rules.d/60-ioschedulers.rules ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="bfq"通过设置 IO 调度器很好的解决了我的问题,那么代价是什么呢?
I/O 调度器性能对比
相较于 none 调度器,其他的软件调度器都加入了额外的一层抽象,这势必会引入更多的开销,为了搞清楚降低延迟的开销,我进行了下面的测试。
fio --filename=/path/to/no_cow/test.fio --size=8GB --direct=1 --rw=randrw --bs=4k --ioengine=libaio --iodepth=256 --runtime=20 --numjobs=4 --time_based --group_reporting --name=iops-test-job --eta-newline=1 iops-test-job: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=256指标 none(基准) BFQ kyber 读取 IOPS 7,214 7,018 (-2.7%) 7,141 (-1.0%) 写入 IOPS 7,235 7,039 (-2.7%) 7,161 (-1.0%) 总 IOPS 14,449 14,057 (-2.7%) 14,302 (-1.0%) 读取带宽 28.2 MiB/s 27.4 MiB/s (-2.8%) 27.9 MiB/s (-1.1%) 写入带宽 28.3 MiB/s 27.5 MiB/s (-2.8%) 28.0 MiB/s (-1.1%) 吞吐量性能指标 延迟指标 none(基准) BFQ kyber 读取平均延迟 70.5ms 72.4ms (+2.7%) 71.2ms (+1.0%) 写入平均延迟 70.9ms 72.9ms (+2.8%) 71.7ms (+1.1%) 50% 延迟 70.8ms 71ms (+0.3%) 71ms (+0.3%) 95% 延迟 78ms 89ms (+14.1%) 81ms (+3.8%) 99% 延迟 82ms 114ms (+39.0%) 91-92ms (+11%) 99.9% 延迟 88ms 132-133ms (+50.0%) 128ms (+45%) 延迟性能对比 可以看到在单个进程的读写测试下, BFQ 跟 kyber 在吞吐量跟延迟上的表现要略逊一筹。而这些开销给 Linux 桌面场景下带来的提升量化后又有多少呢?这需要设计一个更加复杂的跑分测试了,我们需要让一个延迟敏感应用跟一个高吞吐量应用同时运行,然后对比不同 IO 调度器如何平衡两者的硬盘操作:
# 低延迟小请求 (模拟交互式应用) fio --name=latency_sensitive \ --filename=$TEST_DIR/latency_sensitive.fio \ --size=2GB --direct=1 --rw=randread \ --bs=4k --ioengine=libaio --iodepth=1 \ --runtime=$RUNTIME --time_based \ --group_reporting --output-format=json \ --output=/tmp/latency_sensitive.json & # 高吞吐量请求 (模拟批处理) fio --name=throughput_heavy \ --filename=$TEST_DIR/throughput_heavy.fio \ --size=4GB --direct=1 --rw=randread \ --bs=4k --ioengine=libaio --iodepth=512 \ --runtime=$RUNTIME --time_based \ --group_reporting --output-format=json \ --output=/tmp/throughput_heavy.json &不同的 IO 调度器在我电脑上的实际测试结果如下:
调度器 延迟敏感应用 IOPS 延迟敏感应用平均延迟 高吞吐应用 IOPS IOPS 比率 BFQ 5,474 0.18 ms 129,350 23.63 kyber 4,611 0.22 ms 138,904 30.12 none 3,154 0.32 ms 146,104 46.32 IOPS 比率:高吞吐应用获得的 IOPS 是延迟敏感应用的多少倍
通过上面的测试可以看到:
- BFQ 在公平性方面表现最佳,真正保护了延迟敏感应用
- None 调度器确实能提供最高的原始吞吐量,但以牺牲公平性为代价
- Kyber 提供了较好的平衡,但在极端公平性方面不如 BFQ
结论
正如 Arch Wiki 所说,如何选择 IO 调度器取决于你的使用场景跟工作负载,在我的工作电脑上,BFQ 才是那个能够让我这块中年硬盘提供最佳桌面应用使用体验的调度器。
提升机械革命无界 15XPro 暴风雪的充电速度
无界15XPro 的 99Wh 电池容量属实很大,但充电速度一言难尽,基本上要 4~5 小时左右才能从 10% 充到 100%。经过一番搜索后,总算找到了提升充电速度的方法。
安装 Tuxedo Control Center 后,可以在 Settings 中找到 Battery Charging Options,只需要将 USB-C charging options 设置为 Priorize battery charing speed 就行。另外,如果长时间插电使用,还可以将 Charging profiles 设置成 Stationary use,这将会在硬件层面限制电池充电到 80% (但系统设置仍会显示充电到 100%)。

如果你没安装 Tuxedo Control Center 也没关系,只要安装了驱动程序 (aur/mechrevo-drivers-dkms) ,就能通过下面两个 sysfs 接口实现同样的功能:
cat /sys/bus/platform/drivers/tuxedo_keyboard/tuxedo_keyboard/charging_profile/charging_profile cat /sys/bus/platform/drivers/tuxedo_keyboard/tuxedo_keyboard/charging_priority/charging_prio