Cumartesi, Temmuz 21, 2007

Quartz Scheduler

Özellikle kurumsal uygulamalardaki en kritik konulardan biri de belli bir saatte çalışması planlanmış batch işlemleridir. Örneğin Bankacalık Uygulamalarındaki Otomatik Ödeme Talimatları, Havale ve EFT talimatları, Günsonu işlemleri, vs. "Job Scheduler" diye adlandırılan araçlar ile gerçekleştirilmektedir.

Bu işlemler arkaplanda, kullanıcı ile bir etkileşimi olmadan çalıştığı için aynı anda yüzlerce thread'in çalışmasına neden olabilir. Bu yüzden bu araçların işlerini, sistem kaynaklarını en verimli bir şekilde kullanarak, hata yapmadan, yapsa bile loglayarak veya daha sonra düzelterek (recovery) çalışması gerekmektedir. Özellikle bankacılık gibi kritik uygulamaların günsonu işlemlerinde milyon dolar'ların işlendiğini düşünecek olursanız bu araçların önemi daha iyi anlaşılacaktır.

İşte bu blogum'da daha evvel geliştirdiğimiz bir çok uygulamamızda kullandığımız Quartz Scheduler'dan bahsedeceğim. Hatta bahsetmekle kalmayacak, Quartzla ilgili yazdığım bir örneği de paylaşacağım.

Quartz, dünyaca ünlü bir çok lisanslı uygulamanın da kullandığı açık kaynak uygulama. Quartz halen, bünyesinde WebWork (Strus ile birleşip Strus2 adını aldı), SiteMesh, OSCache gibi dünyaca ünlü açık kaynak projeleri barındıran OpenSymphony Açık Kaynak topluluğu altında geliştirilmekte. Açık Kaynak uygulamaları kullanmakta hala tereddüt edenleri biraz rahatlattıktan sonra Quartz'ın özelliklerine geçelim.

Quartz öncelikle her türlü Java Uygulamasının bir parçası şeklinde çalışabiliyor:
* Quartz can run embedded within another free standing application
* Quartz can be instantiated within an application server (or servlet container), and participate in XA transactions
* Quartz can run as a stand-alone program (within its own Java Virtual Machine), to be used via RMI
* Quartz can be instantiated as a cluster of stand-alone programs (with load-balance and fail-over capabilities)
Quartz'ın XA Transaction desteği aslında çok önemli bir özellik, maalesef bir çok yazılım geliştirici XA'in (Distributed Transactions) öneminin farkında olmadığı için veritabanları üzerinde uyumsuz (inconsistant) veriler bulunmakta.

Quartz bir özelliği de, dünyaca ünlü Strus ve Spring gibi framework'lere kolayca entegre edilebilir olması:

* Quartz'ın Spring ile Entegrasyonu
* Quartz'ın Strus ile Entegrasyonu

Quartz'ın en önemli özelliklerinden biri de Trigger diye adlandırlan çok farklı tetikleme mekanizmasına sahip olması:
* at a certain time of day (to the millisecond)
* on certain days of the week
* on certain days of the month
* on certain days of the year
* not on certain days listed within a registered Calendar (such as business holidays)
* repeated a specific number of times
* repeated until a specific time/date
* repeated indefinitely
* repeated with a delay interval
Quartz'ın bir başka özelliği de çalıştırdığı işlerin transactional bir şekilde gerçekleştirebilmesi. Ayrıca Clustering ve Job Persistence desteği sayesinde bir veritabanı üzerinde işlerini saklayabiliyor ve cluster node'ları arasında dağıtabiliyor:
* The design of Quartz includes a JobStore interface that can be implemented to provide various mechanisms for the storage of jobs.
* With the use of the included JDBCJobStore, all Jobs and Triggers configured as "non-volatile" are stored in a relational database via JDBC.
* With the use of the included RAMJobStore, all Jobs and Triggers are stored in RAM and therefore do not persist between program executions - but this has the advantage of not requiring an external database.
* Quartz can participate in JTA transactions, via the use of JobStoreCMT (a subclas of JDBCJobStore).
* Quartz can manage JTA transactions (begin and commit them) around the execution of a Job, so that the work the Job does happens within a JTA transaction.
* Fail-over.
* Load balancing.
Quartz'ın diğer özelliklerini ve güzelliklerini anlatmam saatler sürer. Bunun yerine kendi sitesindeki tutorial'lara bir gözatmanızda fayda var. Ayrıca aşağıda linkini paylaştığım Quartz'ın Cluster modda kullanımı ile ilgili bir örneğe göz atabilirsiniz.

Quartz JDBCJobStore Tutorial

