Monday, May 4, 2015

JBoss EAP 6'da Kümeleme Çözümü

Java EE platformunun mimarisi tasarlanırken iki önemli işlevsel olmayan gereksinim göz önünde tutulmuştur: her zaman erişilebilir (=high availability) ve ölçeklenebilir (=scalability) olmak. Yazılımcı, kurumsal uygulama geliştirirken, sanki uygulamayı tek kullanıcı kullanıyormuş gibi kodlar. Güvenlik, eş zamanlılık/paralel kod koşumu, kalıcılık, atomik işlemler gibi konuları düşünmesi gerekmez. Bunlar mimari ile ya da ilgiye yönelik programlama (=aspect oriented programming) ile ilgili konulardır. Geliştirici doğrudan sunumu ya da iş mantığını kodlamaya odaklanır. Uygulama sunucuları her zaman erişilebilir olmayı ve ölçeklenebilirliği, kümeleme (=clustering) ve yük dengeleme (=load balancing) ile sağlarlar. JBoss uygulama sunucusu açık kaynak kodlu olarak geliştirilen bir projedir. İçinde RedHat firmasında çalışan geliştiricilerin de olduğu herkese açık bir topluluk tarafından geliştirilmektedir. Bu topluluk tarafından geliştirilen uygulama sunucusunun adı JBoss AS'dir. RedHat, sunucu belirli bir olgunluğa eriştiğinde, projeyi alıp yoğun testlerden geçirerek, üretimde kullanılabilecek kaliteye yükseltir. RedHat, bu ürüne JBoss EAP (Enterprise Application Platform) adını veriyor. JBoss EAP, JBoss AS'nin ürüne dönüşmüş hali olarak düşünülebilir. 
JBoss EAP 6, Java EE 6 uyumlu, açık kaynak kodlu, RedHat firmasından desteğini alabileceğiniz, modüler bir mimariye sahip, çevik bir uygulama sunucusudur. JBoss AS 8 ile JBoss AS, Wildfly adını almıştır. Wildfly Java EE 7 uyumludur. Bu yazıda JBoss EAP 6 ve Wildfly 8 için kurulumu, çalışma kipleri, yapılandırılması, kümeleme ve yük dengeleme konuları ile ilgili ayrıntılı bilgiler verilecektir.

Kurulum

JBoss EAP'ın güncel sürümünü (6.4) bu adresten ve Wildfly'ın güncel sürümünü (8.2) ise bu adresten indirebilirsiniz. Kurulum için tek yapmanız gereken sıkıştırılmış arşiv dosyasını uygun bir dizine açmaktır. Kurulumu yaptığınız dizine bir göz atalım:
[.installation]
[appclient]
[bin]
[bundles]
[docs]
[domain]
jboss-modules.jar
JBossEULA.txt
LICENSE.txt
[modules]
[standalone]
version.txt
welcome-content
JBoss'u bağımsız (=standalone) ve alan (=domain) olmak üzere iki farklı kipte kullanabilirsiniz. Eğer elinizin altında bir kaç tane yönetmeniz gereken JBoss sunucusu varsa bağımsız kipi tercih edebilirsiniz. Ancak sunucu sayısı artmaya başladığında, bağımsız kipte yönetmek zorlaşır. Bu durumda alan kipini tercih etmelisiniz. Özellikle yönetiminizdeki bu sunucular, fiziksel olarak yarı ayrı makinalarda bulunuyor ise mutlaka alan kipini düşünmelisiniz. Kümeleme çözümü ise hem bağımsız hem de alan kiplerinde gerçekleştirilebilir. Ancak kümeleme çözümünde yönetmesi ve izlemesi daha kolay olduğu için alan kipini tercih etmelisiniz. Tüm çalıştırılabilir dosyalar ve betikler bin dizinde yer alıyor. Bağımsız kipte çalıştırmak için standalone.bat (standalone.sh) betiğini ve alan kipinde çalıştırmak için domain.bat (domain.sh) betiğini kullanıyoruz. Bağımsız kipte yönetmek gerekli olan tüm dosyalar ve dizinler standalone dizininde ve alan kipinde yönetmek için gerekli olan tüm dosyalar ve dizinler domain dizininde yer alıyor.
JBoss AS 7 modüler bir mimariye sahiptir.  Java EE'nin gelişimini aşağıdaki şekil özetlemektedir:
Her yeni sürümde daha çok API, daha çok servis yer alıyor. Bu kaçınılmaz olarak yekpare (=monolithic) olarak tasarlanan uygulama sunucularının hantallaşmasına neden olmaktadır. Daha yavaş açılmakta ve uygulamaları kapatıp açmak, yeni bir uygulama yayınlamak vakit almaktadır. Bir kurumsal uygulama geliştirirken, bu API'lerin hepsini birden kullanmıyoruz. Uygulama sunucusu, kullanılmayan bu servisleri başlatmak ve ilklendirmek için açılışta vakit kaybediyor. Biz ise uygulama sunucularının çevik olmasını istiyoruz. Bu durumla baş edebilmek için Java EE standardının hamlesi profil kavramı oldu. Gerçi hala bir tane profilimiz bulunuyor: "Web profili". Web profili tüm API'lerin web merkezli mimaride uygulama geliştirilmesine olanak sağlayacak on civarında API barındırıyor:
Java EE 6'da yapılan hatalardan biri JAX-RS'in Web profiline dahil edilmemesiydi. Java EE 7'de bunu düzelttiler. Java EE 6'dan itibaren uygulama sunucusunu iki şekilde edinebilirsiniz: Tüm platform ve Web profili. Web profili daha hafif sıklet bir çözüm sunar ama JMS, JCA gibi uygulamaların tümleştirilmesine yönelik bazı API'leri içermez. Bu karmaşıklıkla baş edebilmek için bazı uygulama sunucusu üreticileri, çözümlerini modüler platformlara taşımaya karar verdiler. Glassfish, WebSphere, Virgo Tomcat Server, SpringDM Server modüler platform olarak OSGi platformunu kullanırken, JBoss ekibi, OSGi'ye göre daha hafif sıklet bir çözüm olan MSC (Modular Service Container)'yi geliştirdi:
Kurulum dizininde yer alan jboss-modules.jar MSC'yi barındırır ve hangi kipte JBoss'u başlatırsanız başlatın, çalışan uygulama jboss-modules.jar dosyasıdır. JBoss'un MSC uyumlu modülleri modules dizininde yer alır. MSC, OSGi modüllerini de çalıştırabilir. OSGi'da modülleri bundle olarak adlandırılır. Bu nedenle OSGi modüllerini bundles dizinine yerleştirmeniz gerekir. MSC modülleri jar dosyalarından ve modülün tanımının verildiği module.xml dosyasından oluşur. module.xml dosyasında ayrıca bir modülün bağımlı olduğu diğer modüllerin listesi verilir. Şimdi örnek bir modül tanımına bakalım:
modules/system/layers/base/org/jboss/as/weld/main:
jboss-as-weld-7.5.0.Final-redhat-21.jar
module.xml
Modül adı ile yer aldığı dizin arasında bir bağlantı var. module.xml dosyasında modülün adı yer alıyor. Ancak module.xml dosyasına bakmadan da modülün adını söyleyebiliriz: org.jboss.as.weld. Tüm modüllerin modules dizini altında olduğunu biliyoruz. Modüller hemen bu dizinin altında yer almazlar, systems/layers/base dizini altından itibaren yerleşirler. Modülün adı dizin yapısını takip eder. org/jboss/as/weld dizin yapısı modül adını ele veriyor. main ise her modülde var olan dizin. OSGi'den farklı olarak MSC'de sürüm numarası bilgisi yoktur. O yüzden sadece main dizini yer alıyor. Belki ileride maven projelerinde olduğu gibi sürüm numarası da yer alabilir. Şimdi, modül tanımını içeren module.xml dosyasına bir göz atalım:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.jboss.as.weld">

    <properties>
        <property name="jboss.api" value="private"/>
    </properties>

    <resources>
        <resource-root path="jboss-as-weld-7.5.0.Final-redhat-21.jar"/>
        <!-- Insert resources here -->
    </resources>

    <dependencies>
        <module name="ch.qos.cal10n" />
        <module name="com.google.guava"/>
        <module name="javax.api"/>
        <module name="javax.annotation.api"/>
        <module name="javax.el.api" />
        <module name="javax.ejb.api" />
        <module name="javax.enterprise.api"/>
        <module name="javax.faces.api"/>
        <module name="javax.interceptor.api"/>
        <module name="javax.persistence.api"/>
        <module name="javax.servlet.api"/>
        <module name="javax.servlet.jsp.api"/>
        <module name="javax.transaction.api"/>
        <module name="org.javassist"/>
        <module name="org.jboss.jandex"/>
        <module name="org.jboss.staxmapper"/>
        <module name="org.jboss.as.controller"/>
        <module name="org.jboss.as.ee"/>
        <module name="org.jboss.as.ejb3"/>
        <module name="org.jboss.as.jpa"/>
        <module name="org.jboss.as.jpa.spi"/>
        <module name="org.jboss.as.naming"/>
        <module name="org.jboss.as.security"/>
        <module name="org.jboss.as.server"/>
        <module name="org.jboss.as.transactions"/>
        <module name="org.jboss.as.web"/>
        <module name="org.jboss.ejb-client"/>
        <module name="org.jboss.ejb3"/>
        <module name="org.jboss.invocation"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.metadata"/>
        <module name="org.jboss.modules"/>
        <module name="org.jboss.msc"/>
        <module name="org.jboss.vfs"/>
        <module name="org.jboss.weld.api" />
        <module name="org.jboss.weld.core" />
        <module name="org.jboss.weld.spi" />
        <module name="org.slf4j" />
        <module name="org.slf4j.ext" />
    </dependencies>
