Friday, February 29, 2008

QRCodes in action!

Typing a web address with the number based keypads of cellphones is an annoying process for the majority of wireless subscribers that don't have phones with QWERTY keypads. If you don't agree try typing the address below with your cellphone:

http://www.abc.net.au/cgi-bin/common/transform.pl?telstrawallaceml2html&wap&telstra~World&imode/2175963
By using QRCodes wireless subscribers just SCAN & GO. Here is a small list of QRCodes usage:

  1. ORCodes & Facebook

  2. "Add to friends" link of facebook is encoded into a QRCode image and printed on a t-shirt. Seeing people around you, trying to scan your t-shirt with their cellphone will be freaky.



  3. QRKill - shooting game

  4. QRKill is a QRCode powered game. Players stick in their back a QRCode with his/her telephone and name encoded. They will have to kill each other capturing the code and sending an SMS. Players will be eliminated right after receiving a deathly SMS.


  5. Product Information

  6. McDonald's in Japan is printing the QRCodes on all its food packaging so customers know exactly what they are eating. By scanning the code with their cameraphone McDo lovers access all the information about the McFood including any potential allergy warnings.

    QRCodes are very popular in Japan. I haven't seen any printed QRCode in Turkey but according to me they'll catch attraction of Mobile advertisers soon. Here's another image that shows a product with information printed on it via QRCodes.



Thursday, February 28, 2008

memcached - Dağıtımlı (distributed) önbellek sistemi


TBD BİLİŞİM TERİMLERİ KARŞILIKLAR SÖZLÜĞÜ'nde "distributed" kelimesinin karşılığı olarak "dağıtımlı" yazıyor. Önceleri "distributed" kelimesi için "dağıtık", "dağıtılmış" kelimelerini kullanırdım. Madem Türkiye Bilişim Derneği "dağıtımlı" diyor bundan sonra benim de bu kelimeyi kullanmak boynumun borcudur. Bu yazıyı, okuduğum bir çok ingilizce yazının bir özeti olarak yazıyorum. (Kendi fikirlerimi eklemeyi unutmadım tabi ki :)) Yazıda ingilizce terimlerin türkçe karşılıklarını kullanmaya özen gösterdim fakat yine de tam türkçe karşılığını bulamadığım terimler var.

1. Nedir bu memcached denen şey?


Memcached, Danga Interactive http://www.danga.com/ tarafından geliştirilmeye başlanmış bir "distributed object caching" sistemidir. Yüksek trafik alan dinamik web uygulamalarının veritabanına gitme sayısını azaltmayı, bu sayede de performansı artırmayı hedefleyen bir uygulamadır.
Memcached'yi network üzerinden erişilebilen kocaman bir Hashtable olarak düşünebiliriz. Network üzerindeki herhangi bir makinadan "key" ile memcached'de sakladığımız bir nesneye, network üzerindeki başka bir makinadan aynı key ile ulaşabiliriz. Detaylar için okumaya devam...

2. Lisansı nasıl?


BSD License ile lisanslanmış. http://en.wikipedia.org/wiki/BSD_license

3. Hangi işletim sistemlerinde çalışıyor?


Linux, BSD, Windows üzerinde sorunsuz çalışıyor. Web sitesinde Solaris ile ilgili bir bilgi yok. Mail listelerine bakılınca solaris üzerinde çalıştırmak için taklalar atmak gerektiğini anlıyoruz. Memcached fazla CPU kullanmıyor ve tek ihtiyacı boş RAM. Bu yüzden memcached instance'larını çalıştıracağımız makinanın Sun sparc işlemcili bir makina olmasına gerek yok. Hızlı bir network kartı ve yeterli RAM'i olan linux PC'ler memcached çalıştırmak için yeterli olacaktır. (Ben testlerimi Ubuntu 7.10 kurulu Dell Laptop üzerinde yaptım :) )

4. Nasıl kurulur?


http://www.danga.com/memcached/download.bml adresinden indireceğiniz kaynak kodunu INSTALL ve README dosyalarını okuyarak derleyip kurabilirsiniz.
http://blog.ajohnstone.com/archives/installing-memcached/ adresinde kurulum ile ilgili bir tutorial var.

5. Nasıl çalıştırılır?


Memcached bir konfigürasyon dosyasına ihtiyaç duymaz. Gerekli bütün ayarlar komut satırından memcached daemon'u çalıştırırken verilebilir.

# ./memcached -d -m 2048 -l 192.168.43.47 -p 11211


Bu komut memcached'ye der ki:
  • (-d) daemon olarak çalışacaksın
  • (-m 2048) 2GB'dan fazla RAM kullanamazsın.
  • (-l) 192.168.43.47 makinasında çalışıyorsun
  • (-p) 11211 portunu dinleyeceksin.

