本文探讨了在简单的 `Arrays.fill` 基准测试中,G1GC 与 ParallelGC 之间存在的显著性能差异,其中 G1GC 的速度慢了 200 多倍。 **调查结果:** * **罪魁祸首:** 性能损耗是由 **G1 写屏障(Write Barrier)** 引起的。ParallelGC 使用简单的无条件存储,而 G1 则会执行复杂的屏障逻辑来跟踪对象引用。 * **屏障开销:** 当数组位于“老年代”时,G1 的屏障会执行一条包含**全内存屏障(`dmb ish`)**的“慢速路径”,以确保跨核心的内存可见性。该屏障会阻塞 CPU,从而使存储并行化失效。 * **触发条件:** 当向老年代数组中存储非空引用时,会触发此性能损耗。被分配为“巨型对象(Humongous Object)”只是进入老年代的捷径;任何长寿的数组最终都会产生这种开销。 * **影响:** 性能随数组增大而急剧下降,从缓存范围内的较小损耗演变为大型数组约 100 倍的减速。 **解决方案:** * 使用 `Arrays.fill(a, null)` 或 `System.arraycopy`,它们可以绕过昂贵的屏障逻辑。 * **升级至 JDK 26:** 新的 G1 卡表实现(JEP 522)完全移除了对内存屏障的需求,消除了这一特定的性能瓶颈。
这篇文章指出,“横向扩展性”常被误解为一种通用属性,但实际上它是一种依赖于工作负载的权衡。许多分布式数据库(如 CockroachDB)通过跨节点分布数据来实现横向扩展,却为此付出了沉重的“协调开销”代价,这显著降低了性能,尤其是在存在资源争用的情况下。
Spacetime 采用了不同的方法:它优先考虑高性能的单线程执行。通过保持事务的快速、本地化且无需分布式协调带来的锁,它避免了过早分布式所带来的陷阱。Spacetime 通过将数据库视为独立的、串行的“参与者”(actors)来实现扩展。
Spacetime 的横向演进路线图——最终将于 2026 年 10 月 31 日发布重大版本——包括:
1. **复制数据库**:通过状态机复制实现高性能。
2. **分片**:明确分片边界,以保持常规事务的本地化。
3. **分层存储**:利用对象存储来突破内存限制。
4. **分区**:在单个数据库内管理负载。
其核心哲学是“零开销原则”:在开发者的具体工作负载需要分布式系统之前,不应为其复杂性买单。通过将大部分工作保持在本地,Spacetime 在确保性能的同时,仅在真正需要时才提供扩展工具。