Bu blogu okuyanlar arasında "Ne gerek var Java'da Scheduler kullanmaya" diye düşünenler olabilir. Bu soruya cevap vermeden evvel alternatifleri düşünelim:

1) Batch işlemlerinin veritabanı job'ları olarak çalıştırılması
Bu yöntem zaten şu an en yaygın kullanılan yöntemlerden birisi. Veritabanı diğer kullanıcı işlemleri nedeniyle yük altında değilken veya batch olarak işlenen çok fazla veri yokken bu yöntem çok sağlıklı çalışır. Peki yükümüz her geçen gün artarsa ne yapacağız, unutmayın veritabanı üzerinde çalışan fonksiyonlar bir yandan hesaplama yapmak için bir yandan da kayıtları güncellemek için sistem kaynaklarını kullanırlar. Kaynaklarınız yetmediği zaman aynı orta katmanda olduğu gibi veritabanlarınızı çoğaltamazsınız.

Ama Quartz kullanıyorsanız veritabanını sadece insert, update ve delete işlemleri için kullanılıyor, tüm business fonksiyonları ise Quartz'ın çalıştığı başka sunucular üzerinde işleniyor olacak. Kaynak ihtiyacınız arttıkça yeni sunucular ekleyebileceksiniz. (Load-balancing)

2) Batch işlemlerinin işletim sistemi (unix/windows) job'ları olarak çalıştırılması
Bu yöntem aslında ilk bakışta Quartz'ın load-balancing özelliğini karşılıyor gibi gözüküyor. Shell script yazılarak Unix'in cron'una eklenen batch işlemlerin en zayıf yani recovery'dir. Kısaca özetlemek gerekirse Quartz'ın cluster node'ları arasında "Quartz Kardeşliği" diye bir kavram vardır. Hiç bir kardeş diğerine hükmetmez ama arkasını kollar. Kardeşlerden biri çalışırken hata alırsa diğerleri onun işlerini halledebilirler. Eğer aralarına başka bir kardeş daha katılırsa ellerindeki işleri diğer kardeşle paylaşırlar. Shell scriptler ile bu işleri yapmak çok zordur. (Fail-over)

Etiketler:

Google'dan Kablosuz Internet Atağı

Google kablosuz dünyaya olan ilgisini hız kesmeden devam ettiriyor. Google, geçenlerde GrandCentral'ı satın almasından sonra şimdi de Amerika'daki açık arttırma ile dağıtılacak olan 700MHz spekturumundaki kablosuz bağlantı ihalesine tam 4.6 milyar dolar teklif vereceğini açıkladı:
Our commitment to open broadband platforms
Google's interest in promoting competition in the broadband market here in the U.S., to help ensure that as many Americans as possible can access the Internet. However, it takes more than just ideas and rhetoric if you want to help bring the Internet to everyone. So today, we're putting consumers' interests first, and putting our money where our principles are -- to the tune of $4.6 billion.
Buraya kadar olan herşey normal gözüküyor. Adamın parası var, Telekom işine girmek istiyor, dolayısıyla parayı gözden çıkarmış. Fakat Google ihaleyi düzenleyecek olan FCC'yi biraz da manupüle etmeye çalışarak bu parayı aşağıdaki şartlar dahilinde vereceğini söylüyor:
With that in mind, last week, as the federal government prepares for what is arguably its most significant auction of wireless spectrum in history, we urged the Federal Communications Commission (FCC) to adopt rules to make sure that regardless of who wins the spectrum at auction, consumers' interests are the top priority. Specifically, we encouraged the FCC to require the adoption of four types of "open" platforms as part of the auction:

* Open applications: consumers should be able to download and utilize any software applications, content, or services they desire;
* Open devices: consumers should be able to utilize their handheld communications device with whatever wireless network they prefer;
* Open services: third parties (resellers) should be able to acquire wireless services from a 700 MHz licensee on a wholesale basis, based on reasonably nondiscriminatory commercial terms; and
* Open networks: third parties (like Internet service providers) should be able to interconnect at any technically feasible point in a 700 MHz licensee's wireless network.
Bu da demek oluyor ki Google açıklık stratejisini mobil dünyada da uygulamak istiyor. GigaOM'da bu haberle ilgili yapılan ilginç bir yorum da şu şekilde:
Google will bid for Wireless Spectrum
Google’s proposal liberally throws around the word, OPEN: open apps, open platform, open devices, open services and open network. Those are nice words. But in reality no one commits spending $4.6 billion (or more) unless they have vested interests. I suspect Google has a lot more wireless applications coming, and needs to basically insure a way to get them to the people.
Tabii bu ihaleye teklif verecek olan diğer büyük rakiplerden AT&T de, Google'un bu teklifinin üzerine hemen bir açıklama yayınladı:
AT&T Responds to Google Bid
Google is demanding the Government stack the deck in its favor, limit competing bids, and effectively force wireless carriers to alter their business models to Google’s liking. We would repeat that Google should put up or shut up— they can bid and enter the wireless market with any business model they prefer, then let consumers decide which model they like best.
Açık Kaynak Dünyasının bir taraftarı olarak Google'ın bu "OPEN" hareketlerini canı gönülden destekliyorum :)

