ehcache同步原理


最近研究ehcache同步時發現一個問題:

現有A、B兩個服務器,由A服務器向B服務器同步信息,采用RMI方式手動方式進行同步

配置信息如下:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false"
    monitoring="autodetect" dynamicConfig="true">
        
    <cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
        properties="hostName = 127.0.0.1,
                    port = 50001,
                    socketTimeoutMillis=10000" />
    
    <cacheManagerPeerProviderFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
        properties="peerDiscovery=manual, 
                     rmiUrls=//127.0.0.1:40001/clusterCache"/>
    
    <cache name="clusterCache" maxEntriesLocalHeap="999999999" eternal="false"
        timeToIdleSeconds="1800" timeToLiveSeconds="1800" overflowToDisk="false">
        <cacheEventListenerFactory 
            class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/> 
    </cache>
</ehcache> 

同步的核心代碼:

String key = StringUtils.leftPad(Thread.currentThread().getName() + a, 20, "a");
Element element = new Element(key, value);
CacheInstance.cache.put(element);

其中,value全部引用的是同一個靜態變量 static final byte[] bytes = new byte[1024*100];

測試發現問題:假設現有單個byte[1024*100],同步16000個,那么同步的數據大小為1.5G左右,但是同步過程中,通過監控B服務器的網卡,發現網卡上實際並沒有如此大的數據

 

后續經過分析得知:

  RMI協議,是有java序列化和HTTP協議構成,同步時會將同步的數據全部序列化,而放入Element的value,實際上都是對靜態變量value的引用,而ehcache同步時默認是同步1000個Element,所以這1000個Element實際上經過網卡的數據只有一個byte[1024*100]大小。

Ehcache同步源碼:

    private void writeReplicationQueue() {
        List<EventMessage> eventMessages = extractEventMessages(maximumBatchSize);

        if (!eventMessages.isEmpty()) {
            for (CachePeer cachePeer : listRemoteCachePeers(eventMessages.get(0).getEhcache())) {
                try {
                    cachePeer.send(eventMessages);
                } catch (UnmarshalException e) {
                    String message = e.getMessage();
                    if (message.contains("Read time out") || message.contains("Read timed out")) {
                        LOG.warn("Unable to send message to remote peer due to socket read timeout. Consider increasing" +
                                " the socketTimeoutMillis setting in the cacheManagerPeerListenerFactory. " +
                                "Message was: " + message);
                    } else {
                        LOG.debug("Unable to send message to remote peer.  Message was: " + message);
                    }
                } catch (Throwable t) {
                    LOG.warn("Unable to send message to remote peer.  Message was: " + t.getMessage(), t);
                }
            }
        }
    }

  其中,maximumBatchSize是本次同步Element的數量,該值可以在如下配置中進行自定義:

<cacheEventListenerFactory 
            class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
            properties = "asynchronousReplicationMaximumBatchSize=1"/> 

  其中,asynchronousReplicationMaximumBatchSize=1表示每次同步一個Element,那么此時經過網卡的流量就跟實際正常。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM