3

我们正在评估一些基于 Java 的内存数据库,例如 Hazelcast 和 VoltDB。如果我们跨多个服务器复制数据,两个节点的 GC 怎么可能同时命中服务器?

例如,我们有两个具有 500 GB 内存的节点,并且我们知道 GC 启动后会极大地影响我们的性能。那么两个节点中的 GC 一起发生的概率是多少?

换句话说 - 是否可以通过某些配置来防止 GC 同时命中两个节点?我们预计每秒大约 15k 个请求的吞吐量,因此通过分布在 4 个或更多节点上,我们可以一次承受一个节点的冲击,从而获得 25% 的性能冲击和相应的大小。

4

6 回答 6

3

如果您真的想防止 GC 问题,请不要使用堆。这就是我们为 Hazelcast 添加非堆商业产品的原因。

在一般层面上:如果您保留对象的时间过长或创建对象的频率太高以至于您将它们复制到任期空间,则会出现 GC 问题。因此,许多高速应用程序首先尝试防止创建对象垃圾。

我目前正在研究 Hazelcast 的 POC 实现,其中对象创建被完全删除。

于 2014-03-20T12:52:15.727 回答
3

正如 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,我们只关心它们,因为我们经常根据最大暂停时间进行评估,而不是平均暂停时间或某个百分位数的暂停时间。

于 2014-04-24T21:45:06.567 回答
3

您无法通过任何配置同时阻止不同 JVM 中的 GC 启动。话虽如此,您应该查看您的应用程序并可以微调 GC。

于 2014-03-20T12:55:16.200 回答
1

VoltDB 将表数据存储在堆外。内存由用 C++ 编写的 SQL 执行引擎进程分配。

VoltDB 中的 Java 堆用于相对静态的部署和与模式相关的数据,以及处理请求和响应时的短期数据。甚至其中大部分都使用直接字节缓冲区和其他结构保持在堆外(在此处阅读更多信息)。

于 2014-04-24T20:25:34.750 回答
1

Assuming you're running Hazelcast/VoltDB on big(ger) servers with plenty of memory and cores, the Garbage First (G1) garbage collector in new versions of Java could largely ameliorate your concern.

http://www.oracle.com/technetwork/java/javase/tech/g1-intro-jsp-135488.html

于 2014-03-24T16:56:59.373 回答
0

对于像 Geode 一样保持一致性的内存数据库(即在释放客户端线程之前同步复制到其他节点),您的网络将比热点编译器更受关注。尽管如此,这里有两点输入可以让您达到语言无关紧要的地步:

1)如果您在读取上进行大量创建/更新:在服务器上使用堆外内存。这最大限度地减少了 GC。

2)使用Geode的C/C++和Java对象之间的序列化映射来避免JNI。具体来说,使用 DataSerializer http://gemfire.docs.pivotal.io/geode/developing/data_serialization/gemfire_data_serialization.html如果您打算广泛使用查询而不是gets/puts,请使用PDXSerializer:http ://gemfire.docs .pivotal.io/geode/developing/data_serialization/use_pdx_serializer.html

于 2017-04-19T15:10:38.937 回答