</module>
Kök elemanı module ve bu elemanda modülün adı yer alıyor: name="org.jboss.as.weld". dependencies elemanı altında bu modülün bağımlı olduğu diğer modüllerin listesi veriliyor. resources elemanı ile modülü oluşturan jar dosyalarının listesi verilmektedir. Modüller, MSC'nin  sınıf yükleyicileri (=class loader) tarafından O(1) karmaşıklıkta, çoklu-lifli olarak ve üşengeç (=lazy) yaklaşımla yüklenmektedir. MSC'nin bu özelliği, JBoss sunucularının çok hızlı açılmasını sağlar. Sunucu başlatmak için bir kaç sistem değişkenini ayarlamalıyız:
c:\opt\jboss-eap-6.4>set JAVA_HOME=c:\opt64\java\jdk1.7.0_71
c:\opt\jboss-eap-6.4>set JBOSS_HOME=c:\opt\jboss-eap-6.4
c:\opt\jboss-eap-6.4>set PATH=%JAVA_HOME%\bin;%JBOSS_HOME%\bin;%PATH%
Sunucuyu bağımsız kipte çalıştırmak için
c:\opt\jboss-eap-6.4>start standalone
komutunu çalıştırabilirsiniz. Şimdi yeni pencerede log kayıtları akmaya başlayacaktır:
Calling "c:\opt\jboss-eap-6.4\bin\standalone.conf.bat"
Setting JAVA property to "c:\opt64\java\jdk1.7.0_71\bin\java"
===============================================================================

  JBoss Bootstrap Environment


  JBOSS_HOME: "c:\opt\jboss-eap-6.4"


  JAVA: "c:\opt64\java\jdk1.7.0_71\bin\java"


  JAVA_OPTS: "-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=3M -XX:-TraceClassUnloading -XX:+UseCompressedOops -Dprogram.name=standalone.bat -Xms1G -Xmx1G -XX:Max

PermSize=256M -Djava.net.preferIPv4Stack=true  -Djboss.modules.policy-permissions=true  -Djboss.modules.system.pkgs=org.jboss.byteman"

===============================================================================


12:47:21,529 INFO  [org.jboss.modules] (main) JBoss Modules version 1.3.6.Final-redhat-1

12:47:21,849 INFO  [org.jboss.msc] (main) JBoss MSC version 1.1.5.Final-redhat-1
12:47:21,943 INFO  [org.jboss.as] (MSC service thread 1-6) JBAS015899: JBoss EAP 6.4.0.GA (AS 7.5.0.Final-redhat-21) starting
12:47:23,229 INFO  [org.xnio] (MSC service thread 1-8) XNIO Version 3.0.13.GA-redhat-1
12:47:23,232 INFO  [org.jboss.as.server] (Controller Boot Thread) JBAS015888: Creating http management service using socket-binding (management-http)
12:47:23,237 INFO  [org.xnio.nio] (MSC service thread 1-8) XNIO NIO Implementation Version 3.0.13.GA-redhat-1
12:47:23,286 INFO  [org.jboss.remoting] (MSC service thread 1-8) JBoss Remoting version 3.3.4.Final-redhat-1
12:47:23,288 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 31) JBAS010280: Activating Infinispan subsystem.
12:47:23,390 INFO  [org.jboss.as.connector.logging] (MSC service thread 1-7) JBAS010408: Starting JCA Subsystem (IronJacamar 1.0.31.Final-redhat-1)
12:47:23,406 INFO  [org.jboss.as.jsf] (ServerService Thread Pool -- 37) JBAS012615: Activated the following JSF Implementations: [main, 1.2]
12:47:23,446 INFO  [org.jboss.as.security] (ServerService Thread Pool -- 44) JBAS013371: Activating Security Subsystem
12:47:23,442 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 27) JBAS010403: Deploying JDBC-compliant driver class org.h2.Driver (version 1.3)
12:47:23,429 INFO  [org.jboss.as.naming] (ServerService Thread Pool -- 39) JBAS011800: Activating Naming Subsystem
12:47:23,452 INFO  [org.jboss.as.security] (MSC service thread 1-1) JBAS013370: Current PicketBox version=4.1.1.Final-redhat-1
12:47:23,472 WARN  [org.jboss.as.txn] (ServerService Thread Pool -- 46) JBAS010153: Node identifier property is set to the default value. Please make sure it is unique.
12:47:23,469 INFO  [org.jboss.as.mail.extension] (MSC service thread 1-3) JBAS015400: Bound mail session [java:jboss/mail/Default]
12:47:23,468 INFO  [org.jboss.as.naming] (MSC service thread 1-4) JBAS011802: Starting Naming Service
12:47:23,563 INFO  [org.jboss.as.webservices] (ServerService Thread Pool -- 48) JBAS015537: Activating WebServices Extension
12:47:23,714 INFO  [org.apache.coyote.http11.Http11Protocol] (MSC service thread 1-1) JBWEB003001: Coyote HTTP/1.1 initializing on : http-/127.0.0.1:8080
12:47:23,788 INFO  [org.apache.coyote.http11.Http11Protocol] (MSC service thread 1-1) JBWEB003000: Coyote HTTP/1.1 starting on: http-/127.0.0.1:8080
12:47:23,973 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-6) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS]
12:47:24,029 INFO  [org.jboss.as.server.deployment.scanner] (MSC service thread 1-4) JBAS015012: Started FileSystemDeploymentService for directory c:\opt\jboss-eap-6.4\standalone\deployments
12:47:24,039 INFO  [org.jboss.as.remoting] (MSC service thread 1-8) JBAS017100: Listening on 127.0.0.1:4447
12:47:24,039 INFO  [org.jboss.as.remoting] (MSC service thread 1-7) JBAS017100: Listening on 127.0.0.1:9999
12:47:24,131 INFO  [org.jboss.ws.common.management] (MSC service thread 1-5) JBWS022052: Starting JBoss Web Services - Stack CXF Server 4.3.4.Final-redhat-1
12:47:24,215 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management
12:47:24,216 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990

12:47:24,217 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss EAP 6.4.0.GA (AS 7.5.0.Final-redhat-21) started in 3217ms - Started 153 of 191 services (57 services are lazy, passive or on-demand)
191 servisten sadece 153'ünü başlattı. Açılış süresi 3 saniye civarında sınırlı kaldı. Sunucunun başarılı bir şekilde başladığını anlamanın yolu, bir web tarayıcı açıp http://localhost:8080 adresine bakmaktır:
Bu sayfayı görüyorsanız kurulumu başarı ile tamamladınız demektir. Yönetim paneline erişmek için sayfadaki bağlantıya gitmeye çalışırsanız, JBoss size uyarıda bulunacaktır:
Önce bir ManagementRealm'de bir kullanıcı yaratmalısınız. Bunun için add-user komutunu kullanabilirsiniz:
c:\opt\jboss-eap-6.4>add-user

What type of user do you wish to add?
 a) Management User (mgmt-users.properties)
 b) Application User (application-users.properties)
(a): <Enter>

Enter the details of the new user to add.
Using realm 'ManagementRealm' as discovered from the existing property files.
Username : jack
Password requirements are listed below. To modify these restrictions edit the add-user.properties configuration file.
 - The password must not be one of the following restricted values {root, admin, administrator}
 - The password must contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s)
 - The password must be different from the username