Pazar, Temmuz 15, 2007

Robocode and BattleCode

Bir çoğumuzda olduğu gibi benim de yazılım dünyasına hevesim bilgisiyar oyunlarıyla başladı. İlk bilgisayarım olan Commodore 64'ü aldığımdan bu yana hep takıldığım bir oyun mutlaka olmuştur. Fakat son bir yıldır oyunun yerini bloglar, wikiler ve RSS'ler almaya başladı. :)

Oyun olayını abarttığım dönem ise Ultima Online (UO) oynadığım yıllardır. Aslında MMRPOG'ciler ne demek istediğimi gayet iyi anlayacaklardır. Bir "RolePlaying" oyunu olan UO'nun en önemli ve en çok zaman alan kısmı ise argoda "skill kasma" diye tabir edilen, bilgisayarın başında anlamsızca saatlerinizi geçirdiğiniz kısımdır. Bu tip oyunlarda karakterinizin yetenekleri kuvvetli değilse hiç birşey yapamazsınız.

İşte o dönemde UO'da otomatik bir şekilde (unattended) karakter geliştirmenin yollarını ararken EasyUO isminde bir programın varlığını keşfettim. EasyUO kabaca UO'daki client-server arasındaki iletişimi simüle eden bir scripting programıydı. EasyUO kullanarak bir arkadaşımla birlikte öyle scriptler yazmıştık ki, scriptler oyunu bizden daha iyi oynar olmuşlardı. Gece biz uyurken karakterlerimiz otomatik olarak gelişiyordu. Bir nevi oyun robotları yazıyorduk.

Daha sonra farkettim ki çok kompleks bir oyun için işleri otomatikleştirebiliyorsak, iş dünyasında görece daha basit işler için otomatikleştirme çok daha kolay yapılabilirdi. İşte Apache Ant ve CruiseControl gibi Konfigürasyon Yönetimi araçlarına ilgim bu şekilde başladı.

Açıkçası oyun oynamak için yazılım yapmanın, yazılım mühendislerine çok şey katacağını düşünüyorum. Bu yüzden birkaç sene evvel takıldığım fakat geçenlerde iş yerinde bir arkadaşla konuşurken tekrar gündeme gelen iki konuyuı sizinle paylaşmak istedim.


Robocode
Robocode, yıllar önce IBM mühendislerinden Matthew Nelson tarafından başlatılan açık kaynak bir java oyunu. Şu aralar Flemming N. Larsen tarafından bakımı yapılan oyunda kendi yazdığınız robotları başkalarının robotları ile çarpıştırabiliyorsunuz. Oyunda bir numara olmak için hem Java bilginizi hem de AI, algoritma, vs. gibi bilgilerinizi devamlı geliştirmeniz gerekiyor. Epey bir hayran kitlesi bulunan Robocode'un çeşitli ülkelerde ligleri bile düzenlenmekte. Daha evvel duymadıysanız mutlaka bir deneyin derim. http://robocode.sourceforge.net/
Learning never stops with Robocode
If there was ever any doubt on the ability of Robocode to serve as a great teaching tool for Java programming, algorithm design, basic trigonometry, or even distributed computing principles, this article should settle it. Robocode naturally challenges the beginning robot designer to go "the extra mile" to create winning, advanced robots that reflect their mastery of the programming and algorithm design art. Far from being "just another game," Robocode delivers on its educational goals in the name of friendly competition. If only learning could always be this much fun!


BattleCode
BattleCode da MIT'de ders olarak okutulan java tabanlı, yarışma tadında bir oyun. Robocode'dan en büyük farkı BattleCode'da takım oyununun ön plana çıkması. Ayrıca BattleCode, Robocode'a göre çok daha karmaşık. Zaten oyunun spec'lerini inceledeğinizde ne demek istediğimi anlayacaksınız.



Sanırım MIT derslerde öğrencilere oyun oynatacak kadar cidiyetsiz bir üniversite. Ben zaten MIT'den daha adam çıktığını hiç duymadım :)

