IMap.unlock() 与 Hazelcast 中的 EntryProcessor 和 MapListener 一起使用时的性能问题
Performance issue in IMap.unlock() when used with along with EntryProcessor and MapListener in Hazelcast
HZ 版本:3.5.3
我在 IMap.unlock(key)
中遇到性能问题,它需要大约 4-5 秒才能完成执行。场景如下:
我有一个 employeeList IMap
,它根据员工列表 (ArrayList<Employee>
) 存储 companyId
。每个值(Arraylist)可能包含 1500000 个员工。
IMap<Integer, ArrayList<Employee>> employeeListMap = hz.getMap("empList");
// adding MapListener for eviction.
employeeListMap.addEntryListener(new SimpleEvictionListener<Integer,
ArrayList<Employee>>(), false);
int companyId = 1;
ArrayList<Employee> empList = new ArrayList<>();
for(int index = 0; index < 1500000; index++)
{
empList.add(new Employee(index));
}
employeeListMap.set(companyId, empList);
// lock() takes approx 2ms.
employeeListMap.lock(key);
// EDIT: do some business logic associated with this key.
// executeOnKey() takes approx 3ms.
employeeListMap.executeOnKey(companyId, new ListEntryProcessor<Integer,
ArrayList<Employee>>());
// unlock() takes 4-5sec
employeeListMap.unlock(companyId);
employeeListMap.destroy();
Employee
是一个定义如下的POJO。
public class Employee implements Serializable
{
private static final long serialVersionUID = 1L;
protected int employeeId;
protected String name;
public Employee(int id)
{
this.employeeId = id;
this.name = "name-" + id;
}
public int getEmployeeId()
{
return employeeId;
}
public void setEmployeeId(int employeeId)
{
this.employeeId = employeeId;
}
为了添加新员工,我编写了一个条目处理器 SimpleEntryProcessor
,它将向列表中添加一个新员工并且 return 为真。
public class ListEntryProcessor<K, V> extends AbstractEntryProcessor<K, V>
{
private static final long serialVersionUID = 129712L;
public ListEntryProcessor()
{
// We need to modify the backup entries as well.
super(true);
}
@Override
public Object process(Entry<K, V> entry)
{
ArrayList<Employee> empList = (ArrayList) entry.getValue();
empList.add(new Employee(-123));
entry.setValue((V)empList);
return true;
}
}
为了在驱逐时打印钥匙,我已将以下 MapListener 添加到 employeeMap。
public class SimpleEvictionListener<K, V> implements
EntryEvictedListener<K, V>, MapEvictedListener
{
public void mapEvicted(MapEvent arg0)
{
syso("map got evicted");
}
public void entryEvicted(EntryEvent<K, V> arg0)
{
syso("entry got evicted");
}
}
IMap配置如下
<map name="empList">
<in-memory-format>OBJECT</in-memory-format>
<backup-count>0</backup-count>
<max-idle-seconds>1800</max-idle-seconds>
<eviction-policy>LRU</eviction-policy>
<time-to-live-seconds>0</time-to-live-seconds>
<max-size>51000</max-size>
<eviction-percentage>30</eviction-percentage>
<merge-policy>com.hazelcast.map.merge.PutIfAbsentMapMergePolicy</merge-policy>
</map>
在这种情况下,IMap.unlock()
需要 4-5 秒 完成执行。
当我注释掉代码 employeeListMap.addEntryListener(...)
(即没有 MapListener)时,IMap.unlock()
方法只用了 1 毫秒。
这是 hazelcast 的未决问题吗?任何指针都会有很大帮助。
注意:我知道我应该将 <employeeId, Employee>
存储在单独的 employee IMap
中,将 <companyId, <list of emp ids>
存储在不同的 companyEmps IMap
中以获得更好的结果。但是,由于代码的遗留性质,这是不可能的。
锁定时间确实很奇怪。但是当您使用 EntryProcessor 时,您不需要应用锁。 EntryProcessor 块条目,因此不会发生并发更新。
我会为这个问题创建一张票。它看起来像一个错误。
您使用的是哪个 HZ 版本?
我已将您的代码片段放入一个 class 中,以便能够轻松尝试:https://gist.github.com/gurbuzali/af8422339bfa81af9750
Hazelcast 中存在一个错误,即使您将 false
传递给 employeeListMap.addEntryListener()
以获取 includeValue
参数,该错误也会序列化该值。
由于您的值太大,问题在您的案例中变得更加明显。
以下是报告的问题和修复 PR。修复将在尚未发布的 3.5.5 中进行,但您可以尝试使用快照 3.5.5-SNAPSHOT
HZ 版本:3.5.3
我在 IMap.unlock(key)
中遇到性能问题,它需要大约 4-5 秒才能完成执行。场景如下:
我有一个 employeeList IMap
,它根据员工列表 (ArrayList<Employee>
) 存储 companyId
。每个值(Arraylist)可能包含 1500000 个员工。
IMap<Integer, ArrayList<Employee>> employeeListMap = hz.getMap("empList");
// adding MapListener for eviction.
employeeListMap.addEntryListener(new SimpleEvictionListener<Integer,
ArrayList<Employee>>(), false);
int companyId = 1;
ArrayList<Employee> empList = new ArrayList<>();
for(int index = 0; index < 1500000; index++)
{
empList.add(new Employee(index));
}
employeeListMap.set(companyId, empList);
// lock() takes approx 2ms.
employeeListMap.lock(key);
// EDIT: do some business logic associated with this key.
// executeOnKey() takes approx 3ms.
employeeListMap.executeOnKey(companyId, new ListEntryProcessor<Integer,
ArrayList<Employee>>());
// unlock() takes 4-5sec
employeeListMap.unlock(companyId);
employeeListMap.destroy();
Employee
是一个定义如下的POJO。
public class Employee implements Serializable
{
private static final long serialVersionUID = 1L;
protected int employeeId;
protected String name;
public Employee(int id)
{
this.employeeId = id;
this.name = "name-" + id;
}
public int getEmployeeId()
{
return employeeId;
}
public void setEmployeeId(int employeeId)
{
this.employeeId = employeeId;
}
为了添加新员工,我编写了一个条目处理器 SimpleEntryProcessor
,它将向列表中添加一个新员工并且 return 为真。
public class ListEntryProcessor<K, V> extends AbstractEntryProcessor<K, V>
{
private static final long serialVersionUID = 129712L;
public ListEntryProcessor()
{
// We need to modify the backup entries as well.
super(true);
}
@Override
public Object process(Entry<K, V> entry)
{
ArrayList<Employee> empList = (ArrayList) entry.getValue();
empList.add(new Employee(-123));
entry.setValue((V)empList);
return true;
}
}
为了在驱逐时打印钥匙,我已将以下 MapListener 添加到 employeeMap。
public class SimpleEvictionListener<K, V> implements
EntryEvictedListener<K, V>, MapEvictedListener
{
public void mapEvicted(MapEvent arg0)
{
syso("map got evicted");
}
public void entryEvicted(EntryEvent<K, V> arg0)
{
syso("entry got evicted");
}
}
IMap配置如下
<map name="empList">
<in-memory-format>OBJECT</in-memory-format>
<backup-count>0</backup-count>
<max-idle-seconds>1800</max-idle-seconds>
<eviction-policy>LRU</eviction-policy>
<time-to-live-seconds>0</time-to-live-seconds>
<max-size>51000</max-size>
<eviction-percentage>30</eviction-percentage>
<merge-policy>com.hazelcast.map.merge.PutIfAbsentMapMergePolicy</merge-policy>
</map>
在这种情况下,IMap.unlock()
需要 4-5 秒 完成执行。
当我注释掉代码 employeeListMap.addEntryListener(...)
(即没有 MapListener)时,IMap.unlock()
方法只用了 1 毫秒。
这是 hazelcast 的未决问题吗?任何指针都会有很大帮助。
注意:我知道我应该将 <employeeId, Employee>
存储在单独的 employee IMap
中,将 <companyId, <list of emp ids>
存储在不同的 companyEmps IMap
中以获得更好的结果。但是,由于代码的遗留性质,这是不可能的。
锁定时间确实很奇怪。但是当您使用 EntryProcessor 时,您不需要应用锁。 EntryProcessor 块条目,因此不会发生并发更新。
我会为这个问题创建一张票。它看起来像一个错误。
您使用的是哪个 HZ 版本?
我已将您的代码片段放入一个 class 中,以便能够轻松尝试:https://gist.github.com/gurbuzali/af8422339bfa81af9750
Hazelcast 中存在一个错误,即使您将 false
传递给 employeeListMap.addEntryListener()
以获取 includeValue
参数,该错误也会序列化该值。
由于您的值太大,问题在您的案例中变得更加明显。
以下是报告的问题和修复 PR。修复将在尚未发布的 3.5.5 中进行,但您可以尝试使用快照 3.5.5-SNAPSHOT