Password : Secret_123
Re-enter Password : Secret_123
What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[  ]: <Enter>
About to add user 'jack' for realm 'ManagementRealm'
Is this correct yes/no? yes
Added user 'jack' to file 'C:\opt\jboss-eap-6.4\standalone\configuration\mgmt-users.properties'
Added user 'jack' to file 'C:\opt\jboss-eap-6.4\domain\configuration\mgmt-users.properties'
Added user 'jack' with groups  to file 'C:\opt\jboss-eap-6.4\standalone\configuration\mgmt-groups.properties'
Added user 'jack' with groups  to file 'C:\opt\jboss-eap-6.4\domain\configuration\mgmt-groups.properties'
Is this new user going to be used for one AS process to connect to another AS process? <Enter>
e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls.
yes/no? yes
To represent the user add the following to the server-identities definition <secret value="U2VjcmV0XzEyMw==" />
Press any key to continue . . .
Artık yönetim paneline bağlanıp, yönetim panelinin yeteneklerine bir göz atabilirsiniz. Ama hemen uyarayım, çok fazla bir beklentiniz olmasın. Weblogic'in yönetim konsolu ile karşılaştırılamayacak basitlikte bir yönetim paneli bulacaksınız:
JBoss'un yönetimsel tarafta asıl güçlü olduğu aracı, komut satırında çalışan jboss-cli'dır. jboss-cli ile her türlü yönetimsel işlemi yapabilirsiniz. Biz ise ilk olarak sunucuyu nasıl kapatılabileceğine bakalım:
c:\opt\jboss-eap-6.4>jboss-cli --connect --controller=localhost --command=:shutdown
{"outcome" => "success"}
Press any key to continue . . .
Komut başarı ile çalıştı. Komutun, JSON (JavaScript Object Notation) formatına benzer bir çıktı ürettiğine dikkat etmişsinizdir. Şimdi, jboss-cli kullanarak 8080 olan http portunu 80 olarak değiştirelim:
[standalone@localhost:9999 /] /socket-binding-group=standard-sockets/socket-binding=http:read-resource
{
    "outcome" => "success",
    "result" => {
        "client-mappings" => undefined,
        "fixed-port" => false,
        "interface" => undefined,
        "multicast-address" => undefined,
        "multicast-port" => undefined,
        "name" => "http",

        "port" => 8080

[standalone@localhost:9999 /] /socket-binding-group=standard-sockets/socket-binding=http:write-attribute(name=port,value=80)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}

[standalone@localhost:9999 /] :reload
{
    "outcome" => "success",
    "result" => undefined

}
jboss-cli komutunu kullanırken Tab tuşundan yararlanabilirsiniz. Tab tuşuna her bastığınızda, size bir kısmını yazdığınız komutu tamamlar ya da olası seçeneklerin bir listesini sunar. jboss-cli komutunu isterseniz kullanıcı arayüzü üzerinden de kullanabilirsiniz: 
jboss-cli --connect --gui


JBoss Sunucusunu İzlemek

Çalışan JBoss sunucularının listesini farklı şekillerde öğrenebiliriz:
  • jps
jps kullanarak çalışan Java uygulamalarının bir listesini almak mümkündür.

jps -lmv
10148 c:\opt\jboss-eap-6.4\jboss-modules.jar -mp c:\opt\jboss-eap-6.4\modules -jaxpmodule javax.xml.jaxp-provider org.jboss.as.standalone -Djboss.home.dir=c:\opt\jboss-eap-6.4 -Xloggc:c:\opt\jboss-eap-6.4\standalone\log\gc.log -
verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=3M -XX:-TraceClassUnloading -XX:+UseCompressedOops -Dprogram.name=standalone.bat -Xms1G -Xmx1G -XX:MaxPermSize=256M -
Djava.net.preferIPv4Stack=true -Djboss.modules.policy-permissions=true -Djboss.modules.system.pkgs=org.jboss.byteman -Dorg.jboss.boot.log.file=c:\opt\jboss-eap-6.4\standalone\log\server.log -Dlogging.configuration=file:c:\opt\jboss-ea
p-6.4\standalone\configuration/logging.properties
  • jcmd
Bu komutu kullanabilmek için jdk 7u40 ya da sonrasında bir JDK kullanmak gerekir:
jcmd -l
10148 c:\opt\jboss-eap-6.4\jboss-modules.jar -mp c:\opt\jboss-eap-6.4\modules -jaxpmodule javax.xml.jaxp-provider org.jboss.as.standalone -Djboss.home.dir=c:\opt\jboss-eap-6.4

jcmd 10148 VM.version
10148:
Java HotSpot(TM) 64-Bit Server VM version 24.71-b01
JDK 7.0_71

jcmd 10148 VM.flags
10148:
-XX:GCLogFileSize=3145728 -XX:InitialHeapSize=1073741824 -XX:MaxHeapSize=1073741824 -XX:MaxPermSize=268435456 -XX:NumberOfGCLogFiles=5 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:-TraceClassUnloading -
XX:+UseCompressedOops -XX:+UseGCLogFileRotation -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

jcmd 10148 VM.uptime
10148:
2172.027 s
  • jconsole
jconsole, JDK içinden çıkan Java uygulamalarını izlemek için geliştirilmiş, jps ve jcmd'de olduğu gibi uzaktaki bir makinadaki Java uygulamalarını izlemek için de kullanılabilecek bir pencere uygulamasıdır. Özellikle JMX konsolü nedeni ile JBoss sunucusunu JMX üzerinden yönetmek için kullanılabilir:


  • jvisualvm
jvisualvm, JDK içinden çıkan Java uygulamalarını izlemek için geliştirilmiş, jconsole'a göre çok daha üstün özellikleri olan, NetBeans RCP ile geliştirilmiş, eklentiler yükleyerek zenginleştirilebilen,  jps, jcmd, ve jconsole'da olduğu gibi uzaktaki bir makinadaki Java uygulamalarını izlemek için de kullanılabilecek bir pencere uygulamasıdır. Özellikle HeapDump ve ThreadDump Analizi, Tracer, Profiler gibi yetenekleri ile öne çıkmaktadır.



  • jmc
Bu komutu kullanabilmek için jdk 7u40 ya da sonrasında bir JDK kullanmak gerekir. Mission Control, Oracle jRockit JSM'si (Java Sanal Makinası) içinde yer alan bir izleme aracıydı. Oracle, jRockit geliştirilmesini durduğunda, içindeki bazı araçları HotSpot JSM'sine aktardı. jmc bu aktardığı araçlardan biridir ve ticari kullanımı ücretli, kişisel kullanımı ise ücretsizdir. Bu ürünü kullanabilmek için uygulamayı -XX:+UnlockCommercialFeatures ve -XX:+FlightRecorder seçenekleri ile birlikte çalıştırmanız gerekir:
set "JAVA_OPTS=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder"
start standalone
jmc

JBoss Suncusunun Yapılandırılması

Bağımsız Kipte Yapılandırma

Bu kipte yapılandırma dosyaları standalone/configuration dizininde yer alır. Bu dizinde hazır beş tane yapılandırma dosyası yer alır: standalone.xml, standalone-ha.xml, standalone-full.xml, standalone-full-ha.xml ve standalone-osgi.xml. JBoss modüler bir mimariye sahiptir. Kendi ihtiyaçlarınıza göre kendi JBoss'unuzu tanımlayabilirsiniz. Tek yapmanız gereken, yukarıda listelenen ve JBoss kurulumu ile hazır olarak gelen yapılandırma dosyalarından, size yakın olanını seçip,  bağımlılıkları gözeterek, servisleri eklemek ya da çıkarmaktır. Aynı Lego parçalarından kendinize ev, itfaiye arabası, gemi ya da uçak yapmaya benziyor. Yapılandırma dosyasının adındaki full, tüm servisleri içerdiğini, ha ise kümeleme ile ilgili servisleri içerdiğini tanımlamak için kullanılmıştır. Herhangi bir yapılandırma dosyası vermediğinizde standalone.xml dosyasını kullanıyor. standalone-full.xml ile başlatmak isterseniz aşağıdaki komutu yazmalısınız:
c:\opt\jboss-eap-6.4>start standalone -c standalone-full.xml
ya da 
c:\opt\jboss-eap-6.4>start standalone --server-config standalone-full.xml
Şimdi, standalone-full.xml yapılandırma dosyasında, daha fazla sayıda servis tanımlı olduğu için açılış biraz daha uzun sürdü, daha fazla sayıda servis yüklendi:
. . . . . . . . . . . . . . . 
15:35:12,892 INFO  [org.hornetq.ra] (MSC service thread 1-1) HornetQ resource adaptor started
15:35:12,893 INFO  [org.jboss.as.connector.services.resourceadapters.ResourceAdapterActivatorService$ResourceAdapterActivator] (MSC service thread 1-1) IJ020002: Deployed: file://RaActivatorhornetq-ra
15:35:12,895 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-4) JBAS010401: Bound JCA ConnectionFactory [java:/JmsXA]
15:35:12,971 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management
15:35:12,972 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990
15:35:12,972 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss EAP 6.4.0.GA (AS 7.5.0.Final-redhat-21) started in 3619ms - Started 192 of 229 services (68 services are lazy, passive or on-demand)
Şimdi standalone-full.xml yapılandırma dosyasına bir göz atalım:
  • Kök elemanı server
  • Hemen altında extensions ile modüllerin listesi veriliyor:
  <extensions>
        <extension module="org.jboss.as.clustering.infinispan"/>
        <extension module="org.jboss.as.cmp"/>
        <extension module="org.jboss.as.connector"/>
        <extension module="org.jboss.as.deployment-scanner"/>
        <extension module="org.jboss.as.ee"/>
        <extension module="org.jboss.as.ejb3"/>
        <extension module="org.jboss.as.jacorb"/>
        <extension module="org.jboss.as.jaxr"/>
        <extension module="org.jboss.as.jaxrs"/>
        <extension module="org.jboss.as.jdr"/>
        <extension module="org.jboss.as.jmx"/>
        <extension module="org.jboss.as.jpa"/>
        <extension module="org.jboss.as.jsf"/>
        <extension module="org.jboss.as.jsr77"/>
        <extension module="org.jboss.as.logging"/>
        <extension module="org.jboss.as.mail"/>
        <extension module="org.jboss.as.messaging"/>
        <extension module="org.jboss.as.naming"/>
        <extension module="org.jboss.as.pojo"/>
        <extension module="org.jboss.as.remoting"/>
        <extension module="org.jboss.as.sar"/>
        <extension module="org.jboss.as.security"/>
        <extension module="org.jboss.as.threads"/>
        <extension module="org.jboss.as.transactions"/>
        <extension module="org.jboss.as.web"/>
        <extension module="org.jboss.as.webservices"/>
        <extension module="org.jboss.as.weld"/>
    </extensions>

  • extentions'ın devamında management elemanı yer alır. Bu elemanın için kullanıcı bilgilerinin nereden alınacağı, loglamanın  nereye ve nasıl yapılacağının ayarları yer alır.
  • profile elemanı içinde her bir subsystem içinde, yukarıda extensions'da verilen modüllerin teker teker ayarları yapılır:
     . . . . . .      
        <subsystem xmlns="urn:jboss:domain:ee:1.2">
            <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
            <jboss-descriptor-property-replacement>true</jboss-descriptor-property-replacement>
            <annotation-property-replacement>false</annotation-property-replacement>
        </subsystem>
      . . . . . .
Bu ayarlarda değişiklikler dört şekilde yapılabilinir:
  1. Doğrudan yapılandırma dosyasına değişiklik yapmak: Sunucuyu her durumda yeniden başlatmak gerekir.
  2. Yönetim panelini kullanmak: Yetenekleri kısıtlıdır. Çoğu ayar için arayüzde bir karşılık bulamazsınız. Bazı değişiklikler sunucuyu yeniden başlatmayı gerektirebilir.
  3. jboss-cli komutunu kullanmak: Her türlü ayarı komut satırından yapabilirsiniz. Bazı değişiklikler sunucuyu yeniden başlatmayı gerektirebilir.
  4. JMX konsol kullanmak: jconsole, jvisualvm kullanarak MBean'lerin özniteliklerinin değerini değiştirebilir ya da metotlarını çağırabilirsiniz.  Bazı değişiklikler sunucuyu yeniden başlatmayı gerektirebilir.

Alan Kipinde Yapılandırma

