จริงๆไม่ได้เกี่ยวกับสปริงตรงๆครับแต่เกี่ยวทางอ้อมๆ เพราะในกรณีที่เรานำแอพพลิเคชั่นของเราไปวางไว้บนคลัสเตอร์แล้วเราต้องการให้ข้อมูลที่อยู่ในโลคอลแคชของเราเหมือนกันทุกเราจะทำยังไง? แน่นอนปัญหาพวกนี้ไม่ได้เพิ่งเิกิดขึ้นกับเราคนแรก มันมักจะมีคนอื่นแก้ไว้ให้แล้วเสมอ ดังนั้นอย่าเทพ ไปแก้ปัญหาเหล่านี้ด้วยการเขียนเองทั้งหมด
หลังจากไล่อ่านเอกสารของอีเฮชแคชไปได้สามรอบผลคือรู้ว่ามันทำได้ห้าวิธีคือ อาร์เอ็มไอ(RMI),เจกรุ๊ป(JGroups),เจเอ็มเอส(JMS),เทอรราคอตต้า(Terracotta)และแคชเซิร์ฟเวอร์(Cache Server)
แต่เท่าที่ไล่ดูจากเอกสารแล้วที่พอจะเอาได้ไล่ออกจากเอกสารแย่ๆของอีเฮชแคชนั้น สรุปได้ว่าอาร์เอ็มไอ ดูเข้าท่าที่สุดเพราะเนื่อหาดูท่าจะอ่านรู้เรื่องที่สุดแต่หลังจากที่อ่านไปอีกสามรอบก็ ห่านนนนนนน อ่านไม่รู้เรื่องแต่โชคดีที่มีลิงค์เล็กที่ท้ายระบุว่าถ้าอยากชมการทำงานเรื่องของการเรพพลิเขตข้อมูลให้ไปดูที่ยูนิตเทสท์ ==”แต่ต้องยอมรับว่ายูนิตเทสท์เค้าเทพมากๆ ถึงแม้ว่าอ่านรอบแรกจะไม่รู้เรื่องเลยก็ตาม แต่หลังจากรื้อๆค้นแก้ไปแก้มาก็เห็นภาพชัดเจนโดยสามารถสรุปได้ดังนี้
สิ่งที่ต้องมีเพิ่มในคอนฟิกกูเรชั่นไฟล์
1.เพียร์โพรไวด์เดอร์ (PeerProvider)
2.แคชเมเนเจอร์เพียร์ลิสท์ซึนเนอร์ (CacheManagerPeerListener)
โดยเราสามารถเพิ่มลงไปได้ดังนี้
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="hostName=,
peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446,
timeToLive=64"/>
ส่วนของเพียร์โพรไวด์เดอร์มีหน้าที่ระบุว่าแต่ละแคชนั้นเป็นเพียร์ต่อกันไม่มีตัวใดตัวหนึ่งเป็นมาสเตอร์ และแต่ละเพียร์จะสื่อสารกันผ่านมัลติคาสท์กรุ๊ปแอดเดรส(MulticastGroupAddress)ด้วยการค้นหาแบบอัตโนมัติซึ่งเป็นวิธีที่ง่ายและสะดวกที่สุด ดังนั้นในกรณีของเราเราสามารถใส่ค่านี้ลงไปในคอนฟิกกูเรชั่นไฟล์ได้ทั้งสองเครื่องเหมือนๆกัน ส่วนต่อไปคือแคชเมเนเจอร์เพียร์ลิสท์ซึนเนอร์
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=,
port=40001,
remoteObjectPort=47000,
socketTimeoutMillis="/>
แคชเมเนเจอร์เพียร์ลิสท์ซึนเนอร์ทำหน้าที่คอยฟังสัญญาณจากเพียร์ต่างๆและส่งต่อไปให้แคชเมเนเจอร์ตัวปัจจุบัน
ส่วนต่อไปคือเราต้องกำหนดการทำเรพพลิเคเตอร์ที่แคชเมเนเจอร์ของเราว่าต้องการให้ทำงานในโหมดไหน ในที่นี้เราจทำเป็นแบบซิงค์โครนัส และยอมรับการเปลี่ยนแปลงทุกชนืดที่เกิดขึ้นในแคชไม่ว่าจะเป็นการ แก้ไข ลบ หรือเพิ่ม ข้อมูล
<cache name="getUserById"
maxElementsInMemory="10"
eternal="true"
overflowToDisk="true">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=false,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true "/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
ดังนั้นหลังจากที่เราทำการกำหนดค่าต่างๆไว้เรียบร้อยแล้วเราจะสามารถทดสอบการทำเรพพลิเขตข้อมูลข้ามแคชได้ด้วยการเขียนยูนิตเทสท์ดังนี้
@Before
public void setUp() throws Exception {
MulticastKeepaliveHeartbeatSender.setHeartBeatInterval(1000);
CountingCacheEventListener.resetCounters();
manager1 = new CacheManager(AbstractCacheTest.TEST_CONFIG_DIR + "distribution/ehcache-distributed1.xml");
manager2 = new CacheManager(AbstractCacheTest.TEST_CONFIG_DIR + "distribution/ehcache-distributed2.xml");
//allow cluster to be established
Thread.sleep(1020);
cache1 = manager1.getCache(cacheName);
cache1.removeAll();
cache2 = manager2.getCache(cacheName);
cache2.removeAll();
//enable distributed removeAlls to finish
waitForPropagate();
}
@Test
public void testBigPutsProgagatesSynchronous() throws CacheException, InterruptedException {
//Give everything a chance to startup
StopWatch stopWatch = new StopWatch();
Integer index;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 1000; j++) {
index = new Integer(((1000 * i) + j));
manager2.getCache("sampleCache3").put(new Element(index,
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
}
}
long elapsed = stopWatch.getElapsedTime();
long putTime = ((elapsed / 1000));
LOG.log(Level.INFO, "Put and Propagate Synchronously Elapsed time: " + putTime + " seconds");
assertEquals(2000, manager1.getCache("getUserById").getSize());
waitForPropagate();
assertEquals(2000, manager2.getCache("getUserById").getSize());
}
