与Hazelcast中的EntryProcessor和MapListener一起使用时,IMap.unlock()中的性能问题

时间:2015-10-30 14:20:57

标签: java hazelcast distributed-caching distributed-cache hazelcast-imap

HZ版本:3.5.3

我在Err = Shell("powershell.exe -ExecutionPolicy Unrestricted -File G:\OPSPDF\MergeFiles.ps1 -path "" TestString "" ", 1) 面临性能问题,大约需要4-5秒才能完成执行。方案如下:

我有一个employeeList IMap.unlock(key),它将IMap存储在员工列表中(companyId)。每个值(Arraylist)可能包含150万名员工。

ArrayList<Employee>

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(); 是POJO,定义如下。

Employee

为了添加新员工,我编写了一个条目处理器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; } ,它将新员工添加到列表中并返回true。

SimpleEntryProcessor

要在驱逐时打印密钥,我已将以下MapListener添加到employeeMap。

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;
    }
}

IMap配置如下。

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");
    }
}

在这种情况下,<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> 需要 4-5秒才能完成执行。

当我注释掉代码IMap.unlock()时(即没有MapListener),employeeListMap.addEntryListener(...) 方法只花了1毫秒

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

注意:我了解我应该将IMap.unlock()存储在单独的<employeeId, Employee>employee IMap中的不同<companyId, <list of emp ids>中以获得更好的结果。但是由于代码的遗留性质,这是不可能的。

2 个答案:

答案 0 :(得分:1)

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

我将为此问题创建一张票。它看起来像一个bug。

您使用的是哪个HZ版本?

答案 1 :(得分:1)

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

Hazelcast中存在一个错误,即使您将false传递给employeeListMap.addEntryListener() includeValue param,也会对该值进行序列化。 在您的情况下,问题变得更加明显,因为您的值太大了。

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

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

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