Aynı makina üzerinde RAM yettiği sürece birden fazla memcached daemon çalıştırabiliriz (Farklı portlarda çalıştırmaya dikkat etmek lazım). Örneğin, herbiri 512MB kapasiteli 5 adet memcached daemon'u aynı makina üzerinde asaşıdaki şekilde başlatabiliriz. Toplamda 2.5GB'lık bir cache'imiz oluyor. (Dikkat böyle bir kullanım size mantıklı gelmeyebilir, sadece daemon'u nasıl başlattığımız göstermek için bir örnek.)

# ./memcached -d -m 512 -l 192.168.43.47 -p 11211
# ./memcached -d -m 512 -l 192.168.43.47 -p 11212
# ./memcached -d -m 512 -l 192.168.43.47 -p 11213
# ./memcached -d -m 512 -l 192.168.43.47 -p 11214
# ./memcached -d -m 512 -l 192.168.43.47 -p 11215



6. Memcached'ye uygulamalarımız nasıl erişecek?


Memcached'nin network üzerinden erişilebilen büyük bir Hashtable olduğundan bahsetmiştik. Uygulamaların memcached'ye erişebilmeleri için çeşitli dillerde yazılmış istemci kütüphaneleri var. Java dışında Perl, Php, Python, Ruby, C# ve C için yazılımış istemciler mevcut. Bu adresten http://www.whalin.com/memcached/ java memcached client indirilebilir.
Yazılımcılar gerek görürlerse memcached ile haberleşmeyi sağlayacak kendi istemci kütüphanelerini yazabilirler. Memcached ile client'lar arasındaki protokolün detaylarına http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt adresinden erişilebilir.

7. Tipik bir kullanım örneği


Örnek java kodu:

public VpnAccount getVpnAccount(String msisdn) {
VpnAccount account = memcachedClient.get(msisdn);
if (account == null) {
account = getAccountFromDatabase(msisdn);
memcachedClient.set(msisdn, account);
}
return accout;
}



6. Nasıl çalışıyor? Nasıl "distribution" sağlıyor?


Evet zurnanın "zıırrrt" dediği yere geldik. Memcached network üzerinden erişebileceğimiz boş RAM'i olan herhangi bir makinada çalıştırılabilir.

Örnek 1: Bir veya birden fazla uygulamanın tek bir memcached instance kullandığı senaryo:


Bu senaryonun üzerinde fazla durmaya gerek yok. Uygulamalara memcached'nin çalıştığı makinanin IP'si ve memcached'nin dinlediği port bilgisi verilir. Bütün uygulamalar aynı cache instance'ını kullanır. A uygulamasının K anahtar kelimesi ile cache'e gönderdiği V değerini, B uygulaması K anahtar kelimesini kullanarak alabilir.
Bu mimarinin artıları:
  • Basit bir mimaridir. (Fakat tavsiye edilen mimari değil)
  • Merkezi bir cache olduğu için uygulamalar (java uygulamalarından bahsediyorum) kendi cache'lerini tutmak zorunda değil. Uygulamaların Cache'leri arasında tutarlılık kontrolleri yapmaya gerek yok.

Eksileri:
  • Tek bir cache instance = SPOF (Single point of failure)

Örnek 2:


Birden fazla memcached daemon'ın kullanıldığı senaryo.


192.168.43.47:11211, 192.168.43.48:11211 ve 192.168.43.49:11211 da çalışan 3 adet memcached daemon olsun. Bizim de bu cache'leri kullanan A,B ve C uygulamalarımız olsun. (IN uygulamalarından örnek verecek olursak GW1, GW2 ve GW3).
memcached'nin çalışması iki adımdan oluşan hashing mekanizmasına bağlıdır.
  • 1. adımda client, memcached daemon listesini kullanarak "K" anahtarının hash'ini hesaplar. "K" ile saklanan "V" değerine ulaşmak için (ya da "K" ile "V" değerini saklamak için) hangi memcached server'a gideceğini bulur.

  • 2. adımda memcached serverda (çok büyük bir hashtable olarak düşünebiliriz demiştik) "K" anahtarının hash'i farklı bir algoritma ile hesaplanır. "Hashtable lookup" ile "V" değerine erişilir.