Bu kip aynı ya da farklı fiziksel makinada yer alan sunucuları yönetmeyi amaçlıyor. Yapılandırma dosyaları artık standalone/configuration dizininde değil, domain/configuration dizininde yer alıyor. Üstelik artık iki tane yapılandırma dosyamız var: domain.xml ve host.xml. Değişiklik sadece yapılandırma dosyaları ile sınırlı değil. Mimarimizde de önemli bir kaç değişiklik var. Artık her fiziksel makinada çalışan JBoss sunucuları dışında iki Java prosesi daha bulunuyor: Alan denetçisi (=Domain Controller) ya da duruma göre Ev sahibi Denetçi (=Host Controller) ile Proses Denetçisi (=Process Controller). Proses denetçisi, bekçi köpeği işlevi görmektedir, JBoss sunucularını, makina denetçisinden gelen istek üzerine kapatır ya da açar, makinadaki sunuculardan biri sorun yaşar ve istenmeyen bir şekilde kapanırsa, yeniden başlatır. Aşağıdaki şekilde dört fiziksel düğümden oluşan bir alan verilmiştir. Bu dört düğümden birinde (host1) alan denetçisi çalışmaktadır. Alan denetçisi alandaki düğümlerin yapılandırma dosyasını ve bilgilerini taşır. Diğer düğümlerde ise ev sahibi denetçisi, açılışta yapılandırma bilgisini ve daha sonra ise yapılandırmadaki değişiklikleri, host1'deki alan denetçisinden  alır.
Her düğümün kendi host.xml dosyası bulunur ve içinde sunucu tanımları yer alır. Bu sunucuların yapılandırması ise host1'deki domain.xml'de yer alır. Her düğüm (host2, host3 ve host4) bu yapılandırma bilgisini, yerelde çalışan ev sahibi denetçi üzerinden host1'deki alan denetçisinden edinir. host1 192.168.1.1'li ip adresinde, host2 192.168.1.2'li ip adresinde, host3 192.168.1.3'lü ip adresinde ve host4 ise 192.168.1.4'lü ip adresinde yer alsın. host3'ün host.xml dosyasına bir bakalım:
<host name="host3" xmlns="urn:jboss:domain:1.7">
    <management>
        <security-realms>
            <security-realm name="ManagementRealm">
                <server-identities>
                     <secret value="c2xhdmVfdXNlcl9wYXNzd29yZA=="/>

                </server-identities>
    . . . . . . . .
    <domain-controller>
       <remote host="192.168.1.1" port="${jboss.domain.master.port:9999}" security-realm="ManagementRealm"/>
    </domain-controller>

    <interfaces>
        <interface name="management">
            <inet-address value="${jboss.bind.address.management:192.168.1.3}"/>
        </interface>
        <interface name="public">
           <inet-address value="${jboss.bind.address:192.168.1.3}"/>
        </interface>
        <interface name="unsecure">        
            <inet-address value="${jboss.bind.address.unsecure:192.168.1.3}"/>
        </interface>
    </interfaces>

    <jvms>
      <jvm name="default">
            <heap size="64m" max-size="256m"/>
            <permgen size="256m" max-size="256m"/>
              <jvm-options>
                  <option value="-server"/>
              </jvm-options>
         </jvm>
    </jvms>

    <servers>
        <server name="server6" group="backup"/>
        <server name="server7" group="backup">
            <socket-bindings port-offset="100"/>
        </server>
    </servers>
</host>
</host>
host3'de, host.xml yapılandırma dosyasında, alan denetçisi aşağıdaki satırda tanıtıldığını görüyoruz:
    <domain-controller>
       <remote host="192.168.1.1" port="${jboss.domain.master.port:9999}" security-realm="ManagementRealm"/>
    </domain-controller>
Ancak host1'de host2, host3 ve host4 adında birer kullanıcı yaratılmış olması gerekiyor. Kullanıcı parolasının, Base64 olarak kodlanarak host.xml'de aşağıdaki gibi tanımlanması gerekir:
        <security-realms>
            <security-realm name="ManagementRealm">
                <server-identities>
                     <secret value="c2xhdmVfdXNlcl9wYXNzd29yZA=="/>
                </server-identities>
          . . . . . . . . 
Kullanıcının nasıl yaratıldığını daha önce incelemiştik. Bu amaçla user-add komutu kullanıldığını biliyorsunuz. Şimdi dikkatle tekrar bakarsanız, en son komutun çıktısında, <secret value="Base64 kodlanmış parola"/> tanımında kullanıma hazır, Base64 kodlanmış parolanın yazdığını göreceksiniz.
Sunucuları alan kipinde başlatmak için her düğümde domain.bat komutunu çalıştırmak yeterli olacaktır.
host1'deki domain.xml yapılandırma dosyasında tüm düğümlerdeki host.xml'de tanımlı olan sunucuların ayarları yer alır. Ayarları ve sunucuları kolay yönetmek için sunucu grubu kavramı geliştirilmiştir. Sunucular gruplara atanmıştır: <server name="server6" group="backup"/>. backup grubunun ayarları domain.xml'de tanıtılır:
<server-groups>
     <server-group name="main" profile="default">
         <jvm name="default">
             <heap size="1000m" max-size="1000m"/>
             <permgen max-size="256m"/>
         </jvm>
         <socket-binding-group ref="standard-sockets"/>
     </server-group>
     <server-group name="backup" profile="default">
         <jvm name="default">
             <heap size="1000m" max-size="1000m"/>
             <permgen max-size="256m"/>
         </jvm>
         <socket-binding-group ref="standard-sockets"/>
     </server-group>
</server-groups>
Burada iki grubun olduğuna dikkat edin:
  1. Sunucu grupları (=Server Groups)
  2. Soket bağlama grupları (=Socket Binding Groups)
Soket bağlama grupları ise yine domain.xml'de tanıtılır:
<socket-binding-groups>
        <socket-binding-group name="standard-sockets" default-interface="public">
            <socket-binding name="ajp" port="8009"/>
            <socket-binding name="http" port="8080"/>
            <socket-binding name="https" port="8443"/>
            <socket-binding name="remoting" port="4447"/>
            <socket-binding name="txn-recovery-environment" port="4712"/>
            <socket-binding name="txn-status-manager" port="4713"/>
            <outbound-socket-binding name="mail-smtp">
                <remote-destination host="localhost" port="25"/>
            </outbound-socket-binding>
        </socket-binding-group>
        <socket-binding-group name="ha-sockets" default-interface="public">
            <socket-binding name="ajp" port="8009"/>
            <socket-binding name="http" port="8080"/>
            <socket-binding name="https" port="8443"/>
            <socket-binding name="jgroups-mping" port="0" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
            <socket-binding name="jgroups-tcp" port="7600"/>
            <socket-binding name="jgroups-tcp-fd" port="57600"/>
            <socket-binding name="jgroups-udp" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
            <socket-binding name="jgroups-udp-fd" port="54200"/>
            <socket-binding name="modcluster" port="0" multicast-address="224.0.1.105" multicast-port="23364"/>
            <socket-binding name="remoting" port="4447"/>
            <socket-binding name="txn-recovery-environment" port="4712"/>
            <socket-binding name="txn-status-manager" port="4713"/>
            <outbound-socket-binding name="mail-smtp">
                <remote-destination host="localhost" port="25"/>
            </outbound-socket-binding>
        </socket-binding-group>
        <socket-binding-group name="full-sockets" default-interface="public">
            <socket-binding name="ajp" port="8009"/>
            <socket-binding name="http" port="8080"/>
            <socket-binding name="https" port="8443"/>
            <socket-binding name="jacorb" interface="unsecure" port="3528"/>
            <socket-binding name="jacorb-ssl" interface="unsecure" port="3529"/>
            <socket-binding name="messaging" port="5445"/>
            <socket-binding name="messaging-group" port="0" multicast-address="${jboss.messaging.group.address:231.7.7.7}" multicast-port="${jboss.messaging.group.port:9876}"/>
            <socket-binding name="messaging-throughput" port="5455"/>
            <socket-binding name="remoting" port="4447"/>
            <socket-binding name="txn-recovery-environment" port="4712"/>
            <socket-binding name="txn-status-manager" port="4713"/>
            <outbound-socket-binding name="mail-smtp">
                <remote-destination host="localhost" port="25"/>
            </outbound-socket-binding>
        </socket-binding-group>
        <socket-binding-group name="full-ha-sockets" default-interface="public">
            <socket-binding name="ajp" port="8009"/>
            <socket-binding name="http" port="8080"/>
            <socket-binding name="https" port="8443"/>
            <socket-binding name="jacorb" interface="unsecure" port="3528"/>
            <socket-binding name="jacorb-ssl" interface="unsecure" port="3529"/>
            <socket-binding name="jgroups-mping" port="0" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45700"/>
            <socket-binding name="jgroups-tcp" port="7600"/>
            <socket-binding name="jgroups-tcp-fd" port="57600"/>
            <socket-binding name="jgroups-udp" port="55200" multicast-address="${jboss.default.multicast.address:230.0.0.4}" multicast-port="45688"/>
            <socket-binding name="jgroups-udp-fd" port="54200"/>
            <socket-binding name="messaging" port="5445"/>
            <socket-binding name="messaging-group" port="0" multicast-address="${jboss.messaging.group.address:231.7.7.7}" multicast-port="${jboss.messaging.group.port:9876}"/>
            <socket-binding name="messaging-throughput" port="5455"/>
            <socket-binding name="modcluster" port="0" multicast-address="224.0.1.105" multicast-port="23364"/>
            <socket-binding name="remoting" port="4447"/>
            <socket-binding name="txn-recovery-environment" port="4712"/>
            <socket-binding name="txn-status-manager" port="4713"/>
            <outbound-socket-binding name="mail-smtp">
                <remote-destination host="localhost" port="25"/>
            </outbound-socket-binding>
        </socket-binding-group>
    </socket-binding-groups>

JBoss Suncusuna Uygulama Dağıtmak

Bağımsız Kipte Uygulama Dağıtmak

Bağımsız kipte uygulama dağıtmak için ilk çalışacağımız yöntem, deployment-scanner servisi kullanmaktır. Bu servis belirli aralıklarla ayarlarda tanımlanan dizini, belirli aralıkla yoklar. Buraya bırakılan dosyaları otomatik olarak yayınlar. Aynı zamanda, dağıtım durumunu izleyebilir, uygulamanın yaşam döngüsü ile ilgili komut verebiliriz. Servisin ayarları için varsayılan yapılandırma dosyası, standalone.xml'deki tanımlamaya bakalım:
        <subsystem xmlns="urn:jboss:domain:deployment-scanner:1.1">
            <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000"/>
        </subsystem>
