Asdfasf

Thursday, September 20, 2012

Blogger Code Formatter

Blog'da yayinladigimiz kaynak kodlari formatlamak icin oldukca kullanisli bir formatter:

http://hilite.me/

Yakisikli kod'lar dilegiyle.

Pooling and Reusing JAX-WS Client Ports


Load test'leri icin hazirladigim bir simulator uygulamasinda, load altinda kisa bir sure sonra uygulamadan server'a yapilan webservice isteklerinde gecikmeler farkettik. Simulator uygulamasi, apache tomcat'da calisan bir web uygulamasi ve webservis istekleri icin jax-ws ile urettigimiz client kod'u kullaniyor.
Cagri yapan kod asagidaki gibi, her istek oncesinde servis ve port yaratip istekte bulunuyor


 public void callServer(){  
      XXXService service = new XXXService();  
      XXXServicePortType port = service.getXXXServiceHttpSoap11Endpoint();  
      WsUtil.setEndpointAdress(port, TestManager.SERVER_URL);  
      Response response = null;  
      try {  
           response = port.callServer();  
      } catch (SOAPFaultException e) {  
      }  
 }  
 public static void setEndpointAdress(final Object port, final String newAddress) {  
     final BindingProvider bp = (BindingProvider) port;  
     bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, newAddress);  
 }  

Sorunun nedenini bulmak, gecikme ve beklemelerin neden kaynaklandigini anlamak icin simulator uygulamasinin thread dump'ini inceledim.

 jstack <process Id>  

thread dump'in soyledigi, thread'lerin yeni servis objesi yaratirken, WSDL definition'ini yuklerken bekledikleri


 "pool-1-thread-400" prio=3 tid=0x0000000002101800 nid=0x215 waiting for monitor entry [0xfffffd7ff2c35000]  
   java.lang.Thread.State: BLOCKED (on object monitor)  
     at org.apache.axis2.jaxws.ClientConfigurationFactory.getClientConfigurationContext(ClientConfigurationFactory.java:88)  
     - waiting to lock <0xfffffd7f8626c060> (a org.apache.axis2.jaxws.ClientConfigurationFactory)  
     at org.apache.axis2.jaxws.description.impl.DescriptionFactoryImpl.createServiceDescription(DescriptionFactoryImpl.java:92)  
     at org.apache.axis2.jaxws.description.impl.DescriptionFactoryImpl.createServiceDescription(DescriptionFactoryImpl.java:79)  
     at org.apache.axis2.jaxws.description.DescriptionFactory.createServiceDescription(DescriptionFactory.java:76)  
     at org.apache.axis2.jaxws.spi.ServiceDelegate.<init>(ServiceDelegate.java:212)  
     at org.apache.axis2.jaxws.spi.Provider.createServiceDelegate(Provider.java:59)  
     at javax.xml.ws.Service.<init>(Service.java:56)  
     at com.xxx.xxx.xxx.XXXService.<init>(XXXService.java:47)  


Kisaca, her webservice istegi oncesi yeni servis ve port objesi olusturup, WSDL definition'ini yukletmek ve yuklerken alt tarafta kuvvetle muhtemel syncronized bir block'ta zaman kaybetmek pekte mantikli degil.

Pooling bir cozum olacaktir.

Uygulama ayaga kalkarken, kullanacagimiz port'lari ihtiyacimiz kadar yaratip bir queue'da tutmak ve bu havuzdan kullanmak, kullandiktan sonra queue'ya baskalarinin kullanmasi icin koymak uygun olacaktir.


 static BlockingQueue<XXXServicePortType> portQueue = new LinkedBlockingQueue<XXXServicePortType>();  
 public static void initialize() {  
      try {  
           long start = System.currentTimeMillis();  
           int portCount = Integer.parseInt(TestManager.PORT_POOL_COUNT.trim());  
           for (int i = 0; i < portCount; i++) {  
                XXXService service = new XXXService();  
                XXXServicePortType port = service.getXXXServiceHttpSoap11Endpoint();  
                WsUtil.setEndpointAdress(port, TestManager.SERVER_URL);  
                try {  
                     portQueue.put(port);  
                } catch (InterruptedException e) {  
                     e.printStackTrace();  
                }  
           }  
           TestManager.debug("Producing ports took " + (System.currentTimeMillis() - start));  
      } catch (Exception e) {  
           TestManager.error("", e);  
      }  
 }  
 public void callServer(){  
      XXXServicePortType port = null;  
      Response response = null;  
      try {  
           long l = System.currentTimeMillis();  
           port = portQueue.take();        
           TestManager.debug("Taking port took:[" + (System.currentTimeMillis() - l) + " msec");                 
           response = port.callServer();  
      } catch (InterruptedException e) {  
           e.printStackTrace();  
      } finally{  
           if (port != null){  
                try {  
                     portQueue.put(port);  
                } catch (InterruptedException e) {  
                     e.printStackTrace();  
                }  
           }  
      }  
 }  


