性能 ,尤其是可预测的性能,成为每个 Hazelcast 版本的更高优先级。 3.5 之前版本的性能问题之一是基准测试之间——每个基准测试都有一个新的集群——通常会有很大的性能变化,即使基准测试期间的性能相当稳定。
例如,如果我们有一个使用分布式负载/性能测试工具 Hazelcast 模拟器 运行的基本地图测试。
class=com.hazelcast.simulator.tests.map.StringStringMapTest
threadCount=40
keyLocality=Random
keyLength=20
valueLength=100
keyCount=10000
valueCount=1000
putProb=0.0
basename=map
logFrequency=100000
probe-getLatency = latency
probe-putLatency = latency
此地图测试从 IMap 中的随机成员调用 IMap.get。如果我们在旧的 4 节点测试实验室(4 个双路 Xeon Sandy Bridge Boxes 和 1 GbE 网络)上每次运行 5 分钟,然后运行 10 次,我们将获得以下数据:
Run Operations/second 1 487785.57666666666 2 412653.88 3 527906.43 4 492721.67 5 438349.95666666667 6 435373.49 7 516845.0466666667 8 457152.36666666664 9 439493.16 10 496815.06666666665 Operations/second min 412653.88 max 527906.43 avg 470509.664333333
如您所见,最小值和最大值之间的差异很大。最快的运行比最慢的运行快 28%。运行之间有如此大的性能差异非常烦人:
- 它使 Hazelcast 更难在生产环境中使用,因为很难预测性能会怎样。
- 它使性能调整几乎不可能,因为我们不知道我们是做得更快还是走运了。
在系统中添加各种临时指标以弄清楚发生了什么之后,当我们开始跟踪每个选择器处理的事件数量时,我们终于找到了金子。
class=com.hazelcast.simulator.tests.map.StringStringMapTest
threadCount=40
keyLocality=Random
keyLength=20
valueLength=100
keyCount=10000
valueCount=1000
putProb=0.0
basename=map
logFrequency=100000
probe-getLatency = latency
probe-putLatency = latency
如您所见,与其他选择器相比,第一个输入和输出选择器完全失衡。你可能会问自己,“这些选择器是做什么的?”。在 Hazelcast 中,我们将非阻塞 IO 与 选择器 结合使用。这使得仅由几个线程处理多个连接成为可能。每个选择器都由一个线程处理,默认情况下我们有 3 个输入选择器和 3 个输出选择器。如果输入线程正在等待从套接字缓冲区读取数据,它将从输入选择器接收到一个读取事件,并且“readEvents”会递增。每次输出线程接收到写入事件时,在等待套接字缓冲区中的空间可用后,'writeEvents' 就会递增。
在 4 节点集群中,每个节点应该有 3 个连接,因为节点不需要连接自己。使用 3 个输入和 3 个输出选择器,连接应完美分布在选择器上;但如您所见,事实并非如此。这种不平衡的结果是成员在选择器上获得不平衡的负载,这导致系统性能不佳。当每个节点都完美平衡时,您偶尔会获得超棒的性能,但在大多数情况下,大多数成员都存在不平衡。
为什么会出现不平衡?
下一个要回答的问题是为什么会发生不平衡?答案在于 Hazelcast 节点的并发启动。当节点尚未形成集群时,它们会尝试连接到所有其他众所周知的 IP 地址,这可能会导致成员之间在尝试相互联系时出现重复连接。最后,只使用了一个连接,但是这个重复的连接导致循环连接到选择器分配机制出现问题。
为了证明这个理论,我添加了一个默认情况下禁用的 hack,它强制来自单个主机的连接始终以相同的选择器结束。可以使用以下 JVM 设置“-Dhazelcast.selectorhack.enabled=true”在 Hazelcast 3.4 中启用 hack。它应该只用于实验目的。
在我添加 hack 并进行了一些基准测试之后,选择器现在达到了完美的平衡:
class=com.hazelcast.simulator.tests.map.StringStringMapTest
threadCount=40
keyLocality=Random
keyLength=20
valueLength=100
keyCount=10000
valueCount=1000
putProb=0.0
basename=map
logFrequency=100000
probe-getLatency = latency
probe-putLatency = latency
但是 selector-hack 对性能有什么样的影响呢?当我们再次运行它时,但启用了 selector-hack,我们得到以下数据:
Run Operations/second 1 568136.3033333333 2 580225.72 3 550599.2766666666 4 560531.0966666667 5 548103.9666666667 6 544054.8133333334 7 554470.4433333334 8 539209.21 9 552880.8966666666 10 532643.53 Operations/second min 532643.53 max 580225.72 avg 553085.525666667
最小值和最大值之间的性能差异仅为 9%;将其与禁用 hack 时 28% 的性能差异进行比较。除此之外,平均吞吐量增加了 18%!
偶尔禁用 selector-hack 后,如果没有不平衡,您将获得非常好的性能。启用 selector-hack 后,您将始终获得这种良好的性能。
IO平衡器
在 Hazelcast 3.5 中,我们用称为 IO-balancer 的适当解决方案替换了 selector-hack。它定期检查选择器并检查不平衡。如果检测到不平衡,则将最忙的选择器中至少有 2 个连接的最忙连接迁移到最不忙的选择器。默认情况下,IO 平衡器每 20 秒检查一次此类可迁移连接,但这可以使用“-Dhazelcast.io.balancer.interval.seconds=seconds”属性进行更改。如果设置为负值,IO 平衡器将被禁用。
IO 平衡器不仅对并发节点启动问题有用;它在成员加入和离开集群的环境中也非常有用。在某个时间点处于完美平衡状态的东西,如果某个成员加入或离开,稍后可能会失去平衡。另一件很酷的事情是客户端依赖于与成员相同的连接机制,所以他们也得到了重新平衡!在大多数情况下,客户端不如集群成员持久。
在 Hazelcast 3.6 中,我们将包含一个名为“指标”的新功能。它会公开各种内部探测器并定期将其记录到文件中。这应该提供很多关于正在发生的事情的洞察力。当然,选择器是度量系统中的关键探针之一。
敬请关注!
别忘了,您可以获得 30 天的免费试用期来查看 Hazelcast Enterprise!
现在下载 ”