【问题标题】:Facing performance issue in Hazelcast with Client-Server在 Hazelcast 中面对客户端-服务器的性能问题
【发布时间】:2020-09-04 07:12:25
【问题描述】:

我在将 hazelcast 配置为客户端-服务器时遇到了性能问题。 我有一个由 5 个节点和 1 个主节点组成的 K8S 集群。每个节点有 64 GB 的 RAM 和 16 核(Hazelcast 版本 3.12.4) Hazelcast 服务器部署在 K8S 上,在集群中可用的节点之一上有一个 POD 我的客户端部署在 K8S 上,它通过智能客户端连接到 Hazelcast 之上(为 K8S 启用了 Hazelcast 发现)。我的应用程序总共有 10 个 POD,每个节点由我的应用程序的 2 个 POD 组成。

我正在运行不同的 API 并对我的应用程序执行负载测试(一次大约 110 个线程在所有 10 个 POD 之间共享)

我的应用程序中有以下代码来获取缓存。

public Map<Object, Object> get(String cacheId, Long lTenantId) {
     String strMethodName="get";
     long t1 = System.currentTimeMillis();
     Map<Object,Object> cacheDataMap=hazelcastInstance.getMap(cacheId);
     long totalTimeTaken = (System.currentTimeMillis()-t1);
     if(totalTimeTaken > 10){
         logger.warnLog(CLASSNAME, strMethodName,"Total time taken by "+cacheId+" identifier for get operation is : "+totalTimeTaken+" ms");
      }
      return cacheDataMap;
}

我的应用程序使用此地图的方式各不相同

1)

map.get(key);

2)

Set keys = map.keySet();
   Iterator iterator = keys.iterator(); //I changed to keyset iterator because entryset was causing lot of performance issues
   while (iterator.hasNext()) {
      // doing stuff
   }

当我的所有 API 都为 Load 启动时,我将这些日志打印在一个应用程序中(总时间……),其中每个缓存访问时间 > 10 毫秒,这会导致性能问题,因此我不是能够为所有 API 实现我想要的 TPS。

大约有 300 个地图存储在缓存中,缓存的总大小为 4.22 MB

我正在使用近缓存配置,并且在管理中心上它显示为 100% 的有效性。 (这是在启用 hazelcast.client.statistics.enabled 时拍摄的)。

我还尝试在 Hazelcast 服务器的 4 个节点和 1 个专用节点上部署 8 个 POD,但问题仍然存在。当我将 Hazelcast 连接为嵌入式时没有观察到任何问题,并且我能够为所有 API 实现我想要的 TPS。

我是否缺少导致此问题的任何配置或任何其他内容?

这是我的 hazelcast-client.xml

<hazelcast-client
xmlns="http://www.hazelcast.com/schema/client-config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.hazelcast.com/schema/client-config
                  http://hazelcast.com/schema/client-config/hazelcast-client-config-3.11.xsd">

<group>
<name>dev</name>
</group>
<instance-name>hazelcast</instance-name>
<properties>
<property name="hazelcast.client.shuffle.member.list">true</property>
<property name="hazelcast.client.heartbeat.timeout">600000</property>
<property name="hazelcast.client.heartbeat.interval">180000</property>
<property name="hazelcast.client.event.queue.capacity">1000000</property>
<property name="hazelcast.client.invocation.timeout.seconds">120</property>
<property name="hazelcast.client.statistics.enabled">false</property>
<property name="hazelcast.discovery.enabled">true</property>
<property name="hazelcast.map.invalidation.batch.enabled">false</property>
</properties>

<network>
<discovery-strategies>
<discovery-strategy enabled="true"
class="com.hazelcast.kubernetes.HazelcastKubernetesDiscoveryStrategy">
<properties>
<property name="service-name"><service-name></property>
<property name="namespace"><namespace></property>
</properties>
</discovery-strategy>
</discovery-strategies>
<smart-routing>true</smart-routing>
<redo-operation>true</redo-operation>
<connection-timeout>90000</connection-timeout>
<connection-attempt-period>100</connection-attempt-period>
<connection-attempt-limit>0</connection-attempt-limit>

