Dev (Back & Front)ARTIGO

Cache Distribuído com REST e EHCache Server no JBoss AS

As aplicações que desenvolvemos hoje são cada vez mais complexas. Essa complexidade se deve a muitos fatores que vão desde a globalização até a evolução da forma como as empresas fazem B2B e B2C.

Muitas vezes, o banco de dados acaba sendo um gargalo. Uma vez que a sua rede está 100% ok, uma forma viável de reduzir a carga no banco de dados é utilizar alguma forma de cache. Se esse cache tiver *hit*, ou seja, acertos em uma taxa considerável, isso pode trazer muitas vantagens para a sua aplicação.

Cache com EHCache

EHCache é um solução open source de cache para Java. O EHCache lhe permite fazer vários tipos de cache, como por exemplo aplicar cache junto ao Hibernate/JPA, cache de páginas web usando GZIP e até mesmo cache distribuído, que é o tema deste post.


EHCache – Arquitetura Modular

O EHCache tem uma arquitetura modular, logo, você pode escolher os módulos que deseja utilizar. Neste post vou mostrar como trabalhar com o Cache Server.

REST EHCache Server

Quando precisamos trabalhar com cache distribuído, existem duas opções com o EHCache. A primeira é utilizar o cluster do próprio Terracota (solução de cache distribuído da Terracota, empresa que comprou o EHCache 🙂 ); a outra opção é usar o cache Server.

O Cache Server tem uma API REST muito bacana. O mais legal disso é que como REST funciona em cima de http, você pode consumir o Cache Server com qualquer linguagem/tecnologia. Por exemplo, você poderia ter cache distribuído para várias aplicações escritas em linguagens diferentes e rodando em diverentes sistemas operacionais distribuídos pelo mundo.

Outro ponto a favor de o Cache Server ser em REST é que com isso podemos usar as soluções de loadbalance e até mesmo DNS, isso porque ele vai ficar rodando em um servidor de aplicação parão JEE. Por default, o REST Server vem empacotado em uma distribuição standalone que roda com um Glassfish embutido. Neste post, vou mostrar como adaptar o REST EHCache Server para rodar no JBoss AS 5.

Ajustes para Rodar no JBoss AS 5.x

Primeiro você precisa baixar o ehcache server, depois disso vamos deletar algumas bibliotecas e adicionar outras. Essa é a unica modificação que precisamos fazer para rodá-lo no JBoss AS. Neste post, vou utilizar a versão 1.0.0.

Entre na pasta onde você extraiu o cache server – vou me referir a essa pasta como $Download. Depois entre na seguinte pasta: $Download/war/WEB-INF/lib e delete os seguintes jars:

  • activation-1.1.jar
  • jaxb-api-2.0.jar
  • jaxb-impl-2.1.9.jar
  • stax-api-1.0.jar
  • resolver-20050927.jar

Agora gere um war com todo o conteúdo das pastas WEB-INF e META-INF, pode ser usando as ferramentas do Java, pode ser com o seu IDE, eu fiz isso usando o winrar. 😀

Faça o deploy no JBoss AS 5.x e se divirta muito!

Manipulando o Servidor de Cache com REST

Agora vou mostrar como criar aréas de cache no REST Cache Server do EHCache e como adicionar e recuperar objetos desse cache. Para isso, vou utilizar dois frameworks que são o XStream e o HttpClient. Então vamos à classe genérica que criei para manipular o cache server, que chamei  carinhosamente de HttpClientRESTBaby.

/**<br /> * <br /> * @author Diego Pacheco<br /> *<br /> */<br />public class MainRESTBabyRules {<br /><br />    public static void main(String[] args) throws Throwable {<br /><br />        HttpClientRESTBaby restBaby = new HttpClientRESTBaby();<br />        restBaby.createCache("cacheName1");<br />        restBaby.getCache("cacheName1");<br /><br />        People p1 = new People();<br />        p1.setId(1l);<br />        p1.setName("Diego Pacheco");<br /><br />        restBaby.addEntry("cacheName1", p1.getId().toString(), p1);<br /><br />        String result = restBaby.getEntry("cacheName1", p1.getId().toString());<br /><br />        People p2     = (People) new XStream().fromXML(result);<br />        System.out.println("P2: " + p2.toString());<br />        System.out.println("p1 is equals p2 ? " + p1.equals(p2)  );<br /><br />    }<br />}

Nessa classe, estou disponibilizando os seguintes métodos:

  • createCache(String cacheName)
  • getCache(String cacheName)
  • addEntry(String cacheName,String key,Serializable value)
  • getEntry(String cacheName,String key)

createCache: Cria uma área de cache dentro do cache server, você chama uma vez e ele cria a área. Se você chamar de novo, ele vai retornar um conflito, porque o cache já foi criado no server.

getCache: Retorna um XML no padrão EHCache com a configuração de cache que está associada a essa área de cache no server.

addEntry: Adiciona um elemento ao cache. Perceba que é uma combinação de chave/valor, onde a chave deve ser única. A chave vai acabar sendo parte do URL REST, e o valor deve ser Serializable, logo, você pode, sim, passar um Objeto do seu domínio da sua aplicação como um pojo de pessoa.

getEntry: Retorna uma entrada do cache a partir de uma chave. Essa chave deve existir no servidor de cache, do contrário você não terá o valor desejado. Neste caso, estou retornando o xml do Xstream que define o objeto, seria possível configurar o XStream para gerar JSon. A vantagem disso é que o EHCache server entende o content type de JSon. 😀