Pooling bize gozle gorulur, ciddi bir iyilesme kazandirdi. Ek olarak her bir port ve kullandigi fiziksel connection arasindaki iliskiden bahsetmek gerekirse:

netstat -n komutu ile load sirasinda server'a kurulan fiziksel baglanti'lari inceledigimde sunu gordum. Pool kullandigimizda, cagrilan url ayni oldugu durumda, port sayisinca connection yaratildigini ve operating system tarafindan canli tutuldugunu gordum. Havuzdaki client port objeleri, canli tutulan bu fiziksel http connection'larini her seferinde kullaniyorlar.

Cagrilan url'i anlik olarak degistirdigim durumda ise operating system yeni bir connection yaratiyor ve port objesi bu yeni connection uzerinden http call yapiyor. Bir sekilde fiziksel connection yonetimi operating system tarafindan yapiliyor ve kisaca port objesinin o anda cagiracagi ip:port icin hazirda bir http connection var ise o kullaniliyor, yok ise yaratiliyor.

SONUC OLARAK:

Webservice cagrisinda asil maliyetli olan service ve port objelerini her seferinde yaratip servis tanimini (WSDL dosyasini) yukletmek oldugunu gorduk, ve bunun yerine port objelerini ayaga kalkarken yaratip bir havuzda tutup tekrar tekrar kullanmak cozumunu uyguladik.

Fiziksel http connection yonetimi ise alt tarafta bir sekilde handle ediliyor ve dikkate deger bir maliyeti olmadigini soyleyebilirim.

Monday, September 17, 2012

Managing cache with Ehcache

IHTIYAC:

 Uretmesi ve elde etmesi maliyetli olan entity'leri olasi sonradan ihtiyaclarda tekrardan uretmek yerine memory'de tutuyoruz, Bunu basitce entity'leri bir ConcurrentHashMap'de tutup, ihtiyac duydugumuz anda da ulasarak sagliyabiliriz. Ancak outOfMemory almamak icin map'de tuttugumuz bu objelerin belli bir sure sonra expire olmalarini saglamali, hatta Map'de tuttugumuz objelerin sayisini da limitli tutmamiz lazim. Bunun icin belli araliklarda calisan bir TimerTask'imiz var, ve Map'deki entity'leri tarayarak, suresi gecmis entity'leri Map'den temizliyoruz.

Butun bu isi kendimiz manage etmek yerine bunu bizim icin belki de daha optimize yapan bir urun var ehcache.

 Ufak bir test kod'u ile kullanimina bakalim. TTL degerimiz 2 sn, yani cach'e koydugumuz obje 2 sn sonra expire olmali ve cache en fazla 100 eleman bulundurmali, eleman sayisi bunu artarsa, first in first out mantigi ile eski elaman'lar cache'den atilip yerine yenileri konmali:

Dependency'lerimiz:

 <dependencies>  
   <dependency>  
    <groupId>junit</groupId>  
    <artifactId>junit</artifactId>  
    <version>4.7</version>  
    <scope>test</scope>  
   </dependency>  
   <dependency>  
       <groupId>net.sf.ehcache</groupId>  
       <artifactId>ehcache</artifactId>  
       <version>2.0.0</version>  
       <type>pom</type>  
      </dependency>  
      <dependency>  
           <groupId>org.slf4j</groupId>  
           <artifactId>slf4j-log4j12</artifactId>  
           <version>1.5.6</version>  
      </dependency>  
 </dependencies>  

Test Code'u:

 import net.sf.ehcache.Cache;  
 import net.sf.ehcache.CacheManager;  
 import net.sf.ehcache.Element;  
 import net.sf.ehcache.config.CacheConfiguration;  
 import org.junit.Before;  
 import org.junit.Test;  
 /**  
  * Unit test for simple App.  
  */  
 public class AppTest  
 {  
   public static final int TTL_IN_SEC = 2;  
   public static final int MAX_ELEMENT_IN_MEMORY = 100;  
   static {  
     CacheManager manager = CacheManager.create();  
     //Create a Cache specifying its configuration.  
     Cache cache = new Cache(new CacheConfiguration("myCache", 1000).timeToLiveSeconds(TTL_IN_SEC).maxElementsInMemory(100));  
     manager.addCache(cache);  
   }  
   @Before  
   public void init() throws Exception {  
     Cache cache = CacheManager.getInstance().getCache("myCache");  
     Element e = new Element(1, "test");  
     cache.put(e);  
   }  
   @Test  
   public void shouldRemoveAfterTTL() throws Exception {  
     Cache cache = CacheManager.getInstance().getCache("myCache");  
     Element e = cache.get(1);  
     org.junit.Assert.assertEquals(e.getValue(), "test");  
     System.out.println("hit value by 1 = " + e);  
     System.out.println("sleep by TTL + 1 sec ");  
     Thread.sleep(TTL_IN_SEC * 1000 + 1000);  
     e = cache.get(1);  
     org.junit.Assert.assertNull(e);  
     System.out.println("hit value by 1 = " + e);  
   }  
   @Test  
   public void shouldRemoveFirstElementWhenCacheFull() throws Exception {  
     Cache cache = CacheManager.getInstance().getCache("myCache");  
     Element e = cache.get(1);  
     System.out.println("hit value by 1 = " + e);  
     org.junit.Assert.assertEquals(e.getValue(), "test");  
     for (int i = 2; i &lt;= 2 * MAX_ELEMENT_IN_MEMORY; i++) {  
       e = new Element(i, "test" + i);  
       cache.put(e);  
     }  
     e = cache.get(1);  
     org.junit.Assert.assertNull(e);  
     System.out.println("xxhit value by 1 = " + e);  
   }  
 }  

