キャッシュライブラリのEhcacheの情報を、JMXで取得する方法について。
まあ、基本的にはこのページの通りです。
JMX Management and Monitoring
http://ehcache.org/documentation/operations/jmx
例ではJConsoleを使っていますが、ここではGroovyを使って値を取得します。
まずは、監視される側のプログラム。
ehcache-server.groovy
import java.lang.management.ManagementFactory @Grab('net.sf.ehcache:ehcache:2.7.2') import net.sf.ehcache.Cache import net.sf.ehcache.CacheManager import net.sf.ehcache.Element import net.sf.ehcache.management.ManagementService def cacheManager = CacheManager.create() def mbeanServer = ManagementFactory.platformMBeanServer ManagementService.registerMBeans(cacheManager, mbeanServer, false, false, true, true) def cache = cacheManager.getCache('simpleCache') (1 .. 10).step(2).each { cache.put(new Element("key${it}".toString(), "value${it}".toString())) } (1 .. 10).each { cache.get("key${it}".toString()) } while (true) { Thread.sleep(3 * 1000L) } cacheManager.shutdown()
設定ファイルは、こんな感じです。
ehcache.xml
ehcache.xml <?xml version="1.0" encoding="UTF-8"?> <ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap" /> </defaultCache> <cache name="simpleCache" maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap" /> </cache> </ehcache>
ちなみに、この設定ファイルのcacheの属性に
statistics="true"
みたいなことが書けますが、JMXとは関係ないようです…。
プログラムのポイントは、作成したCacheManagerをManagementService#registerMBeansに登録すること。
自分で。
def cacheManager = CacheManager.create() def mbeanServer = ManagementFactory.platformMBeanServer ManagementService.registerMBeans(cacheManager, mbeanServer, false, false, true, true)
registerMBeansの後ろの方に、4つboolean引数が付いていますが、これは順に
- CacheManagerをMBeanとして登録する
- CacheをMBeanとして登録する
- Cacheの設定情報をMBeanとして登録する
- Cacheの統計情報をMBeanとして登録する
となります。CacheManagerをMBeanに登録すると停止などができたり、Cacheを登録するキャッシュの全クリアができたりしますが、そんなに便利ではなさそうなのでfalseにしています。
ManagementService
http://ehcache.org/apidocs/net/sf/ehcache/management/ManagementService.html
実際、ドキュメントの例でも統計情報しか有効化されていません。
で、Rangeのstepに2を入れて、5つ要素を登録して、その後10つ取得しようとします。
(1 .. 10).step(2).each { cache.put(new Element("key${it}".toString(), "value${it}".toString())) } (1 .. 10).each { cache.get("key${it}".toString()) }
Cacheには、5つしか要素が入っていないので、キャッシュミスが5回発生することになるはずです。
では、このプログラムに浮いててもらいます。
$ export JAVA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9012 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false" $ groovy ehcache-server.groovy SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
では、MBeanの情報を取得するプログラム。前回作ったGroovyスクリプトの簡易版です。
ehcache-monitor.groovy
import javax.management.ObjectName import javax.management.remote.JMXConnectorFactory import javax.management.remote.JMXServiceURL def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:9012/jmxrmi' def serviceUrl = new JMXServiceURL(serverUrl) def connector = JMXConnectorFactory.connect(serviceUrl) def printMonitor = { mbean -> def format = { collection -> collection .collect { " Name: [$it]${System.lineSeparator()}" } .join('') } def formatAttributes = { names -> names .collect { name -> " Name: [$name], " + "Value: [${mbean.getProperty(name)}]" + "${System.lineSeparator()}" } .join('') } def attributes = formatAttributes(mbean.listAttributeNames()) def operations = format(mbean.listOperationNames()) def operationDescriptions = format(mbean.listOperationDescriptions()) def mbeanInfo = """|[MBean] | Name: ${mbean.name()} | Attributes: |${attributes} | Operations: |${operations} | OperationDescriptions: |${operationDescriptions}""".stripMargin() println(mbeanInfo) } def monitor = { server, query -> def modules = server .queryNames(query, null) .collect { objectName -> new GroovyMBean(server, objectName) } modules.each(printMonitor) } try { def query = new ObjectName('net.sf.ehcache:*') def server = connector.MBeanServerConnection monitor(server, new ObjectName('net.sf.ehcache:type=CacheStatistics,*')) monitor(server, new ObjectName('net.sf.ehcache:type=CacheConfiguration,*')) } finally { connector.close() }
クエリの範囲は、ちょっと絞っています。
monitor(server, new ObjectName('net.sf.ehcache:type=CacheStatistics,*')) monitor(server, new ObjectName('net.sf.ehcache:type=CacheConfiguration,*'))
実行。
$ groovy ehcache-monitor.groovy
出力結果。まずは、統計情報から。
[MBean] Name: net.sf.ehcache:type=CacheStatistics,CacheManager=__DEFAULT__,name=simpleCache Attributes: Name: [AssociatedCacheName], Value: [simpleCache] Name: [WriterQueueLength], Value: [0] Name: [OnDiskHits], Value: [0] Name: [CacheMisses], Value: [5] Name: [OffHeapHits], Value: [0] Name: [InMemoryHits], Value: [5] Name: [CacheHits], Value: [5] Name: [OnDiskMisses], Value: [5] Name: [ObjectCount], Value: [5] Name: [WriterMaxQueueSize], Value: [0] Name: [MemoryStoreObjectCount], Value: [5] Name: [OffHeapStoreObjectCount], Value: [0] Name: [DiskStoreObjectCount], Value: [5] Name: [CacheHitPercentage], Value: [0.5] Name: [CacheMissPercentage], Value: [0.5] Name: [InMemoryHitPercentage], Value: [0.5] Name: [OffHeapHitPercentage], Value: [0.0] Name: [OnDiskHitPercentage], Value: [0.0] Name: [InMemoryMisses], Value: [5] Name: [OffHeapMisses], Value: [0] Operations: OperationDescriptions:
登録されているオブジェクトが5個であることや、キャッシュヒット率やキャッシュミス率が確認できます。
その他、設定情報。
[MBean] Name: net.sf.ehcache:type=CacheConfiguration,CacheManager=__DEFAULT__,name=simpleCache Attributes: Name: [Name], Value: [simpleCache] Name: [Eternal], Value: [false] Name: [TerracottaClustered], Value: [false] Name: [MemoryStoreEvictionPolicy], Value: [LRU] Name: [MaxBytesLocalHeap], Value: [0] Name: [MaxBytesLocalDisk], Value: [0] Name: [OverflowToOffHeap], Value: [false] Name: [OverflowToDisk], Value: [true] Name: [TimeToIdleSeconds], Value: [120] Name: [TimeToLiveSeconds], Value: [120] Name: [MaxEntriesLocalHeap], Value: [10000] Name: [MaxEntriesLocalDisk], Value: [10000000] Name: [DiskExpiryThreadIntervalSeconds], Value: [120] Name: [MaxBytesLocalOffHeap], Value: [0] Name: [DiskPersistent], Value: [false] Name: [MaxElementsInMemory], Value: [10000] Name: [DiskSpoolBufferSizeMB], Value: [30] Name: [MaxElementsOnDisk], Value: [10000000] Name: [MaxMemoryOffHeapInBytes], Value: [0] Name: [TerracottaConsistency], Value: [na] Name: [LoggingEnabled], Value: [false] Operations: OperationDescriptions: