本地开发环境慢?localhost 的锅!
一场历时三小时的性能追杀
第一章:晴空霹雳
"后台响应速度太慢了,查询要 300ms 以上,降到 50ms。"
接到这个需求的时候,我心想:不就是几个简单的 SELECT 查询吗?加个索引、优化下 SQL,手到擒来。
太天真了。
第二章:全面围剿
三个端点,全是简单的元数据查询:
sql
SELECT id, code, name, table_name FROM meta_entity WHERE is_deleted = 0 ORDER BY code ASC;
SELECT ... FROM meta_entity_prop WHERE parent = ? AND is_deleted = 0 ORDER BY sort ASC;
SELECT ... FROM meta_enum_item WHERE parent = ? AND is_deleted = 0 ORDER BY create_time ASC;
于是开始了一轮又一轮的优化:
第一轮:索引 ------建覆盖索引,消除全表扫描。没解决。
第二轮:SQL 改写 ------把两次查询合成一次 JOIN,减少数据库往返。没解决。
第三轮:代码级优化 ------发现 resultSetToList 里在行循环中重复调用 ResultSetMetaData.getColumnLabel(),这可是 JDBC 驱动级操作!果断提到循环外面。还是没解决。
第四轮:祭出 Arthas------发现 Arthas 跟 Dragonwell JDK + JRebel 有兼容问题,Netty term server 绑定端口后立刻 CLOSE。Arthas 阵亡。
第五轮:JDK 内置 JFR ------启动参数居然带着 -XX:TieredStopAtLevel=1!这不等于让法拉利挂一档跑高速吗?赶紧去掉。依然没解决。
第六轮:XRebel------换上 Tomcat,XRebel 终于亮了。所有请求都在 10ms 内完成。完美!
......等等。
第三章:鬼打墙
如果 XRebel 说后端只用了 10ms,那 300ms 去哪儿了?
我盯着 Chrome DevTools 的 Network 面板,陷入了沉思:
等待服务器响应 (TTFB): 313.90 ms ← 这 313ms 在等什么?
下载内容: 8.95 ms ← 后端返回后浏览器秒收
后端 10ms 完成,浏览器却等了 313ms 才收到。中间的 300ms 凭空消失了。
那一刻我想到了所有可能的原因:
- Vite 代理层有 bug?升级 Vite,优化 proxy,装上超时处理和监控日志。
- 前端 JS 处理太慢?检查 Vue 渲染性能。
- 操作系统 TCP 栈有问题?检查 Windows 网络配置。
- 服务器 HikariCP 连接池满了?调大最小连接数。
我像个无头苍蝇一样在代码里来回乱撞。每一个可能的方向都是死胡同。
第四章:真相大白
折腾了三个小时之后,我瘫在椅子上,盯着浏览器的地址栏发呆。
然后我注意到------
地址栏里赫然写着:http://localhost:3000
等等。
我之前用 curl 直接调后端的时候,用的可是 127.0.0.1:8080。
一个念头闪过。我抄起 Chrome,在地址栏里敲下:
http://127.0.0.1:3000
回车。
页面刷出来了。我点了一下设计器。操作流畅得像在本地原生应用里一样。
我不信邪,打开 Network 面板,看了下请求耗时:
「15ms」
我揉了揉眼睛。
「12ms」
「8ms」
「6ms」
终章:localhost 的诅咒
真相让人哭笑不得:
Windows 上 localhost 不是直接走 127.0.0.1 的。
localhost 是一个 DNS 名称。Windows 会先尝试解析到 IPv6 地址 ::1,连接失败后再回退到 IPv4 的 127.0.0.1。这个 IPv6 → IPv4 回退过程 每次都要耗费 200-300ms。
而我的所有优化------索引、JOIN、列名预取、升级 Vite、换 Tomcat------它们都在正确地工作着。只是被操作系统自己给坑了。
花了一百万改装一辆赛车,结果赛道入口被一块石头堵了。
每次请求都要经历:
浏览器 → localhost (DNS解析 ::1 → 超时 → 回退 127.0.0.1) → Vite 代理 → Java 后端
↑ 白白浪费 300ms ↑ 10ms 完成
改成 127.0.0.1 后:
浏览器 → 127.0.0.1 (直连) → Vite 代理 → Java 后端
↑ 0ms ↑ 10ms 完成
教训
排查性能问题时,先看一眼浏览器的地址栏------有时候最蠢的问题隐藏在最显眼的地方。
以及,localhost 和 127.0.0.1 在 Windows 上不是一回事。
附:解决方案
| 方案 | 操作 |
|---|---|
| 立竿见影 | 浏览器地址栏用 http://127.0.0.1:3000 替代 http://localhost:3000 |
| 一劳永逸 | 修改 C:\Windows\System32\drivers\etc\hosts,确保 127.0.0.1 localhost 排在 ::1 localhost 前面 |
| 终极方案 | 禁用 IPv6(不推荐,可能影响其他网络功能) |