Bu tanımda, 5'er saniye aralıklarla standalone/deployments dizinini yoklayacak şekilde kurgulandığını anlıyoruz. Bu ayarları çalışma zamanında jboss-cli ile değiştirebiliriz:
c:\opt\jboss-eap-6.4>jboss-cli --connect
[standalone@localhost:9999 /] /subsystem=deployment-scanner/scanner=default
:  /
[standalone@localhost:9999 /] /subsystem=deployment-scanner/scanner=default:
add                         read-children-types         read-resource-description   whoami
read-attribute              read-operation-description  remove                      write-attribute
read-children-names         read-operation-names        resolve-path
read-children-resources     read-resource               undefine-attribute
[standalone@localhost:9999 /] /subsystem=deployment-scanner/scanner=default:write-attribute(
name=   value=
[standalone@localhost:9999 /] /subsystem=deployment-scanner/scanner=default:write-attribute(name=
relative-to           auto-deploy-exploded  scan-enabled          auto-deploy-zipped
path                  auto-deploy-xml       scan-interval         deployment-timeout
[standalone@localhost:9999 /] /subsystem=deployment-scanner/scanner=default:write-attribute(name=scan-interval,value=10000)
{"outcome" => "success"}
[standalone@localhost:9999 /] /subsystem=deployment-scanner/scanner=default:write-attribute(name=
relative-to           auto-deploy-exploded  scan-enabled          auto-deploy-zipped
path                  auto-deploy-xml       scan-interval         deployment-timeout
[standalone@localhost:9999 /] /subsystem=deployment-scanner/scanner=default:write-attribute(name=path,value=deps)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
[standalone@localhost:9999 /] :reload
{
    "outcome" => "success",
    "result" => undefined
}
SimpleWebApplication.war ve NumberGuessingGameWebApp.war gibi iki web uygulamasını dağıtmak için deps dizinine bırakmamız yeterli olacaktır. Önce aynı isimde ama "isdeploying" uzantılı bir dosya oluşacaktır. Bir süre sonra, dağıtım başarılı olursa, bu dosyanın uzantısı "isdeploying"'den "deployed"'a dönüşecektir. Eğer bir problem oluşursa uzantı "failed" olacaktır. Dosyanın içinde ise hatanın açıklaması yer alır:



Uzantıyı komut vermek için kullanabiliriz. SimpleWebApplication.war.deployed dosyasını SimpleWebApplication.war.undeploy olarak değiştirirsek ya da SimpleWebApplication.war dosyasını silersek uygulamayı yayından kaldırır. Ardından SimpleWebApplication.war.undeployed isimli bir dosya oluşacaktır.
jboss-cli komutunu kullanarak uygulama dağıtımı yapabiliriz:
jboss-cli --connect "--command=deploy c:\tmp\SimpleWebApplication.war"
Eğer uygulamanın yeni sürümünü yayınlamak istiyorsak --force seçeneğini kullanmak gerekir:
jboss-cli --connect "--command=deploy --force c:\tmp\SimpleWebApplication.war"
Yayınlanan uygulamaların listesini almak için deployment-info komutunu kullanıyoruz:
jboss-cli --connect "--command=deployment-info"
NAME                         RUNTIME-NAME                 PERSISTENT ENABLED STATUS
NumberGuessingGameWebApp.war NumberGuessingGameWebApp.war false      true    OK
SimpleWebApplication.war     SimpleWebApplication.war     true       true    OK
Press any key to continue . . .
Bir uygulamayı yayından kaldırmak için ise undeploy komutunu kullanıyoruz:
jboss-cli --connect "--command=undeploy SimpleWebApplication.war"
Press any key to continue . . .

jboss-cli --connect "--command=deployment-info"
NAME                         RUNTIME-NAME                 PERSISTENT ENABLED STATUS
NumberGuessingGameWebApp.war NumberGuessingGameWebApp.war false      true    OK
Üçüncü yöntem ise yönetim panelini kullanmaktır. Burada Deployments menüsünde Add butonuna basarak war dosyasını ekliyoruz ve etkinleştiriyoruz:



Yayından kaldırmak, durdurmak ve yeniden başlatmak için önce dağıtım listesinden uygulamayı seçmeli ve ardından ilgili işlemin butonuna basmalısınız.

Alan Kipinde Uygulama Dağıtmak

Alan kipinde de jboss-cli kullanarak dağıtım yapılabilir. Yukarıda bağımsız kipte anlatılanlar yine geçerlidir.  İki noktada farklılık var:
1. Dağıtım, alan denetçisi düğüme bağlanılarak yapılır. Bu yazıda kullanılan örnek için bu host1 isimli düğümdür.
2. Alan kipinde sunucu grupları yaratılarak, aynı gruptaki sunucular toplu olarak yönetilir. Aynı gruptaki sunucuların yapılandırma ayarları ortaktır, toplu olarak kapatılıp, yeniden başlatılabilir. Benzer şekilde bir uygulamanın dağıtımı yapılırken, uygulamanın eklenmesi istenilen sunucu grupları seçilir:
c:\opt.cw\jboss-eap-6.4>jboss-cli --connect --controller=localhost
[domain@localhost:9999 /] deploy
deploy              deployment-info     deployment-overlay
[domain@localhost:9999 /] deploy c:\tmp\SimpleWebApplication.war --
--all-server-groups  --force              --name=              --script=            --unmanaged
--disabled           --headers=           --runtime-name=      --server-groups=
[domain@localhost:9999 /] deploy c:\tmp\SimpleWebApplication.war --server-groups=
backup  main
[domain@localhost:9999 /] deploy c:\tmp\SimpleWebApplication.war --server-groups=main
[domain@localhost:9999 /] deployment-info --
--headers=       --help           --name=          --server-group=
[domain@localhost:9999 /] deployment-info --server-group=main
NAME                     RUNTIME-NAME             STATE
SimpleWebApplication.war SimpleWebApplication.war enabled
[domain@localhost:9999 /] deploy c:\tmp\NumberGuessingGameWebApp_ha.war --all-server-groups
[domain@localhost:9999 /] deployment-info --server-group=main
NAME                            RUNTIME-NAME                    STATE
NumberGuessingGameWebApp_ha.war NumberGuessingGameWebApp_ha.war enabled
SimpleWebApplication.war        SimpleWebApplication.war        enabled
[domain@localhost:9999 /] deployment-info --server-group=backup
NAME                            RUNTIME-NAME                    STATE
NumberGuessingGameWebApp_ha.war NumberGuessingGameWebApp_ha.war enabled
SimpleWebApplication.war        SimpleWebApplication.war        not added
Alan kipinde, bağımsız kipte olduğu gibi yönetim paneli kullanılarak basit bir şekilde dağıtım yapılabilir. Tek farklılık, jboss-cli uygulamasındaki farklılık da olduğu gibi  uygulamanın çalıştırılması istenilen sunucu gruplarının seçimi aşamasıdır:


JBoss EAP Kümeleme Kurulumu

JBoss kümeleme çözümü için çeşitli servislerden yararlanır:
  • Oturum bilgisini Infinispan dağıtık cep (=distributed cache) sunucusunda tutar.
  • Dağıtık cep sunucuları arasındaki haberleşme için JGroups servisini kullanır.
  • Yük dengeleme için ise mod_cluster servisini kullanır.
JBoss kümeleme yapılandırması, yukarıdaki anlatılan temel kavramları biliyorsanız, son derece kolaydır. Biri profil seçiminde, diğer soket bağlantı grubu seçiminde olmak üzerer iki ayar yapmanız gerekiyor:
1. domain.xml dosyasında, kümeleme yapmak istediğiniz sunucu gruplarını "ha" profillerden birinden seçmek
2. Kümeleme yapmak istediğiniz sunucu grubunun tanımında "ha" soket bağlantılardan birini seçmek
Örnek bir yapılandırma aşağıdaki gibi olabilir:
<server-groups>
        <server-group name="main" profile="ha">
            <jvm name="default">
                <heap size="1000m" max-size="1000m"/>
                <permgen max-size="256m"/>
            </jvm>
            <socket-binding-group ref="ha-sockets"/>
            </deployments>
        </server-group>
        <server-group name="backup" profile="ha">
            <jvm name="default">
                <heap size="1000m" max-size="1000m"/>
                <permgen max-size="256m"/>
            </jvm>
            <socket-binding-group ref="ha-sockets"/>
        </server-group>
    </server-groups>

JBoss için Yük Dengeleme Çözümü

Her kümeleme çözümünde bir yük dengeleyiciye ihtiyaç vardır. Kümeleme çözümü dışarıya yük dengeleyici üzerinden açılır. Yük dengeleyici, gelen istekleri, sunuculara dağıtmaktan sorumludur. Aynı oturumdan gelen istekleri aynı kümeleme sunucusuna yönlendirme özelliğine sahiplerdir. Kümeleme sunucularının kalp atışlarını dinlerler. Kalp atışını alamadığında, istekleri başka sunuya yönlendirirler. Yükü farklı stratejilerle dağıtabilirler. Yük dengeleyici donanımsal ya da yazılımsal olarak edinilebilir. NetScaler, F5 gibi donanımsal yük dengeleyici çözümlerin başarımı daha yüksektir. Üstelik yük dengeleme dışında, ateş duvarı, iletişim protokol yükünün yıkılması gibi yan görevleri de yüksek başarımla yerine getirebilirler.
Bu yazıda, yük dengeleyici olarak Apache Web Sunucusu üzerinde çalışan mod_cluster modülü kullanılacaktır. mod_cluster bir JBoss projesidir ve bu bağlantıdan indirilebilir. İndirdiğiniz zip dosyasını uygun bir dizine açın. bin dizinindeki installconf.bat betiğini bir kereliğine çalıştırın. Gerekli yapılandırma dosyalarını oluşturacaktır. Buradaki en önemli yapılandırma dosyası conf dizinindeki httpd.conf dosyasıdır. Bu dosyanın sonunda mod_cluster modülünün yapılandırılması ile ilgili satırlar yer alır:
<IfModule manager_module>
  Listen 192.168.1.100:6666
  ManagerBalancerName mycluster
  <VirtualHost 192.168.1.100:6666>
    <Location />
     Order deny,allow
     Deny from all
     Allow from 192.168.1
    </Location>

    KeepAliveTimeout 300
    MaxKeepAliveRequests 0
    ServerAdvertise on http://192.168.1.100:6666
    AdvertiseFrequency 5
    #AdvertiseSecurityKey secret
    AdvertiseGroup 224.0.1.105:23364
    EnableMCPMReceive

    <Location /mod_cluster_manager>
       SetHandler mod_cluster-manager
       Order deny,allow
       Deny from all
       Allow from 192.168.1
    </Location>

  </VirtualHost>
</IfModule>
Apache web sunucusunu bin dizini altındaki httpd uygulamasını çalıştırarak başlatabilirsiniz. Artık kümeleme grubuna yaptığınız dağıtımlara 80 portu üzerinden erişebilirsiniz. Kümeleme çözümünüzün topolojisi değiştiğinde ya da kümeye yeni uygulamalar dağıttığınızda Apache Web sunucusunda herhangi bir ayar değişikliği yapmanız ya da sunucuyu yeniden başlatmanız gerekmez. Kümeleme çözümünüzdeki yük dengeleme ile ilgili durumu ise 6666 portunda yayında olan mod_cluster-manager sayfasından izleyebilirsiniz:
Kümeleme çözümünü test etmek için NumberGuessingGameWebApp_ha.war uygulamasını kümeye yönetim aracını kullanarak yayınladım. Bu durumu hem yönetim panelinden hem de yük dengeleyicinin izleme sayfasından doğrulayabiliriz:


Şimdi, uygulamaya yük dengeleyici üzerinden erişelim:
Bu bir sayı tahmini oyunu. Bilgisayar 1-100 arasında, o oturum için bir rastgele sayı belirliyor ve biz de bu sayıyı bulmaya çalışıyoruz. 7 hakkımız bulunuyor. Tahminimizi iyileştirmek için bilgisayarın "Daha büyük bir sayı seç" ya da "Daha küçük bir sayı seç" yönlendirmelerinden yararlanıyoruz. Şimdi oyunu oynarken, sırayla sunucuları sunucuları teker teker kapatacağız. Oyunu kesintisiz oynayabildiğimize dikkat ediniz:





JBoss ve Wildfly kurulumu, yapılandırılması, izlenmesi, kümeleme mimarileri ile ilgili daha detaylı bilgi almak isteyenler için Omega Eğitimin kataloğunda yer alan "JBoss AS 7: Administration" eğitimini tavsiye ederim. Danışmanlık hizmeti almak için ise bu bağlantıdaki iletişim bilgilerini kullanabilirsiniz.

Thursday, April 30, 2015

Java Sanal Makinası ve HotSpot

Java platformunun en güçlü bileşeni yazdığımız Java uygulamalarını çalıştıran Java Sanal Makinasıdır. Hatta son dönemde ortaya çıkan programlama dillerinin çoğunun Java Sanal Makinası (JSM) üzerinde çalışması rastlantısal olamaz! JSM etrafında kümelenmiş bu dilleri ortak olarak "JSM dilleri" olarak adlandırıyoruz. JSM kapalı bir kutu gibi görünse de bu kutuyu açıp içini kurcalamak, davranışını izlemek, başarımını iyileştirmek mümkündür. JSM gerçek bir işlemci tanımlar. Bu işlemcinin komut kümesi, adresleme kipi, saklayıcıları, aritmetik ve lojik işlem birimi ve bellek modeli bulunur (Şekil-1).  Bu işlemcinin standart tanımına bu adresten ulaşabilirsiniz. JSM fiziksel olarak üretilebilecek bir işlemci tanımlar. Ancak biz uzun süredir JSM'yi yazılımsal olarak ediniyoruz. 
Şekil-1 JSM'nin iç yapısı
Farklı işletim sistemlerinde farklı JSM'lerle karşılaşabilirsiniz. Oracle'ın HotSpot'u en çok kullanılan JSM'dir ve hemen hemen her işletim sitemi için HotSpot bulabilirsiniz. Oracle'ın sahip olduğu ama artık geliştirmesini durdurduğu bir JSM daha var: JRockit. Oracle'ın Sun firmasını satın almasından sonra HotSpot ile ilerlemeye karar verdi ve JRockit'in geliştirmesini durdurdu. Onun iyi özelliklerini HotSpot'a aktardığını ve HotSpot'u ticarileştirdiğini görüyoruz. JDK 7u40 sürümü ile birlikte gelen jmc (Mision Control) ve Flight Recorder yeteneğini JRockit'dan almıştır. jmc'nin kişisel kullanımı ücretsizdir, ancak ticari kullanımı için "Oracle ile gelirinizi paylaşmanız" gerekir. Azul Systems'ın biri OpenJDK tabanlı olan Zulu adında destek alabileceğiniz bir JSM'si ve diğeri Zing isimli, büyük Heap alanlarıyla, donma olmadan çalışmayı vaat eden, C4 (Continuously Concurrent Compacting Collector) adında bir çöp toplayıcısı barındıran bir JSM'si daha bulunuyor. IBM'in kendi AIX ve Linux tabanlı sistemleri için geliştirdiği J9 adında bir JSM'si bulunuyor.
Java uygulamalarını çalıştırdığınız ortamlarda, farklı mimariler ile karşılaşabilirsiniz. Java SE platformunda uygulama çalıştıracak iseniz tipik yapı Şekil-2'de verilmiştir.
 
Şekil-2 Java SE Uygulamalarının çalıştığı tipik mimari
Burada en altta tüm işi asıl yapan, fiziksel olarak dokunabileceğimiz donanım yer alır. Onun üzerinde donanım kaynaklarını yönetmekle sorumlu olan işletim sistemi çekirdeği yer alır. JSM ise işletim sistemi üzerinde oturur. Java uygulamalarının platform bağımsız olmasını sağlayan JSM'dir. JSM geliştirdiğimiz uygulamanın byte kodlarını alıp, işlemcinin ve  işletim sisteminin anlayacağı makine komutlarına ve sistem çağrılarına dönüştürür. Kurumsal uygulama geliştirmek için ise Java EE platformunu kullanıyoruz. Java EE platformunda uygulama geliştirmek için ise Java EE uyumlu bir uygulama sunucusuna ihtiyaç bulunmaktadır. Uygulama sunucusunun kendisi de bir Java uygulamasıdır ve bu nedenle JSM üzerinde çalışır. Bu durumda Java EE uygulamaları Şekil-3'deki gibi bir mimari üzerinde koşarlar. Java EE uygulama sunucularının bir kısmı açık kaynak kodlu (TomEE, GF, JBoss AS, Wildfly), bir kısmı ücretli (JBoss EAP, Weblogic, WebSphere) ve bir kısmı da kapalı kodludur (Weblogic, WebSphere). 
Şekil-3 Java EE Uygulamalarının çalıştığı tipik mimari
Son dönemde güçlü donanımlar ile karşılaşıyoruz. Bu güçlü donanımlar üzerinde, sistem kaynaklarının, uygulamalar arasında daha iyi paylaştırılabilmesi için çeşitli çözümler geliştirildiğini görüyoruz:
Zone ve Control Groups çözümleri Kap (=Container) teknolojisini kullanırlar. Ev sahibi işletim sisteminden, biri birinden yalıtılmış klonlar yaratılır. Bu yaratılan klonlara ihtiyaca göre kaynak atanarak, kaynak kullanımı planlanır. Sanallaştırma çözümünde ise donanım üzerinde ince bir sanallaştırma katmanı oturur. Bu katman üzerinde sanal makinalar tanımlanır. Bu sanal makinalar üzerine ihtiyaca göre farklı işletim sistemleri kurulur. JSM bu işletim sistemleri üzerinde çalışır (Şekil-4). 
Şekil-4 Sanallaştırma çözümü ve JSM
JSM'nin İşletim Sistemine ihtiyaç duymayan, doğrudan Sanal Makina üzerinde oturan türleri de mevcuttur (Şekil-5): JRockit VE (Virtual Edition) ve WebSphere HE (Hypervisor Edition).
Şekil-5 Doğrudan sanal makina üzerinde çalışan JSM
HotSpot
Bu bölümde HotSpot marka Java Sanal Makinasını inceleyeceğiz. HotSpot ona sorulduğunda kendisini tanıtır:
c:\opt32\java\jdk1.7.0_71\bin>java -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) Client VM (build 24.71-b01, mixed mode, sharing)
Burada JSM'nin HotSpot marka olduğunu, dağıtım sürümünün 24.71-b01, JDK sürümünün ise 1.7u71 olduğunu anlıyoruz. Ancak burada açıklamam gereken Client VM, mixed mode ve sharing tanımlamaları var. JSM hem 32-bit hem de 64-bit olabilir. Eğer bize açıkça 64-bit olduğunu söylemiyor ise 32-bittir. 64-bitlik bir HotSpot bize kendini aşağıdaki gibi tanıtacaktır:
c:\opt64\java\jdk1.7.0_71\bin>java -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)
Evet, HotSpot kendini 64-bit olarak tanıttı. Bir değişiklik daha dikkatimizi çekiyor: Client VM yazan yerde şimdi Server VM yazıyor! Henüz ne olduklarını bilmiyoruz ama en azından varsayılan olarak, 32-bitlik HotSpot, Client VM özelliğinde ve 64-bitlik HotSpot ise Server VM özelliğinde olduğunu biliyoruz. Önce "mixed mode" özelliğini açıklayalım. HotSpot, uygulamaları başlangıçta yorumlamalı olarak çalıştırır. Basit bir şekilde açıklamak gerekirse, HotSpot çalıştırılacak metodun byte kodlarının x86 karşılıklarını, byte kod-x86 çizelgesinden öğrenir ve x86 komutlarını işlemciye çalıştırması için gönderir. Bu çalışma şekli yavaştır. "mixed mode" çalışma şeklinde uygulama başlangıçta bu yüzden yavaş çalışır. Bir süre sonra HotSpot uygulamanın sıkça çalışan ve ısınan metotlarını JIT (=Just-in-time)  derleyicisine gönderir. JIT'lenen metot bundan sonra doğal işlemci komutları olarak çalışacağından, daha hızlı çalışır. Bir süre sonra bakıldığında, çalışan metotların bir kısmı yorumlamalı bir kısmı ise işlemcinin doğal komutlarında çalışır. Java uygulamamız başlangıçta yavaş çalışırken, yavaş yavaş hızlanmaya başlayacaktır. JIT derleyici sadece ana işlemci komutlarına dönüştürme yapmaz, aynı zamanda dinamik en iyileme yöntemlerini uygular. Hızlanmanın asıl kaynağı da buradan gelir. C/C++ ve Java'da yazılmış çözümlerin karşılaştırılmasında, Java'nın bazen daha üstün başarım sergilemesinin nedeni, JIT derleyicisinin uyguladığı bu iyileştirmelerdir. Şekil-6'da JIT derleyicinin basit bir şeması verilmiştir. JIT derleyici içinde basit bir kesit çıkarıcı (=Profiler) vardır ve yazılımın şeklini belirlemeye çalışır. En iyileme teknikleri, yazılımın çalışma zamanında aldığı şekle göre uygulanır. Her en iyileme tekniği her durumda geçerli değildir. JIT derleyici önce JIT'lenecek metodun ya da döngü bloğunun byte kodlarını ara bir gösterime dönüştürür. En iyileyici, yazılımın kesit bilgisinden yararlanarak, yazılımın şekline uygun en iyileme tekniklerini uygular. En iyileme, her durumda ara gösterime uygulanır. Kod üreteci bu ara gösterimden x86 kodu üretir. Kesit çıkarıcı koşturulan kodun davranışından, kesit bilgisini günceller.
Şekil-6 JIT Derleyici
HotSpot içinde iki farklı karakteristikte JIT derleyici bulunur: C1 ve C2. Client VM, C1 derleyicisini ve Server VM ise C2 derleyicisini kullanır. Java uygulamalarının başarımını ölçmek için farklı metrikler kullanarak ölçümler yapabiliriz. Açılış zamanı ve cevap süresi başarımı ölçmek için kullanılabilecek iki ölçüttür. Masaüstü uygulamaları için açılış süresi ve web uygulamaları için ise cevap süresi daha önemlidir. Masaüstü uygulamaları kullanıcı arayüzünü bir an önce kullanıcıya sunmalıdır. Örneğin, e-posta göndermek istiyorsunuz, bunun için favori e-posta istemcinizin  (örneğin, Thunderbird) masaüstü simgesine tıkladınız. Pencerenin beş dakika sonra açılması sizi hiç memnun etmez. Pencerenin hemen açılmasını ve iletinizi bir an önce yazabilmeyi istersiniz. Nasıl olsa yazmaya başladığınızda, işlemci ile karşılaştırıldığında kaplumbağa hızında yazıyor olacaksınız. Yazılımın çok da hızlı çalışmaya ihtiyacı yok. Buna karşılık web uygulamalarında ise uygulama sunucusunun biraz geç açılmasına tahammül edebilirsiniz ama bir istek geldiğinde ona en hızlı sürede yanıt vermek ve cevabı dönebilmek istersiniz. İşte C1 derleyicisi açılış süresini iyileştirmek ve C2 derleyicisi ise hızlı yanıt süresini iyileştirmek üzere en iyilenmiştir. 32-bitlik HotSpot hem Client VM hem de Server VM olarak çalışabilirken, 64-bitlik HotSpot sadece Server VM olarak çalışır. -client ve -server seçenekleri ile tercihimizi HotSpot'a bildirebiliyoruz:

c:\opt64\java\jdk1.7.0_71\bin>java -client -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

c:\opt64\java\jdk1.7.0_71\bin>java -server -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

c:\opt32\java\jdk1.7.0_71\bin>java -client -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) Client VM (build 24.71-b01, mixed mode, sharing)