Bu blog'u da sevgili dostum Oktay Özgün'ün vakti zamanında benimle paylaştığı bir yazıyla kapatayım. Ne demişler, "En güzel oyun kendi yazdığınızdır"
Gaming and Learning
Unlike education acquired through textbooks, lectures, and classroom instruction, what takes place in massively multiplayer online games is what we call accidental learning. It's learning to be - a natural byproduct of adjusting to a new culture - as opposed to learning about. Where traditional learning is based on the execution of carefully graded challenges, accidental learning relies on failure. Virtual environments are safe platforms for trial and error. The chance of failure is high, but the cost is low and the lessons learned are immediate.

XStream HierarchicalStreamWriter Örneği

Google Analytics'in en sevdiğim yanlarından bir tanesi de, blog'umu google üzerinden ziyaret edenlerin hangi anahtar kelimeler kullanarak geldiklerini göstermesi. Analytics kullanmaya başladığım Şubat 2007'den beri bazı konular çok aranmış. Bunların başında da 70 kez sorgulanan XStream geliyor.

Geçen yaz XStream ile ilgili bir blog yazmış, her zaman yaptığım gibi XStream'in güzelliklerinden ve faydalarından bahsetmiş, kullanım ile ilgili hiç örnek vermemiştim. Çünkü kendi sitesinde gayet güzel örnekler mevcuttu. Ama yine de bu kadar çok aranınca benim de çorbada tuzum olsun misali güzel bir örnek paylaşayım istedim.

XStream ile tanışmam JIRA'nın kendi backup'larını XML olarak nasıl aldığını merak etmemle başladı. Veritabanın büyüklüğü ne olursa olsun, JIRA JDBC ile bağlanabildiği tüm veritabanlarından aynı standartta ve performansta XML olarak yedekleme yapabiliyordu. Klasik XML araçları ve yöntemleri kullanarak çok büyük miktarlarda verinin xml olarak yazdırılması mümkün değildi. İşte o zaman biraz araştırınca JIRA'nın XStream'in HierarchicalStreamWriter özelliğini kullandığını farketmiştim.

XStream is abstracted from the underlying XML data using the HierarchicalStreamWriter and HierarchicalStreamReader interfaces for serializing and deserializing respectively.
This abstraction allows XStream to read XML from direct streams using an XML parser or directly manipulate existing structures (such as DOM). This prevents the overhead of having to reparse if XStream is working from XML that has been partially processed by other libraries (for instance a SOAP library). It also avoids tying XStream to a particular library.
XStream comes bundled with reader and writer implementations for most major XML libraries.
Uzun lafın kısası XStream ile büyük miktarlarda Object-to-XML operasyonları yapmak isteyenler için bir örnek hazırladım. İlgilenenler aşağıdaki adresten faydalanabilir:

XStream HierarchicalStreamWriter Tutorial

Çarşamba, Temmuz 11, 2007

Java Hafıza Problemleri ve GCViewer

Uzun bir aradan sonra tekrar blog yazmaya vakit bulabildim. Bu uzun aralığa sebep olan da işyerimin tarihinde yaptığı en büyük altyapığı değişikliğinde görev alıyor olmamdı. Geçiş sırasında 24 saatlik nöbetler ile çalıştığımız için gecemiz gündüzümüze karıştı. Çok büyük bır sıkıntı yaşamadan kısa sürede düzelttiğimiz birkaç performans sorunu ile gayet başarılı bir şekilde migration'ı tamamladık.

Büyük miktarda verinin söz konusu olduğu migration sonrası yaşanılan en büyük sorunların başında, Uygulama katmanındaki Uygulama Sunucularının performansı gelir. Aynı anda gelen binlerce istek, milyonlarca kayıdın bulduğu tablolar üzerinden işlem yaparak Uygulama Sunucularındaki JVM'lerin canına okurlar. Gerçek production ortamını yaşamadan bazı performans sorunlarını önceden tespit etmeniz mümkün olmaz. Bunların başında da memory sorunları gelmektedir.

Hepimizin bildiği gibi Java'nın en temel özelliklerinden biri de hafıza'da işi biten (referansı bulunmayan) objelerinin temizliğini GC (Garbace Collector) mekanizması ile otomatik yapmasıdır. Tabii bu güzel özellik Java geliştiricilerinin hafızayı hoyratça ve sorumsuzca kullanmasına neden olmaktadır. Nasıl olsa GC herşeyi temizlemektedir.