</network>

<near-cache name="default">
                <in-memory-format>OBJECT</in-memory-format>
                <serialize-keys>true</serialize-keys>
                <invalidate-on-change>true</invalidate-on-change>
                <eviction eviction-policy="NONE" max-size-policy="ENTRY_COUNT"/>
        </near-cache>
</hazelcast-client>

这是我的 hazelcast.xml

<?xml version="1.0" encoding="UTF-8"?>

<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.11.xsd"
           xmlns="http://www.hazelcast.com/schema/config"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <management-center enabled="${hazelcast.mancenter.enabled}">${hazelcast.mancenter.url}</management-center>

</hazelcast>

【问题讨论】:

  • 您能否尝试启动多个 Hazelcast 成员作为服务器部分并检查问题是否仍然存在?
  • 感谢您的建议。尝试使用 3、4 和 5 个 Hazelcast 成员作为服务器,但无法达到我想要的 TPS。它与 Single POD 几乎相同。

标签: java performance kubernetes hazelcast hazelcast-imap


【解决方案1】:

缓存的目标是尽可能快地从键中获取值。通常,您已经拥有密钥,并请求该值。这意味着您向任何节点发送请求,这会在分区表中查找键所属的分区,并将查询转发到相关节点。

在您的第二个用例中,您尝试从所有节点获取所有密钥:

Set keys = map.keySet();
Iterator iterator = keys.iterator();
while (iterator.hasNext()) {
    // doing stuff
}

为了尽快返回,Hazelcast 将返回 Iterator 的惰性实现。对于每次调用next(),首先需要按照上述过程检索密钥。另外,我假设// doing stuff 代码实际上是从键中加载值。

总之,请不惜一切代价避免使用map.keySet()。除非我对您的上下文和用例有更多了解,否则很遗憾,我无法提供相关的替代方案。

【讨论】:

  • Yes // 在这个块中做事我访问缓存中每个项目的值。有些缓存我无法通过它的键访问,并且必须遍历所有值,直到找到我的匹配项。
  • 帮帮我:请提供更多上下文。否则,另一个替代方案很有可能解决您的问题。为什么不能通过key访问缓存?
  • 您是否看到所有 Hazelcast 服务器都成功连接并形成集群?您可以从任何服务器日志中的成员列表中确认。随后,您是否也可以确认您的客户端连接到集群中的所有服务器?同样,您可以在客户端的控制台日志中检查这一点。
  • @Nicolas 例如我有一个名为 STAFF_CACHE 的缓存,该缓存包含作为员工 ID 的键,现在我的所有 API 都可以接受员工用户名或员工 ID 作为输入参数。如果在 API 中传递员工 ID,我可以通过密钥直接访问,如果传递了用户名,那么我需要遍历缓存以找到我的员工。类似的场景还有很多。我不想创建另一个缓存,其键为员工用户名和重复数据。
  • @wildnez 是的,我可以看到所有客户端成员都在日志和管理中心连接。此外,所有 Hazelcast 服务器也在集群中通过 Hazelcast 日志验证。
【解决方案2】:

最后我设法通过一些调整来提高我的表现。我有通用代码将数据放入缓存并从缓存中访问数据。我所做的是在将数据放入最终地图之前,我又添加了一个虚拟键“ALL”。因此,当我的数据被访问时,我总是从 ALL 键中检索数据,然后对其进行迭代。虽然这不是一个适当的解决方案,但设法节省了很多努力。将此作为答案发布,可能对处于相同情况的其他人有用。

感谢大家抽出时间并帮助我寻找可能的选择。

【讨论】:

    猜你喜欢
    • 2023-03-09
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多