Telekom uygulamasından bir örnek:
MSISDN'leri anahtar olarak kullanıp VpnAccount nesnelerini memcached içinde saklayalım. MSISDN "905435022434", cache server listesine göre hash'lendiğinde "905435022434"e karşılık gelecek VpnAccount'un hangi memcached daemon'da saklanacağı bulunur. (Örneğin 192.168.43.48:11211).
Uygulamaların hepsi anahtar kelimenin (yani MSISDN'in) hash'ini hesaplarken aynı hash algoritmasını kullanacağı için "905435022434" numaralı VpnAccount'a ulaşmak için bütün uygulamalar aynı memcached daemon'a gidecektir.
Bu mimarinin artıları:
  • çok iyi ölçeklenebilir (highly scalable). Ne kadar çok RAM o kadar çok cache.
  • aklıma şimdilik başka birşey gelmiyor :D

Eksileri:
  • (Eksi alanına birşeyler yazmış olmak için yazıyorum) birden fazla memcached instance'ı yönetmek zor olabilir.


9. Authentication mekanizması nasıl işliyor?


Memcached authentication kullanmıyor. Network üzerinden erişimi olan bütün client'lar "set" ve "get" yapabilirler. Üzerinde memcached çalışan host'ların firewall ayarlarının dikkatli yapılması gerekir.

10. Failover senaryoları nasıl? Memcached failover destekliyor mu?


memcached failover desteklemez. memcached'yi "set(key, value)" ve "get(key)" işlemlerini destekleyen bir Hashtable olarak olarak tanımlamıştık. Memcached instance'larının birbirlerinden haberleri yoktur. Network üzerinden kaç tane memcached'nin çalıştığı bilgisi sadece client'larda vardır. Memcached server grubundan bir server'ın çıkartılması ya da yeni bir server eklenmesi durumu ile başa çıkmak client'lara kalmıştır.
A, B, C hostlarında çalışan 3 tane memcached server oldugunu varsayalım.

hash("905435022434")%(["A","B","C"].length) --> A
hash("905435022435")%(["A","B","C"].length) --> B
hash("905435022436")%(["A","B","C"].length) --> C olsun.


("905435022434" anahtarı ile bir nesneyi aramak için A'ya, "905435022435" anahtarı ile bir nesneyi aramak için B'ye gidilecek.)
Bu üç hosttan bir tanesi örneğin B erişilemez duruma gelirse, kullanılabilen 2 tane memcached server kalır. Bu durumda

hash("905435022434")%(["A","C"].length) --> C
hash("905435022435")%(["A","C"].length) --> A
hash("905435022436")%(["A","C"].length) --> A olabilir.


Yani 3 memcached server ile çalışırken "905435022434" anahtarı ile A hostuna yönlenilirken 2 memcached server ile çalışırken "905435022434" anahtarı ile C hostuna yönlenebiliriz. Bu da "905435022434" anahatarı ile cache içinde tutulan nesnenin artık geçersiz olduğu (DB'den yeniden çekilmesi gerektiği) anlamına gelir. Aynı tip senaryo memcached server grubuna yeni bir memcached server eklendiğinde de geçerlidir.
Yukarıda bahsedilen problemi çözmek için "consistent hashing" algoritmaları geliştirilmiş. memcached client'ların verilen bir anahtar için hangi memcached server'a gideceklerini hesaplayan bu algoritmalar sayesinde memcached server grubundan bir server çıktığı zaman ya da yeni bir server eklendiği zaman "K" anahtarına karşılık gelen memcached server'ın değişmemesi sağlanmıştır.
http://www.whalin.com/memcached/ adresindeki memcached client içerisinde "consistent hashing" algoritmasının implementasyonu mevcut.

11. JVM, cache için extra hafızaya ihtiyaç duyacak mı?


Memcached kullanıldığında nesneler JVM heap'te değil başka bir process'in (bu process JVM ile aynı host'ta ya da farklı bir host'ta olabilir) kullandığı hafıza alanında saklanır. Bugün cache kullanan uygulamalarımız için JVM'i başlatırken (yaklaşık olarak) 2GB heap kullan diyoruz (-Xms2048m -Xmx2048m). Memcached kullandığımız durumda JVM bu kadar geniş bir heap'e ihtiyaç duymayacaktır - çoğu uygulamalar için 256 MB'lık bir heap yeterli olur diye düşünüyorum. Bu sayede Garbage collection sureleri kısalacaktır. (Telekom uygulamalarında Garbage Collection suresinin ne kadar önemli olduğundan söz etmeye gerek yok.)

12. Cache dolduğu zaman ne olur?


Memcached'nin cache'i dolduğu zaman, cache'e yeni bir nesne eklemek istersek LRU (least recently used) yöntemiyle eski nesneler cache'den silinir.

13. memcached'nin arkasında kim var?


memcached kaynak kodu açık bir uygulama. Arkasında bizim gibi 100'lerce yazılımcı var. Daha da önemlisi bir çok yerde kullanıyor ve kendini kanıtlamış. http://developers.facebook.com/opensource.php adresinde, facebook yazılımcılarının memcached kaynak koduna yaptıkları katkılarla, memcached performansını 20% iyileştirdiklerinden bahsediliyor.
Aşağıdaki listede memcached kullandıklarını söyleyen bir kaç tane web sitesi var. Bu sitelerin ortak özellikleri çok hit almaları ve her sayfada dinamik bilgiler göstermeleri.


14. Daha detaylı bilgiye nereden ulaşabilirim?


Bu adreste (http://www.socialtext.net/memcached/index.cgi?faq) memcached ile ilgili bir FAQ var.

Wednesday, February 27, 2008

QRCodes are becoming popular


QRCodes are two dimensional barcodes that can be decoded (scanned) at high speed. QrCode is created by Japanese corporation Denso-Wave. These two dimentisional bar codes are very common in Japan. They are widely used in ad sector.
URLs, Text, Phone numbers can be encoded in these codes. There are J2ME applications that can decode QRCodes. If you have a java enabled cell phone with a camera, install the application from http://reader.kaywa.com/ and begin scanning QRCodes.

I am going to list what can be done with a QRCode reader and a QRCode generator later in this blog.

The image in this post is an example of generated QR Code. Guess what is encoded in the picture. Install the QRCode reader and scan the image ;)

Sunday, February 3, 2008

RESTFUL URLs with Stripes

I came across with Stripes Framework 3 months ago. At first I said "yet another java mvc framework" but after reading its documentation I was suprised to see how easy a web application can be developed with Stripes.

I have developed several web applications with Struts and Spring MVC. The main difference between Stripes and other MVC frameworks is the configuration. Struts uses struts-config.xml to configure its action classes and its action forms. Stripes requires minimal configuration to get up and running (dispatcher conf. in web.xml), and zero configuration per ActionBean or page. If you have never heard of Stripes, go read Quick Start Guide, you will thank to me ;). I do not want to duplicate documentation in this post, because Stripes team has prepared a good and comprehensive documentation.

In this post I will explain how you can create clean urls with Stripes. Stripes does not need a configuration file to configure its action beans. If you does not supply any additional configuration Stripes configures your web application with the default RuntimeConfiguration class. An ActionResolver is responsible for finding your action beans and mapping HTTP requests to action bean methods. Stipes uses NameBasedActionResolver by default.
As it is explained here the default behaviour of NameBasedActionResolver is as follows:

  1. All classes that implements the ActionBean interface is searched. (By default Stripes searches for ActionBean implementations in classpath. But you can narrow the scope of this search by changing the default configuration. This will improve startup performance of your application. See ActionResolver Properties)
  2. Packages "web, www, stripes, action" and their parents are removed. For example "com.companyname.superproject.web.user.DetailsActionBean" becomes "user.DetailsActionBean".
  3. Action or ActionBean suffix is trimmed. "user.DetailsAactionBean" becomes "user.Details"
  4. "." is replaced with "/". "user.Details" becomes "/user/Details"
  5. Finally NameBasedActionResolver appends ".action" to the end of the action URL and we get "/user/Details.action"

If you want to use clear URLs like "http://www.mysite.com/user/details/12345" instead of "http://www.mysite.com/user/Details.action?userid=12345" you must write your custom ActionResolver implementation. Don't worry it is very easy. First in your web.xml tell Stripes to use your ActionResolver class:
web.xml

<filter>
<display-name>Stripes Filter</display-name>
<filter-name>StripesFilter</filter-name>
<filter-class>net.sourceforge.stripes.controller.StripesFilter</filter-class>
<init-param>
<param-name>ActionResolver.UrlFilters</param-name>
<param-value>/WEB-INF/classes</param-value>
</init-param>
<init-param>
<param-name>ActionResolver.Class</param-name>
<param-value>com.companyname.superproject.RestfulActionResolver</param-value>
</init-param>
</filter>

Then write a class that extends NameBasedActionResolver. You only need to override getBindingSuffix() and getUrlBinding(String s) methods. An implementaion (RestfulActionResolver.java) is listed below:
RestfulActionResolver.java

package com.companyname.superproject.RestfulActionResolver
import net.sourceforge.stripes.controller.NameBasedActionResolver;
import org.apache.log4j.Logger;

public class RestfulActionResolver extends NameBasedActionResolver {
@Override
protected String getBindingSuffix() {
return "";
}
@Override
protected String getUrlBinding(String s) {
String urlBinding = super.getUrlBinding(s);
return urlBinding.toLowerCase();
}
}

RestfulActionResolver finds ActionBean instances and performs HTTP requests bindings for you.
"com.companyname.superproject.web.user.DetailsActionBean" action bean is mapped to URL "/user/details".

I used Stripes version 1.4.3 in the above example.
I hope you enjoy the post.