Normalde aynı anda 100 isteğe cevap veren uygulama sunucunuz, yeni bir deployment sonrası daha 50 isteğe gelmeden sıkışmaya başlıyor, gelen istekleri kuyruğa atıyor, CPU tavana vuruyorsa, ilk bakmanız gereken yer JVM'in hafızasıdır. Eğer her bir istekte, memory'de çok büyük yer kaplayan objeler işleniyorsa GC'nin çalışması sistemin performansını korkunç derecede düşürecektir.

Genelde Java Uygulamaları, sunucunun toplam hafızası baz alınarak, JVM'in hafızadan kullanacağı maksimumum değeri gösteren -Xmx parametresi ile başlatılır.

JAVA_OPTS="-Xms2048m -Xmx2048m"

Peki yukarıdaki örnekte olduğu gibi JVM, 2GB hafıza ile çalıştırılmış olmasına rağmen çok kötü bir performans gösteriyorsa sorunun hafıza kaynaklı olup olmadığını nasıl anlayacağız? Bunun tespiti için öncelikle JVM'i GC loglaması yaptıran aşağıdaki parametreler ile başlatmamız gerekmektedir.

JAVA_OPTS="-Xms2048m -Xmx2048m -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"

-Xloggc: parametresi, her GC çalıştığında verdiğiniz dosyaya loglama yapılmasını -XX:+PrintGCDetails -XX:+PrintGCTimeStamps parametreleri de bu loglamanın detaylı yapılmasını sağlayacaktır. Uygulamamızı tekrardan başlattıktan sonra oluşmaya başlayan log dosyasını (gc.log), http://www.tagtraum.com/gcviewer-download.html adresinden ücretsiz olarak indirebileceğimiz GCViewer ile açmamız yeterlidir. Eğer uygulamamızda bir memory problemi var ise, yük altında iken kısa bir süre sonra aşağıdaki gibi bir resimle karşılaşacağız:



Peki bu resimdeki grafik bize tam olarak ne anlatıyor kısaca anlatmaya çalışayım. Mavi zikzak çizgiler o an JVM'de kullanılan hafızayı, siyah uzun çubuklar ise Full GC'nin çalıştığı zamanları ve pause sürelerini göstermektedir. Ekranın Sağ alt köşesindeki Throughput değeri ise JVM'in GC nedeniyle duraklamadan (pause) geçirdiği sürenin toplam süreye oranını göstermektedir.

Yukarıdaki grafikte JVM'in uygulama açıldıktan yaklaşık 15 dakika sonra memory sıkıntısı çekmeye başladığı, bunun üzerinde hafızadaki kullanılmayan objeleri temizlemek için bol bol GC çalıştırdığı, fakat memory'den büyük yer kaplayan objeler bulunduğu için daha sık GC çalıştırmak zorunda kaldığı açıkça görülmektedir. Throughput değeri %55'lere düşmüş, ortalama pause süresi 3.5sn.'lerde gezinmektedir. Bu şekilde çalışmaya devam eden JVM eninde sonunda "Out Of Memory" hatası alacaktır.

Her ne kadar tercih edilen GC algoritmasına göre pause süreleri değişse de, her GC çalışması sistemde bir performans kaybına yol açar. Aşağıdaki gibi sağlıklı bir GC grafiği için büyük miktarlarda hafıza kullanan objelerden uzak durmak ve de JVM'i güzel "Tune" etmek gerekmektedir.




Görüldüğü gibi bu JVM gayet istikrarlı bir şekilde, kendisine ayrılan hafızanın yarısını kullanarak %98 Throughput değerlerinde çalışmaktadır. Fazla yük yok iken JVM zaten default değerlerinde gayet sağlıklı çalışır. Fakat yük altındayken işler değişir.

Bir başka blogumda yüksek yük altında çeşitli JVM parametrelerini kullanarak Throughput'u nasıl yüksek tutabileceğimizi anlatmaya çalışacağım. Aşağıda da özellikle developer arkadaşlara hitap eden bu konuyla ilgili güzel bir blog mevcut:
No Objects Left Behind

If we believe what the graphic that is telling us that the cost of garbage collection is related to the number of objects left behind, the obvious solution is to not leave objects behind. The most reliable way to release objects as soon as possible is to narrow their scope. We can achieve this by moving statically scoped variables to be instance based. We can move instance based variables to local scoping. We need to ask questions such as: “Can we eliminate this variable altogether? Is there any element in the design that is forcing us to hold onto data for longer than is necessary?” Another important aspect is the JVM’s configuration. Is there anything we can do in that regard to help the garbage collector cope with higher rates of object churn? In a vast majority of cases the answers to these questions are yes, yes, and yes. Beware, this advice gets muddled when you consider objects that have a high cost of acquisition.



Etiketler: ,