Hizli ve optimize yazilimlar dilegiyle.

Thursday, September 06, 2012

Throttling with RabbitMQ

Broadcasting with Hazelcast


Farkli host'larda clustered calisan uygulamalarimizin birbirleri ile haberlesmelerine ihtiyacimiz var. Host'lardan birinde gerceklesen bir event'in diger hostlar tarafindan haberdar edilmesi lazim. Bu amacla ve daha bir cok ozelligi ile (distributed caching, load balancing, publish/subscriber messaging) ve en onemlisi kullanim basitligi ile Hazelcast kullanabiliriz.

Asagida Hazelcast kullanarak bir broadcasting ornegi yapalim.

Dependency'miz

 <dependency>  
      <groupId>com.hazelcast</groupId>  
      <artifactId>hazelcast</artifactId>  
      <version>2.2</version>  
 </dependency>  

Hazelcast servisimizi ayaga kaldiralim:

    import org.apache.log4j.Logger;   
    import com.hazelcast.config.Config;   
    import com.hazelcast.config.Join;   
    import com.hazelcast.config.NetworkConfig;   
    import com.hazelcast.core.Hazelcast;   
    import com.hazelcast.core.HazelcastInstance;   
    import com.hazelcast.core.MultiTask;   

    public class HazelcastService{  

    public static Logger    logger = Logger.getLogger(HazelcastService.class);   
    private static HazelcastInstance hazelcastInstance;   
    private static boolean   initialized = false;   

    public void deploy() {   
    logger.info("INITIALIZING HAZELCAST......");   
    try {   
     System.setProperty("hazelcast.logging.class",    HazelcastLoggerFactory.class.getName());    
     Config cfg = new Config();   
     cfg.setPort(ServiceProperties.HAZELCAST_PORT);   
     cfg.setPortAutoIncrement(true);   
     NetworkConfig network = cfg.getNetworkConfig();   
     Join join = network.getJoin();   
     join.getMulticastConfig().setEnabled(false);   
     String ips = ServiceProperties.HAZELCAST_CLUSTER_HOST_IPS_SEPERATED_BY_COMMA;   
     StringTokenizer tok = new StringTokenizer(ips, ",");   
     while (tok.hasMoreTokens()) {   
      join.getTcpIpConfig().addMember(tok.nextToken());   
     }   
     join.getTcpIpConfig().setEnabled(true);   
     hazelcastInstance = Hazelcast.newHazelcastInstance(cfg);   
     initialized = true;   
    } catch (Exception e) {   
     logger.error(e);   
    }   
    logger.info("INITIALIZED HAZELCAST......");   
   }   
 }  

Mesaj gonderimini tetikleyelim:

 public static void notifyEvent(String eventId) {  
     if (!initialized) {  
       logger.warn("HazelcastService is not initialized, doint nothing");  
       return;  
     }  
     try {  
       Event event = new Event(eventId);  
       MultiTask<Boolean> task = new MultiTask<Boolean>(event, hazelcastInstance.getCluster().getMembers());        
       broadcast(task);  
     } catch (Exception e) {  
       logger.error(e);  
     }  
   }  
      private static void broadcast(MultiTask<Boolean> task) throws InterruptedException, ExecutionException, TimeoutException {  
     ExecutorService executorService = hazelcastInstance.getExecutorService();  
     executorService.execute(task);  
     Collection<Boolean> results = task.get(3, TimeUnit.SECONDS);  
     logger.info("Call Results: " + Arrays.toString(results.toArray()));  
   }  

Diger hostlarda mesaj'i karsilayacak class'imiz

 public class Event implements Callable<Boolean>, Serializable {  
   protected String eventId;  
   public PricePlanUpdated(eventId) {  
     super();  
     this.eventId = eventId;      
   }  
   public Boolean call() {  
     try {  
       HazelcastService.logger.info("Received event message with eventId:" + eventId);  
       //do job  
       HazelcastService.logger.info("Processed event message with eventId:" + eventId);  
     } catch (Exception e) {  
       HazelcastService.logger.error(e);  
     }  
     return true;  
   }    
 }  

That's all.