c:\opt32\java\jdk1.7.0_71\bin>java -server -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) Server VM (build 24.71-b01, mixed mode)

C1 en iyileme için acele eder. Amacı açılış süresini iyileştirmek olduğu için çok fazla en iyileme yapmaz. C2 ise JIT'lemek için acele etmez, önce uygulamanın şeklini alması bekler ve daha çok en iyileme tekniklerini uygular. Bu nedenle C1'in JIT'leme zaman maliyeti düşüktür ama buna paralel olarak, üretilen kodun kalitesi de düşüktür. C2'nin JIT'leme zaman maliyeti yüksektir ancak üretilen kodun kalitesi yüksektir. C2'nin ürettiği kod C1'in ürettiği koddan yaklaşık iki kat daha hızlı çalışır.
Java 7'de her iki JIT derleyicinin iyi özelliklerini birleştiren yeni bir JIT derleyicisi var: Katmanlı JIT derleyici (=Tiered Compiler). Hem açılış zamanını hem de cevap süresini iyileştirmeye çalışıyor. Şekil-7'de katmanlı JIT derleyicinin basit akış şemasını bulabilirsiniz.
Şekil-7 Katmanlı JIT Derleyici
Ancak Java 7'de bu özellik kapalıdır. Açmak için JSM'yi -XX:+TieredCompilation seçeneği ile başlatmanız gerekir. Java 8'de ise varsayılan davranış budur, bu nedenle herhangi bir tanımlama yapmanıza gerek yoktur. 
JIT derleyicinin davranışını izleyebilirsiniz. Hatta üretilen x86 kodunu da izlemek mümkündür. Bunun için HotSpot'u aşağıdaki gibi başlatmalısınız:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintAssembly
Ayrıca Windows platformu için hsdis-amd64.dll dosyasını java.exe ile aynı dizine koymanız gerekir. Bu dll dosya, x86 komutlarının sembolik dilde göstermesini sağlar. Ekran çıktısına ilişkin bir örneği aşağıda bulabilirsiniz:
Java HotSpot(TM) 64-Bit Server VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output
    142    1             java.lang.String::hashCode (55 bytes)
