用 Typecho 写博客图的是轻量,但很多人把 Typecho 跑成一个"每次都要执行几百条 SQL、把 PHP 塞在 Apache 里跑 CGI 进程池、图片原图直出、cdn 完全没有"的慢站点。多数"我的博客很卡"的问题,根源其实不在 Typecho 本身,而在 PHP 运行时、静态文件与数据库这三条腿都没迈开。这篇文章不谈玄学,按从下到上的顺序拆解 Typecho 的提速路径:从 PHP-FPM 与 OPcache 这一层开始,再做数据层缓存与数据库索引,最后是 Nginx 静态优化、HTTP/2/3 与 CDN,把每一步跟你讲清楚"为什么它有用、适合谁、代价是什么"。
一、先治运行时:PHP-FPM 与 OPcache
Typecho 的程序代码很小,执行本身的 CPU 消耗并不高,真正拖慢首屏的是"编译 PHP 字节码 + 每请求重复加载框架 + 进程池调度"这三件事。第一刀就下在 PHP 运行时上。
先从部署形态讲起。Typecho 官方文档建议用 Nginx + PHP-FPM,理由很实在:相比之下 Apache 的 mod_php 是每请求都起一个进程响应,而 PHP-FPM 是常驻进程池,配合 Nginx 的 fastcgi 转发,请求之间复用进程,避免反复 fork 的开销。切到 FPM 之后,进程池的 pm 参数就决定了它能吃多少并发:小内存机器用 pm = ondemand 让进程按需拉起、空闲即回收,省内存;流量稳定、内存富裕的机器用 pm = static 配固定进程数来得更稳。从经验上讲,绝大多数个人 Typecho 流量远没到需要调 max_children 的上限,默认值留给正常并发绰绰有余,别一看慢就去无脑加大,那只会把人均内存翻倍。
第二刀是 OPcache——它把 PHP 源码预编译成字节码缓存到共享内存里,命中后跳过编译环节。Typecho 这种框架一经部署代码就不会频繁变动,是 OPcache 的理想对象。在 php.ini 里至少打开 opcache.enable=1、把 memory_consumption 调大到 128M、max_accelerated_files 提到 10000。Windows 上记得确认扩展 dll 存在,Linux 上装 php-opcache 扩展即可。开了 OPcache 后,靠配置里的 validate_timestamps=0 可以进一步省掉"每次检查文件 mtime"的 stat 开销——前提是你不会用 FTP 频繁改代码,否则反而会因为缓存到旧版本而"改完看不到效果",权衡下来大多数场景保持默认的定时校验更省心。
二、数据层:对象缓存与慢查询索引
运行时解决了以后,瓶颈往往转移到数据库。Typecho 的默认配置每开一个页面都要读分类、标签、侧边栏评论等大量 SQL,而这些结果在短时间内几乎不变化。这层内容的缓存由对象缓存插件来做最划算——Typecho 的文章、分类、评论都可以被缓存成文件或 Redis/Memcached 结构。
装一个对象缓存插件(例如 Typecho 生态里的 Redis 缓存类插件)后,前一次请求生成的页面片段、查询结果会被直接命中,第二次打开同一篇或多篇文章时就少跑大半的 SQL。相比文件缓存,Redis/Memcached 的优点是跨进程共享、过期即清、不用为 Nginx worker 变量的一致性操心,代价是要多维护一个常驻内存进程。流量再大的站点,也可以直接让 Nginx 配合 Redis 做页面级缓存,把整张渲染好的 HTML 缓存起来。
数据库自身的优化也不可忽略。Typecho 的 SQLite 默认把数据库当普通文件读写,写多了会触发 WAL 膨胀;换 MySQL/MariaDB 后,重点看两件事:一是给常用字段加上索引——尤其是文章 ID、slug、评论的 articleId,很多"文章列表越来越慢"的根因就是缺索引导致全表扫描;二是用 SHOW PROCESSLIST 或慢查询日志,把真正慢的 SQL 抓出来,而不是凭感觉乱加索引。索引不是越多越好,写多读少的字段加多了反而拖慢写入。
三、静态层:Nginx 缓存、Gzip 与 Brotli
真正让一顿首屏"快一半"的往往不是后端,而是静态文件。Typecho 生成 HTML 后,图片、CSS、JS 这些静态资源如果不做任何处理,浏览器每次都要重新下载原始体积的文件——这是最容易被忽略、收益却最直接的优化点。
第一步是开启 Nginx 的 gzip。对 1KB 以上的文本类响应压缩,配合 gzip_min_length 和 gzip_types 白名单只压 text/css、application/javascript、image/svg+xml 等,图片这种本身已压过的格式就不重复压(没收益还费 CPU)。预算充足或追求 Top 体验的,再上 Brotli——它的压缩率比 gzip 平均高 10%-20%,但需要考虑浏览器兼容(现代浏览器均已支持),配置上往往用
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css application/javascript image/svg+xml;
# brotli 依赖 ngx_brotli 模块
brotli on;
brotli_comp_level 5;
brotli_types text/css application/javascript image/svg+xml;
第二步是为静态资源设置长缓存。给图片、CSS、JS 加 expires 30d 或 Cache-Control: public, max-age=2592000,让浏览器从本地缓存取,避免每次刷新都重新拉。这里有个关键前提:更新后要改文件名或在 URL 上带版本号(version 参数),否则旧缓存不会失效。
第三步是针对仍未命中缓存的页面请求,用 Nginx 的 proxy_cache 或 fastcgi_cache 做一层页面级缓存——把 Typecho 渲染好的整页 HTML 缓存在 Nginx 层,命中后完全不进 PHP。这是"并发突然上来时站点不崩"的关键一招,代价是要小心缓存了登录用户的动态内容,通常策略是按 URL 或按 Cookie 区分分流。
四、传输层:HTTP/2、HTTP/3 与 TLS 会话复用
讨论"快不快"时,连接层容易被忽略:每一次 HTTPS 握手都要做一次密钥交换,在弱网下占总耗时的比例相当可观。HTTP/2 引入了多路复用,一个 TCP 连接里并发多个请求,解决了 HTTP/1.1 的队头阻塞,配合 Nginx 的 http2 指令即可开启;而 HTTP/3 基于 UDP 的 QUIC,进一步消除 TCP + 重传的队头阻塞,弱网丢包时体验提升明显,Nginx 需编译 http_v3、监听 443/udp。
这一层的另一件小事是 TLS 会话复用(ssl_session_cache 与 ssl_session_tickets),它让短连接重连时跳过完整握手,把 TLS 的握手耗时降到一次往返以内。对个人站点这种访问者回头率高的场景,收益长期且稳定。做这些的前提是拿到一张有效的 TLS 证书——让站点一直走 HTTPS,比 HTTP 明文加一层 CDN 对性能和安全都更友好。
五、最后一公里:CDN 与图片裁剪
到这一步,后端、静态资源、连接协议都优化过了,剩下的是两张很多人忘掉的牌:图片瘦身和 CDN。
Typecho 上传的原图往往几 MB。一张首屏里塞三张原图,再快的服务器也会被带宽拖垮。靠谱的做法是开启图片裁剪/WebP 转换插件,把大图在服务端降采样成合适尺寸,再给 WebP 或 AVIF 一个更高的压缩率——同一张图体积能降到原来的三分之一甚至更小,而视觉损失几乎不可感知。配合 <picture> 标签与 srcset,浏览器会自动按屏幕设备密度选合适图片。
CDN 的作用是把静态资源分发到离访客最近的节点,减少跨国/跨运营商的链路时延。给 Typecho 接 CDN 时注意区分"静态 CDN + 动态回源"的组合:图片、CSS、JS 交给 CDN 缓存并 GET 即可,动态页面则让 CDN 回源到你 Nginx 再做 fastcgi 缓存,否则 CDN 会变成一层穿透源站的流量转发,反而拖慢。做 CDN 后别忘了给站点配置正确的 HSTS 与 CORS,避免缓存了错误响应后被浏览器长期记住。
六、把优化做成"可量化"而不是"感觉快了"
最后给一个纪律:任何优化都要能测量、能对比、能回滚。动手之前先记下基线——首字节时间 TTFB、Largest Contentful Paint、每个请求的资源体积与命中率;做完一层就重测一次,确认方向正确以及没有引入新问题(比如缓存了登录态的页面、暴露出过期的动态数据)。
很多"博客还是慢"的问题,其实是慢在你没动过的那一层:可能是某个图片没裁剪、某个 widget 每次请求都查库、或者是 TLS 握手成了弱网下的重头。把上面这几层的顺序走一遍——先 PHP 运行时,再对象缓存与索引,接着静态压缩与页面缓存,然后协议与 TLS 复用,最后 CDN 与图片——Typecho 的提速空间基本就挖得干净了。优化的价值不在于把每一项都调满,而在于你知道你的瓶颈到底在哪一层,并且每一层都有对应的工具去命中它。