Algumas considerações sobre o código

A constante REST_CACHE_SERVER define onde está o servidor de cache. Perceba que o nome da aplicação web(.war) faz parte do url. Caso você tenha empacotado com outro nome, não se esqueça de modificar esse valor, bem como se você estiver usando-o em outra porta.

Um teste básico

Agora podemos subir o JBoss AS com o servidor de cache dentro dele. Vamos a um simples código de testes para verificar se tudo está funcionando como deveria estar. Confira o código abaixo:

/**<br /> * <br /> * @author Diego Pacheco<br /> *<br /> */<br />public class MainRESTBabyRules {<br /><br />    public static void main(String[] args) throws Throwable {<br /><br />        HttpClientRESTBaby restBaby = new HttpClientRESTBaby();<br />        restBaby.createCache("cacheName1");<br />        restBaby.getCache("cacheName1");<br /><br />        People p1 = new People();<br />        p1.setId(1l);<br />        p1.setName("Diego Pacheco");<br /><br />        restBaby.addEntry("cacheName1", p1.getId().toString(), p1);<br /><br />        String result = restBaby.getEntry("cacheName1", p1.getId().toString());<br /><br />        People p2     = (People) new XStream().fromXML(result);<br />        System.out.println("P2: " + p2.toString());<br />        System.out.println("p1 is equals p2 ? " + p1.equals(p2)  );<br /><br />    }<br />}

Ao rodar esse código, você deve ver a seguinte saída no console:

++http://localhost:8080/ehcache-server-jboss-1.0.0/rest/cacheName1<br /> +Result[<br /><br /> +]<br /> +201<br /> +Created<br /> +HTTP/1.1 201 Created<br /><br />++http://localhost:8080/ehcache-server-jboss-1.0.0/rest/cacheName1<br /> +Result[<br />  <?xml version="1.0" encoding="UTF-8" standalone="yes"?><cache><cacheConfiguration><clearOnFlush>true</clearOnFlush><diskAccessStripes>1</diskAccessStripes><diskExpiryThreadIntervalSeconds>120</diskExpiryThreadIntervalSeconds><diskPersistent>false</diskPersistent><diskSpoolBufferSizeMB>30</diskSpoolBufferSizeMB><diskStorePath>C:\Users\DIEGOP~1\AppData\Local\Temp\</diskStorePath><eternal>false</eternal><loggingEnabled>false</loggingEnabled><maxElementsInMemory>10000</maxElementsInMemory><maxElementsOnDisk>10000000</maxElementsOnDisk><name>cacheName1</name><overflowToDisk>true</overflowToDisk><statistics>true</statistics><timeToIdleSeconds>120</timeToIdleSeconds><timeToLiveSeconds>120</timeToLiveSeconds></cacheConfiguration><description>[ name = cacheName1 status = STATUS_ALIVE eternal = false overflowToDisk = true maxElementsInMemory = 10000 maxElementsOnDisk = 10000000 memoryStoreEvictionPolicy = LRU timeToLiveSeconds = 120 timeToIdleSeconds = 120 diskPersistent = false diskExpiryThreadIntervalSeconds = 120 cacheEventListeners: net.sf.ehcache.statistics.LiveCacheStatisticsWrapper  hitCount = 0 memoryStoreHitCount = 0 diskStoreHitCount = 0 missCountNotFound = 0 missCountExpired = 0 size = 0 ]</description><name>cacheName1</name><statistics><averageGetTime>0.0</averageGetTime><cacheHits>0</cacheHits><diskStoreSize>0</diskStoreSize><evictionCount>0</evictionCount><inMemoryHits>0</inMemoryHits><memoryStoreSize>0</memoryStoreSize><misses>0</misses><onDiskHits>0</onDiskHits><size>0</size><statisticsAccuracy>STATISTICS_ACCURACY_BEST_EFFORT</statisticsAccuracy></statistics><uri>http://localhost:8080/ehcache-server-jboss-1.0.0/rest/cacheName1</uri></cache><br /> +]<br /> +200<br /> +OK<br /> +HTTP/1.1 200 OK<br /><br />++http://localhost:8080/ehcache-server-jboss-1.0.0/rest/cacheName1/1<br /> +Result[<br /><br /> +]<br /> +201<br /> +Created<br /> +HTTP/1.1 201 Created<br /><br />++http://localhost:8080/ehcache-server-jboss-1.0.0/rest/cacheName1/1<br /> +Result[<br />  <com.blogspot.diegopacheco.cache.playground.cacheserver.rest.domain.People><br />  <id>1</id><br />  <name>Diego Pacheco</name><br /></com.blogspot.diegopacheco.cache.playground.cacheserver.rest.domain.People><br /> +]<br /> +200<br /> +OK<br /> +HTTP/1.1 200 OK<br /><br />P2: ID: 1, Name: Diego Pacheco<br />p1 is equals p2 ? true

Se você quiser, pode pegar os fontes completos, bem como o projeto do eclipse no meu repositório do subversion na web. Espero que você tenha gostado e que também tire proveito do cache server em suas aplicações.

Abraços.

é Técnico em Processamento de Dados e graduando em Ciências da Computação(7º sem.) na Ulbra. Já trabalhou com desenvolvimento de software em VB, ASP, .NET e PHP. Atualmente é Arquiteto de Software criando soluções corporativas em Java. Certificado pela SUN com SCJP 5 e SCWD 5. Mantém o blog (diego-pacheco.blogspot.com).

Ver perfil