Loaded disassembler from hsdis-amd64.dll
Decoding compiled method 0x00000000024ebd10:
Code:
[Disassembling for mach='i386:x86-64']
[Entry Point]
[Constants]
  # {method} 'hashCode' '()I' in 'java/lang/String'
  #           [sp+0x30]  (sp of caller)
  0x00000000024ebe40: mov    0x8(%rdx),%r10d
  0x00000000024ebe44: cmp    %r10,%rax
  0x00000000024ebe47: jne    0x00000000024b7a60  ;   {runtime_call}
  0x00000000024ebe4d: data32 xchg %ax,%ax
[Verified Entry Point]
  0x00000000024ebe50: mov    %eax,-0x6000(%rsp)
  0x00000000024ebe57: push   %rbp
  0x00000000024ebe58: sub    $0x20,%rsp         ;*synchronization entry
                                                ; - java.lang.String::hashCode@-1 (line 1446)
  0x00000000024ebe5c: mov    %rdx,%r13
  0x00000000024ebe5f: mov    0x10(%rdx),%eax    ;*getfield hash
                                                ; - java.lang.String::hashCode@1 (line 1446)
  0x00000000024ebe62: test   %eax,%eax
  0x00000000024ebe64: jne    0x00000000024ebf44  ;*ifne
                                                ; - java.lang.String::hashCode@6 (line 1447)
  0x00000000024ebe6a: mov    0xc(%rdx),%esi     ;*getfield value
                                                ; - java.lang.String::hashCode@10 (line 1447)
  0x00000000024ebe6d: mov    0xc(%rsi),%r10d    ;*arraylength
                                                ; - java.lang.String::hashCode@13 (line 1447)
                                                ; implicit exception: dispatches to 0x00000000024ebf65
  0x00000000024ebe71: xor    %edi,%edi
  0x00000000024ebe73: test   %r10d,%r10d
  0x00000000024ebe76: jle    0x00000000024ebf50  ;*ifle
                                                ; - java.lang.String::hashCode@14 (line 1447)
  0x00000000024ebe7c: test   %r10d,%r10d
  0x00000000024ebe7f: jbe    0x00000000024ebf54
  0x00000000024ebe85: mov    %r10d,%r8d
  0x00000000024ebe88: dec    %r8d
  0x00000000024ebe8b: cmp    %r10d,%r8d
  0x00000000024ebe8e: jae    0x00000000024ebf54
  0x00000000024ebe94: xor    %ebp,%ebp          ;*imul
                                                ; - java.lang.String::hashCode@36 (line 1451)
  0x00000000024ebe96: movzwl 0x10(%rsi,%rdi,2),%r9d
  0x00000000024ebe9c: add    %r9d,%ebp          ;*iadd
                                                ; - java.lang.String::hashCode@40 (line 1451)
  0x00000000024ebe9f: mov    %ebp,%ecx
  0x00000000024ebea1: shl    $0x5,%ecx
  0x00000000024ebea4: mov    %ecx,%eax
  0x00000000024ebea6: sub    %ebp,%eax          ;*imul
                                                ; - java.lang.String::hashCode@36 (line 1451)
  0x00000000024ebea8: inc    %edi               ;*iinc
                                                ; - java.lang.String::hashCode@42 (line 1450)
  0x00000000024ebeaa: cmp    $0x1,%edi
  0x00000000024ebead: jge    0x00000000024ebeb3  ;*if_icmpge
                                                ; - java.lang.String::hashCode@30 (line 1450)
