0

HZ 版本:3.5.3

我面临一个性能问题,IMap.unlock(key)大约需要 4-5 秒才能完成执行。场景如下:

我有一个employeeList IMap,它companyId根据员工列表(ArrayList<Employee>)存储。每个值 (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,它将一个新员工添加到列表中并返回 true。

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() 方法只用了 1ms

这是 hazelcast 的一个未解决的问题吗?任何指针都会有很大帮助。

注意:我知道我应该存储<employeeId, Employee>在一个单独的employee IMap<companyId, <list of emp ids>不同companyEmps IMap的地方以获得更好的结果。但是,由于代码的遗留性质,这是不可能的。

4

2 回答 2

1

锁定时间确实很奇怪。但是当您使用 EntryProcessor 时,您不需要应用锁。EntryProcessor 会阻止条目,因此不会发生并发更新。

我将为这个问题创建一张票。它看起来像一个错误。

您使用的是哪个 HZ 版本?

于 2015-10-30T14:29:12.437 回答
1

我已将您的代码片段放入一个类中,以便能够轻松尝试:https ://gist.github.com/gurbuzali/af8422339bfa81af9750

Hazelcast 中有一个错误,即使您传递false给参数employeeListMap.addEntryListener(),它也会序列化该值includeValue。由于您的值太大,问题在您的情况下变得更加明显。

以下是报告的问题和修复 PR。修复将在尚未发布的 3.5.5 中,但您可以尝试使用快照3.5.5-SNAPSHOT

https://github.com/hazelcast/hazelcast/issues/6866

https://github.com/hazelcast/hazelcast/pull/6949

于 2016-01-08T20:29:58.887 回答