正如 Ben 指出的那样,VoltDB 将所有数据存储在堆外。堆仅用于事务路由和存储过程执行期间的暂存空间,因此每个事务的数据仅存在几毫秒,并且大多数永远不会在 GC 期间被提升或存在。实际的 SQL 执行也发生在堆外,因此临时表不会产生垃圾。
VoltDB 中的 GC 应占执行时间的 < 1%。您可以通过适当调整年轻代的大小来选择百分比。在该吞吐量下的实际部署每隔几秒就会执行一次年轻代 GC,并且 GC 应该只阻塞个位数毫秒。老一代的 GC 应该不频繁,以天为单位,并且应该只阻塞 10 毫秒。如果您想确保它们在非高峰时间发生,您可以手动调用它们。
我不明白为什么跨节点的并发 GC 很重要。最坏的情况是,如果作为事务依赖的每个节点都背靠背地执行 GC,则延迟是所涉及节点数量的总和。我建议您测量并查看它是否真的会影响一段时间内对您来说很重要的吞吐量。
在最新版本中,我们在延迟方面投入了大量精力,我可以分享其中一个 KPI。
这是一个 3 节点基准测试,50/50 读/写 32 字节密钥和 1024 字节值。有一个具有 50 个线程的客户端。基准测试期间出现节点故障,基准测试运行 30 分钟。这不是吞吐量基准,因此只有一个客户端实例具有少量线程。
Average throughput: 94,114 txns/sec
Average latency: 0.46 ms
10th percentile latency: 0.26 ms
25th percentile latency: 0.32 ms
50th percentile latency: 0.45 ms
75th percentile latency: 0.54 ms
90th percentile latency: 0.61 ms
95th percentile latency: 0.67 ms
99th percentile latency: 0.83 ms
99.5th percentile latency: 1.44 ms
99.9th percentile latency: 3.65 ms
99.999th percentile latency: 16.00 ms
如果您进一步分析这些数字并与其他事件和指标相关联,您会发现即使在高百分位数时 GC 也不是一个因素。如果您可以保持工作集较小并避免升级,Hotspot 的 ParNew 收集器非常好,即使它在延迟方面很差,但在吞吐量方面也很好。
将数据存储在堆上的数据库确实必须更加关注 GC 暂停。在 VoltDB,我们只关心它们,因为我们经常根据最大暂停时间进行评估,而不是平均暂停时间或某个百分位数的暂停时间。