JIT'lenen metod ve döngü blokları ile ilgili ekrana dökülen satırlara bir bakalım:
154    1             java.lang.String::hashCode (55 bytes)
    203    2             java.lang.String::indexOf (70 bytes)
    226    3             sun.java2d.loops.GraphicsPrimitive::getUniqueID (5 bytes)
    249    4             java.lang.Object::<init> (1 bytes)
    257    5             java.lang.String::charAt (29 bytes)
    341    6             java.lang.String::equals (81 bytes)
    343    7             java.util.Arrays::binarySearch0 (95 bytes)
    383    8 %           sun.awt.image.PNGImageDecoder::update_crc @ 3 (41 bytes)
    383    9 % !         sun.awt.image.PNGImageDecoder::produceImage @ 960 (1920 bytes)
    391   10             sun.awt.image.PNGImageDecoder::update_crc (41 bytes)
    419    9 % !         sun.awt.image.PNGImageDecoder::produceImage @ -2 (1920 bytes)   made not entrant
    420   11 % !         sun.awt.image.PNGImageDecoder::produceImage @ 960 (1920 bytes)
    420   12     n       java.lang.System::arraycopy (native)   (static)
    421   13             sun.awt.image.PNGImageDecoder::filterRow (459 bytes)
    461   14             java.util.Properties$LineReader::readLine (452 bytes)
    568   15             sun.security.provider.SHA::implCompress (491 bytes)
    575   16             java.lang.String::lastIndexOf (52 bytes)
    581   17             sun.nio.cs.SingleByte$Encoder::encode (114 bytes)
    586   18             sun.nio.cs.SingleByte$Encoder::encode (32 bytes)
    596   19             java.lang.Math::min (11 bytes)
    604   20             java.nio.HeapByteBuffer::_get (7 bytes)
    610   21             java.io.BufferedInputStream::getBufIfOpen (21 bytes)
    610   22  s          java.io.BufferedInputStream::read (49 bytes)
    611   23             java.io.FilterInputStream::read (8 bytes)
    613   24             java.io.DataInputStream::readChar (40 bytes)
    614   25 %           sun.text.normalizer.CharTrie::unserialize @ 29 (74 bytes)
    622   26             sun.text.normalizer.CharTrie::unserialize (74 bytes)
    637   27             java.nio.Buffer::nextGetIndex (31 bytes)
    651   28             java.lang.String::length (6 bytes)
    656   29             java.awt.geom.Path2D$Float::append (216 bytes)
    656   30             java.awt.geom.Path2D$Iterator::isDone (20 bytes)
    657   31             java.awt.geom.Path2D$Float::needRoom (123 bytes)
    661   32             java.awt.geom.Path2D$Float$CopyIterator::currentSegment (39 bytes)
    663   33             java.awt.geom.Path2D$Iterator::next (35 bytes)
    718   34             java.util.HashMap::indexFor (6 bytes)
    724   35             java.nio.Bits::getCharB (16 bytes)
    724   36             java.nio.Bits::makeChar (12 bytes)
    725   37             java.nio.ByteBufferAsCharBufferB::get (16 bytes)
    725   38             java.nio.ByteBufferAsCharBufferB::ix (9 bytes)
    738   39             java.lang.String::indexOf (166 bytes)
    738   40             java.lang.String::replace (127 bytes)
    755   41             java.util.HashMap::hash (55 bytes)
    769   42             java.lang.String::startsWith (72 bytes)
    772   43             java.util.HashMap::getEntry (86 bytes)
    783   44             java.util.concurrent.atomic.AtomicInteger::get (5 bytes)
Burada birinci sütun JIT'leme zamanını, ikinci sütun ise JIT'leme numarasını ifade eder. Üçüncü sütunda çeşitli semboller yer alır:

  • %: Döngü bloğu JIT'lendi. Metod içinde birden fazla döngü varsa hangi döngü olduğunu @ sembolünden sonra yazan rakamı kullanarak belirleyebilirsiniz. Bu rakam döngünün başlangıç byte kod sırasını verir. 
  • s: synchronized metod JIT'lendi
  • !: Exception bloğu JIT'lendi 
  • n: native metod

Dördüncü sütunda ise JIT'lenen metodun paket ile birlikte adı yer alır. Ne yazık ki işlev yüklenen metodları ayırt etmek her zaman kolay olmayabilir. Parantez içinde metodun gövdesinin kaç byte koddan oluştuğu bilgisi bulunur. İşlev yüklenen metodları ayırt etmek için bu değerden yararlanabilirsiniz.
HotSpot'un varsayılan çalışma kipi "mixed"'dir. İki farklı kipi daha bulunur:

  • Compiled: Tüm metodlar JIT'lenerek çalıştırılır. Bu kipte çalışmak için HotSpot'u -Xcomp seçeneği ile çalıştırmalısınız:

c:\opt64\java\jdk1.7.0_71\bin>java -Xcomp -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, compiled mode)
Uygulama sunucularını üretim ortamında bu kipte çalışan HotSpot üzerinde çalıştırmanız uygun olur. 

  • Interpreted: JIT derleyiciler devre dışıdır. Tüm kod yorumlamalı olarak çalıştırılır. Zamanda yolculuk yapmak için bu kipi kullanabilirsiniz: Java ilk çıktığında çok yavaştı, çünkü sadece bu kipte çalışıyordu. Bu yavaşlığı deneyimlemek ve 1996'ya gitmek için -Xinterp seçeneği ile çalıştırmanız yeterli olacaktır:

c:\opt64\java\jdk1.7.0_71\bin>java -Xinterp -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, interpreted mode)

JSM Ergonomisi
Java uygulamalarını çalıştırmak çok kolaydır. jar olarak dağıtılan bir uygulamayı komut satırından çalıştırmak için "java -jar" yazmak yeterlidir. Ancak JSM'nin komut satırından verebileceğimiz çok sayıda seçeneği bulunur. HotSpot için bu seçeneklerin listesini almak üzere, java'yı aşağıdaki seçeneklerle birlikte yazıp, çalıştırın:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version
Bu komut ekranda yüzlerce satırdan oluşan bir çıktı yaratır:
[Global flags]
    uintx AdaptivePermSizeWeight                    = 20              {product}
    uintx AdaptiveSizeDecrementScaleFactor          = 4               {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10              {product}
    uintx AdaptiveSizePausePolicy                   = 0               {product}
    uintx AdaptiveSizePolicyCollectionCostMargin    = 50              {product}
    uintx AdaptiveSizePolicyInitializingSteps       = 20              {product}
    uintx AdaptiveSizePolicyOutputInterval          = 0               {product}
    uintx AdaptiveSizePolicyWeight                  = 10              {product}
    uintx AdaptiveSizeThroughPutPolicy              = 0               {product}
    uintx AdaptiveTimeWeight                        = 25              {product}
     bool AdjustConcurrency                         = false           {product}
     bool AggressiveOpts                            = false           {product}
     intx AliasLevel                                = 3               {C2 produc
     bool AlignVector                               = false           {C2 produc
     intx AllocateInstancePrefetchLines             = 1               {product}
     intx AllocatePrefetchDistance                  = 192             {product}
     intx AllocatePrefetchInstr                     = 0               {product}
     intx AllocatePrefetchLines                     = 4               {product}
     intx AllocatePrefetchStepSize                  = 64              {product}
     intx AllocatePrefetchStyle                     = 1               {product}
     bool AllowJNIEnvProxy                          = false           {product}
     bool AllowNonVirtualCalls                      = false           {product}
     bool AllowParallelDefineClass                  = false           {product}
     bool AllowUserSignalHandlers                   = false           {product}
     bool AlwaysActAsServerClassMachine             = false           {product}
     bool AlwaysCompileLoopMethods                  = false           {product}
     bool AlwaysLockClassLoader                     = false           {product}
     bool AlwaysPreTouch                            = false           {product}
     bool AlwaysRestoreFPU                          = false           {product}
     . . . . . . . . . . . .
64-bitlik Server VM HotSpot için tam olarak 758 seçenek vardır. 32-bitlik Client VM HotSpot için 685 seçenek ve 32-bitlik Server VM HotSpot için ise 756 seçenek bulunuyor. Bu JDK 7u71 için böyle. JDK 8u40 için ise seçenek sayılarında farklılıklar var:
64-bitlik Server VM HotSpot 790 seçenek, 32-bitlik Client VM HotSpot için 709 seçenek ve 32-bitlik Server VM HotSpot için ise 787 seçenek bulunuyor. Bu çıktıda birinci satırda seçeneğin tipi var. bool true/false değer alabilen seçeneği ifade eder. intx tamsayı, uintx pozitif tamsayıyı ve double ise kayan nokta sayıları ifade eder. İkinci sütunda değişkenin adı ve üçüncü sütunda ise varsayılan değeri bulunur. Eğer değişkenin değeri := sembolü ile verilmiş ise bu seçeneğin değeri kullanıcı tarafından ezilmiş demektir:
     intx CICompilerCount                          := 3                                   {product}
Seçeneklerin değerini değiştirmek için komut satırında seçeneğin önüne "-XX:" koyup yeni değerini "=" sembolünden sonra tanımlıyoruz:
-XX:CompileThreshold=2000
Tek bir özel durum var. bool tipindeki seçenekler için true ve false yerine + ve - sembollerini seçenek adından hemen önce kullanıyoruz:
-XX:+AggressiveOpts
ya da 
-XX:+AggressiveOpts
Dördüncü sütunda ise seçeneğin sınıfı yer alır. 
HotSpot seçeneklerini oluşturan kümeye JSM ergonomisi diyoruz. JSM, ergonomisini üzerinde çalıştığı platform kaynaklarının (bellek ve işlemci gibi) kapasitesine göre belirler. Bazı seçeneklerinin değerlerini kaynakların durumuna göre otomatik olarak uyarlayarak saptar. Diğer seçeneklerin ise varsayılan sabit başlangıç değerleri vardır. JSM'nin otomatik olarak belirlediği bu seçenekler, JSM'yi akort etmek için kullanılabilir. JSM'nin nasıl akort edileceği ve HotSpot ile ilgili detay bilgi edinmek isteyenler için Java Performance Tuning and Optimization eğitimini tavsiye ederim.
Aslında HotSpot'un bu listenenenden daha da fazla seçeneği bulunur. Tüm seçeneklerin listesini almak için HotSpot'u aşağıdaki seçeneklerle çalıştırmalısınız:
java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+AggressiveOpts -XX:+PrintFlagsFinal -version
JDK 8u40 için tüm seçenek sayıları:
64-bitlik Server VM HotSpot 834 seçenek, 32-bitlik Client VM HotSpot için 751 seçenek ve 32-bitlik Server VM HotSpot için ise 831 seçenek bulunuyor.