Living life and Make it Better

life, learn, contribute

Endy Muhardin

Software Developer berdomisili di Jabodetabek, berkutat di lingkungan open source, terutama Java dan Linux.

Pemakaian Git sehari-hari

Pada artikel ini, kita akan mengulas secara singkat perintah-perintah yang sering kita gunakan dalam Git. Tapi sebelum mulai, perlu kita pahami beberapa istilah sebagai berikut:

  • diff : perbedaan antara satu file dengan file lain biasanya diff dilakukan terhadap satu file yang sudah berubah isinya

  • changeset : kumpulan diff

  • working folder : folder kerja kita, berisi file yang (mungkin) sudah berubah sejak commit terakhir

  • staging : tempat persiapan changeset yang akan dicommit

  • commit : snapshot dari posisi folder dan file pada waktu tertentu

  • tip : commit paling ujung

  • head : nama lain tip

  • branch : head yang diberi nama

  • HEAD : head yang sedang aktif

  • merge : menggabungkan lebih dari satu commit

Membuat Repository

Untuk bisa mulai bekerja, kita harus memiliki repository dulu. Ada dua kemungkinan, kita membuat repository baru, atau kita membuat clone dari repository yang sudah ada.

Keterangan Perintah
membuat repository baru git init
membuat repository baru di folder project-baru git init project-baru
membuat repository untuk dishare git init –bare project-baru
copy repository lain git clone repo-url

pilihan format URL

file:///path/ke/repo : clone dari folder lokal

/path/ke/repo : clone dari folder lokal, menggunakan hard link

http://server/path/ke/repo : clone melalui protokol http

username@server:path/ke/repo : clone melalui protokol ssh

Bekerja dengan Git

Berikut ini adalah perintah yang dilakukan selama sesi coding.

Keterangan | Perintah ————————————————————————————————————————|—————————————– Menambah file baru | git add namafile Menghapus file | git rm namafile Memasukkan perubahan di satu file ke staging area | git add namafile memasukkan semua perubahan | git add . memilih potongan kode yang akan dimasukkan | git add -p memasukkan perubahan ke staging menggunakan menu | git add -i melihat status perubahan file, mana yang masih di working dan mana yang sudah di staging | git status mengeluarkan perubahan dari staging area | git reset – namafile melihat perubahan yang belum dimasukkan ke staging area | git diff melihat perubahan yang akan dicommit (sudah ada di staging area) | git diff –staged melihat perubahan antara working folder dan commit terakhir | git diff HEAD melihat file mana saja yang berubah | git diff –name-status abc123..def456 melakukan commit, editor akan diaktifkan untuk mengisi keterangan | git commit melakukan commit, langsung mengisi keterangan | git commit -m “langsung isi keterangan di sini” commit langsung semua perubahan, tanpa melalui staging | git commit -a melihat commit history | git log log lima commit terakhir | git log -5 log hanya menampilkan summary | git log –oneline tampilkan commit summary dari semua branch dengan graph hubungan antar commit | git log –oneline –all –graph membuat commit baru yang berkebalikan dengan (undo) commit terakhir | git revert HEAD undo 2 commit terakhir | git revert HEAD~2 memindahkan HEAD ke commit-id yang diminta, staging disamakan dengan HEAD, working tetap seperti semula.
Ini adalah opsi defaultnya reset | git reset –mixed memindahkan HEAD ke commit-id yang diminta, isi working dan staging disamakan dengan commit-id tersebut | git reset –hard commit-id memindahkan HEAD ke commit-id yang diminta, staging dan working tidak disentuh. Tidak mengubah output git status | git reset –soft membuat working dan staging sama dengan HEAD | git reset –hard

Bekerja paralel menggunakan branch

Branch memungkinkan kita bekerja secara paralel, misalnya ada tim yang menambah fitur, dan ada tim yang melakukan bug fix.

Keterangan Perintah
membuat branch baru git branch namabranch
pindah ke branch tersebut git checkout namabranch
bikin branch sambil pindah git checkout -b namabranch
membuat tracking branch untuk branch bugfix di origin git checkout –track origin/bugfix
membuat tracking branch dengan nama berbeda dengan remote git checkout -b myfix origin/bugfix
membandingkan branch satu dengan lainnya git diff master..fitur-xx
membandingkan branch dengan titik awal branch tersebut git diff master…fitur-xx
menggabungkan branch satu dengan lainnya git checkout branch-tujuan
  git merge branch-yang-mau-diambil
Mengedit konflik :  
- edit konfliknya git add namafile-yang-konflik
- remove markernya git commit -m “merge fitur-xxx ke master”
membatalkan merge yang konflik git reset –hard

Bekerja dengan remote

Interaksi dengan remote repository

Keterangan Perintah
mendaftarkan remote repository git remote add namaremote url
melihat daftar remote repository git remote -v
menghapus remote repository git remote rm namaremote
mengambil perubahan di remote git remote update
mengambil perubahan di satu remote saja git remote update namaremote
mengambil perubahan di remote, hapus branch di lokal yang sudah tidak ada di remote git remote update –prune
mengambil perubahan sesuai refspec yang sudah dikonfigurasi git fetch namaremote
mengambil perubahan kemudian dimerge ke branch lokal yang sesuai pull = fetch + merge
  git pull namaremote
mengirim perubahan di lokal ke remote git push nama-remote nama-branch-lokal:nama-branch-remote
mengirim perubahan di lokal ke remote, semua branch yang namanya bersesuaian akan dikirim git push nama-remote
mengirim perubahan di branch lokal yang sedang aktif ke branch di remote dengan nama yang sama git push nama-remote HEAD
menghapus branch di remote git push nama-remote :nama-branch-remote

Demikianlah perintah-perintah Git yang kita gunakan sehari-hari. Melengkapi daftar perintah di atas, diagram berikut dapat membantu pemahaman kita tentang konsep dan operasi di Git.


Project Setup dengan Gradle

Project Setup dengan menggunakan Gradle dan Git

Hal pertama yang kita lakukan sebelum mulai bekerja tentunya adalah menyiapkan meja kerja dan peralatannya. Sama juga dengan mulai membuat aplikasi. Kita harus menyiapkan struktur folder, library dan framework, dan mengatur semuanya agar siap dikerjakan di meja kita, dalam hal ini IDE.

Di ArtiVisi, biasanya ini dikerjakan oleh programmer senior, yaitu Martinus atau saya sendiri. Kegiatan project setup ini tidak terlalu tinggi frekuensinya, karena biasanya coding project yang existing jauh lebih sering daripada memulai project baru.

Yang jarang dikerjakan biasanya cepat dilupakan. Inilah alasan utama saya menulis posting kali ini, sebagai pengingat buat diri sendiri. Selain itu, mudah-mudahan ada manfaatnya juga untuk para pembaca sekalian.

Sebagai gambaran, tipikal aplikasi di ArtiVisi menggunakan stack standar 2011. Jadi, project setup ini akan dibuat mengikuti stack standar tersebut.

Pertama kali, kita buat dulu projectnya. Satu aplikasi biasanya kita pecah menjadi beberapa komponen, yaitu :

  • Domain Model dan Service API : ini kita pisahkan untuk memudahkan distribusi ke aplikasi client. Perhatikan bahwa yang saya maksud client di sini bukanlah customer pembeli aplikasi, melainkan aplikasi di sisi hilir misalnya user interface yang dibuat dengan Swing. Di sisi client, tidak perlu ada detail implementasi. Cukup class-class domain seperti Produk, Kategori, dsb. Juga kita sediakan service interface, yaitu method yang bisa digunakan untuk menjalankan proses bisnis.

  • Implementasi Service : ini adalah implementasi dari service interface di atas. Implementasi biasanya hanya ada di sisi server. Jadi, jar yang dihasilkan project ini tidak kita distribusikan ke client

  • Konfigurasi : file konfigurasi seperti jdbc.properties, logback-test.xml, smtp.properties, dan setting-setting lain kita juga pisahkan ke project sendiri. Ini tujuannya untuk memudahkan deployment. Seperti kita tahu, biasanya ada beberapa environment seperti development di laptop programmer, testing server, dan production server. Dengan memisahkan konfigurasi, kita bisa menghindari mendeploy konfigurasi development ke server production. Yang perlu diperhatikan di sini, hibernate.cfg.xml dan applicationContext.xml bukanlah file konfigurasi. Itu adalah file aplikasi, walaupun bentuknya xml dan tidak perlu dikompilasi.

  • User Interface : kalau aplikasi desktop, ini hanya satu project saja. Atau mungkin dua dengan konfigurasinya. Tapi untuk web, biasanya kita pecah dua juga. Yang satu berisi source code java, satu lagi berisi aplikasi web. Dengan demikian, bila ada perubahan di controller, kita cukup deploy 1 jar, tidak perlu upload 1 war.

Sebagai ketentuan lain, biasanya nama package selalu kita awali dengan com.artivisi, dan struktur folder mengikuti standar Maven.

Mari kita mulai, berikut rangkaian perintah di linux untuk membuat struktur awal project.

mkdir -p project-contoh/com.artivisi.contoh.{config,domain,service.impl,ui.springmvc,ui.web}/src/{main,test}/{java,resources}
mkdir -p project-contoh/com.artivisi.contoh.ui.web/src/main/webapp/WEB-INF

Outputnya bisa kita lihat sebagai berikut

find . 
.
./com.artivisi.contoh.service.impl
./com.artivisi.contoh.service.impl/src
./com.artivisi.contoh.service.impl/src/test
./com.artivisi.contoh.service.impl/src/test/java
./com.artivisi.contoh.service.impl/src/test/resources
./com.artivisi.contoh.service.impl/src/main
./com.artivisi.contoh.service.impl/src/main/java
./com.artivisi.contoh.service.impl/src/main/resources
./com.artivisi.contoh.domain
./com.artivisi.contoh.domain/src
./com.artivisi.contoh.domain/src/test
./com.artivisi.contoh.domain/src/test/java
./com.artivisi.contoh.domain/src/test/resources
./com.artivisi.contoh.domain/src/main
./com.artivisi.contoh.domain/src/main/java
./com.artivisi.contoh.domain/src/main/resources
./com.artivisi.contoh.ui.springmvc
./com.artivisi.contoh.ui.springmvc/src
./com.artivisi.contoh.ui.springmvc/src/test
./com.artivisi.contoh.ui.springmvc/src/test/java
./com.artivisi.contoh.ui.springmvc/src/test/resources
./com.artivisi.contoh.ui.springmvc/src/main
./com.artivisi.contoh.ui.springmvc/src/main/java
./com.artivisi.contoh.ui.springmvc/src/main/resources
./com.artivisi.contoh.config
./com.artivisi.contoh.config/src
./com.artivisi.contoh.config/src/test
./com.artivisi.contoh.config/src/test/java
./com.artivisi.contoh.config/src/test/resources
./com.artivisi.contoh.config/src/main
./com.artivisi.contoh.config/src/main/java
./com.artivisi.contoh.config/src/main/resources
./com.artivisi.contoh.ui.web
./com.artivisi.contoh.ui.web/src
./com.artivisi.contoh.ui.web/src/test
./com.artivisi.contoh.ui.web/src/test/java
./com.artivisi.contoh.ui.web/src/test/resources
./com.artivisi.contoh.ui.web/src/main
./com.artivisi.contoh.ui.web/src/main/java
./com.artivisi.contoh.ui.web/src/main/webapp/WEB-INF
./com.artivisi.contoh.ui.web/src/main/resources

Berikutnya, kita lengkapi dengan dependensi jar. Di ArtiVisi, kita menggunakan Gradle. Gradle meminta kita untuk mendaftarkan project yang terlibat dalam settings.gradle

include "com.artivisi.contoh.config"
include "com.artivisi.contoh.domain"
include "com.artivisi.contoh.service.impl"
include "com.artivisi.contoh.ui.springmvc"
include "com.artivisi.contoh.ui.web"

Dan ini build file Gradle.


springVersion = "3.0.5.RELEASE"
springSecurityVersion = "3.0.5.RELEASE"
slf4jVersion = "1.6.1"
logbackVersion = "0.9.27"
jodaTimeVersion = "1.6.2"
sourceCompatibility = 1.6
 
subprojects {
    apply plugin: 'java'
    apply plugin: 'eclipse'
 
    configurations {
        all*.exclude group: "commons-logging", module: "commons-logging"
    }
 
    repositories {
        mavenCentral()
    }
 
    dependencies {
        compile "org.slf4j:jcl-over-slf4j:$slf4jVersion",
                "org.slf4j:jul-to-slf4j:$slf4jVersion"
                
        runtime "joda-time:joda-time:$jodaTimeVersion"        
                
        runtime "ch.qos.logback:logback-classic:$logbackVersion"
  
        testCompile 'junit:junit:4.7'
    }
 
    group = 'com.artivisi.contoh'
    version = '1.0-SNAPSHOT'
    sourceCompatibility = 1.6
    
    task wrapper(type: Wrapper) {
        gradleVersion = '0.9.1'
        jarFile = 'wrapper/wrapper.jar'
    }
}

project('com.artivisi.contoh.domain') {
    dependencies { 
        compile "org.hibernate:hibernate-entitymanager:3.4.0.GA"
     
        compile "org.springframework:spring-tx:$springVersion",
                "org.springframework:spring-orm:$springVersion",
                "org.springframework:spring-jdbc:$springVersion"
                
     
    }
}

project('com.artivisi.contoh.service.impl') {
    dependencies { 
        compile project(':com.artivisi.contoh.domain')
        compile "org.hibernate:hibernate-entitymanager:3.4.0.GA"
     
        compile "org.springframework:spring-tx:$springVersion",
                "org.springframework:spring-orm:$springVersion",
                "org.springframework:spring-jdbc:$springVersion"
                
     
    }
}

project('com.artivisi.contoh.ui.springmvc') {
    dependencies {
        compile project(':com.artivisi.contoh.service.impl')
     
        compile "org.springframework:spring-webmvc:$springVersion",
                "org.springframework:spring-aop:$springVersion"
     
        compile "org.springframework.security:spring-security-web:$springSecurityVersion",
                "org.springframework.security:spring-security-config:$springSecurityVersion"
     
        compile "javax.validation:validation-api:1.0.0.GA",
                "org.hibernate:hibernate-validator:4.0.2.GA"
     
    }
}

project('com.artivisi.contoh.ui.web') {
    apply plugin: 'war'
    apply plugin: 'jetty'
     
    dependencies {
        compile project(':com.artivisi.contoh.ui.springmvc')
        runtime project(':com.artivisi.contoh.config')
      
        runtime "javax.servlet:jstl:1.1.2",
                "taglibs:standard:1.1.2",
                "opensymphony:sitemesh:2.4.2"
     
        providedCompile "javax.servlet:servlet-api:2.5"
    }
}

Build file ini sudah mendeskripsikan semua sub-projectnya. Sebetulnya kita bisa membuat buildfile di masing-masing project, tapi saya lebih suka terpusat seperti ini supaya terlihat keterkaitan antar project.

Karena saya menggunakan Eclipse, saya menambahkan metadata supaya projectnya bisa dibuka di Eclipse. Ini bisa kita lakukan dengan cara menjalankan perintah

gradle eclipse

dalam masing-masing folder project. Tapi karena terlalu malas, saya gunakan satu baris perintah ini.

for d in */; do cd "$d"; gradle eclipse; cd ..; done

Untung saja pakai linux, jadi bisa coding di command prompt :D

Selanjutnya, kita bisa test dengan melakukan build di project paling hilir, yaitu ui.web

cd com.artivisi.contoh.ui.web
gradle war

Hasilnya ada di folder build/libs Kita cek apakah semua dependensi sudah terpenuhi dengan perintah berikut.

jar tvf build/libs/com.artivisi.contoh.ui.web-1.0-SNAPSHOT.war

Ini juga bisa langsung dijalankan dengan plugin Jetty yang ada dalam Gradle.

cd com.artivisi.contoh.ui.web
gradle jetty

Outputnya bisa kita lihat di browser, dengan port 8080.

Di situ ada link menuju aplikasi kita. Silahkan diklik.

Folder WEB-INF masih terlihat, karena kita belum membuat web.xml. Berikut isi web.xml, masukkan dalam folder com.artivisi.contoh.ui.web/src/main/webapp/WEB-INF


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- Reads request input using UTF-8 encoding -->
	<filter>
		<filter-name>characterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>characterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- Handles all requests into the application -->
	<servlet>
		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
				/WEB-INF/springmvc-context.xml
			</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

Sekalian saja kita konfigurasi Spring MVC. Pasang file springmvc-context.xml ini di sebelahnya web.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<!-- Scans the classpath of this application for @Components to deploy as beans -->
	<context:component-scan base-package="com.artivisi.contoh.ui.web" />

	<!-- Configures the @Controller programming model -->
	<mvc:annotation-driven />
	
	<!-- mengganti default servletnya Tomcat dan Jetty -->
	<!-- ini diperlukan kalau kita mapping DispatcherServlet ke / -->
	<!-- sehingga tetap bisa mengakses folder selain WEB-INF, misalnya img, css, js -->
	<mvc:default-servlet-handler/>

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
	<mvc:resources mapping="/resources/**" location="/resources/" />

	<!-- Application Message Bundle -->
	<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<property name="basename" value="/WEB-INF/messages/messages" />
		<property name="cacheSeconds" value="0" />
	</bean>

	<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/templates/jsp/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
	
	<!-- Forwards requests to the "/" resource to the "hello" view -->
	<mvc:view-controller path="/" view-name="hello"/>

</beans>

Kita cek juga apakah projectnya sudah bisa dibuka di Eclipse. Mari kita import.

Pertama, arahkan workspace ke folder project-contoh.

Setelah Eclipse terbuka, kita pilih menu Import Project, untuk membuka 4 project yang tadi sudah kita buat.

Pilih folder induknya.

Selesai, semua project kita bisa dibuka. Bahkan kita bisa menjalankan project ui.web dengan cara klik kanan Run in Server. Ini bisa dilihat dari icon project tersebut yang berbentuk bola dunia.

Selesai sudah, mari kita share dengan rekan yang lain.


Konsep Clustering

Di milis JUG, lagi-lagi ada yang tanya tentang load balancing, failover, dan clustering. Jawabannya masih sama sejak 10 tahun saya berkecimpung di urusan coding-mengcoding. Jadi, baiklah saya tulis di blog saja, supaya next time bisa jadi referensi.

Ini sebetulnya dua hal yang berbeda. Load balancing ya membagi beban. Failover ya mencegah single point of failure.

Load Balancing

Load balancer terdiri dari satu balancer dan banyak worker. Bebannya dibagi2 ke semua worker dengan algoritma yang biasanya bisa dipilih. Bisa merata (round robin) bisa juga dengan bobot (weighted), misalnya worker X mendapat 2 kali worker Y karena dia specnya lebih tinggi. Atau bisa juga dynamic, artinya si LB akan mengetes kondisi semua worker, mana yang kira2 sedang idle itu yang dikasi. Mana yang sedang idle ini nanti ada lagi settingnya, apakah melihat CPU usage pakai SNMP, melihat ping response time, whatever.

Failover minimal harus ada 2 titik. Kalo kita implement LB aja, point of failure (POF) nya adalah si LB. Begitu LB nya mati, ya udah semua worker gak bisa diakses. Untuk mencegah ini, LB nya harus ada 2, satu aktif satu standby (pasif).

Contoh aplikasi load balancer :

  • HAProxy
  • ldirectord (Ultra Monkey)
  • Pound

Contoh aplikasi lain yang bisa jadi load balancer :

  • Apache (mod_proxy_balancer)
  • Nginx
  • lighttpd
  • bind (DNS Server)

Failover

Contoh aplikasi failover :

Failover artinya mengatasi kalau ada service yang mati. Ada dua jenis aplikasi untuk menangani failover :

  • Network Oriented : keepalived, ucarp
  • Cluster Oriented : corosync, heartbeat

Penjelasan lengkapnya bisa dibaca di sini. Namun ringkasnya seperti ini:

Network oriented failover memastikan minimal satu service aktif, dan tidak apa-apa bila ada lebih dari satu service yang aktif. Ini cocok untuk dipasang di load balancer, karena load balancer tidak menyimpan state. Tidak masalah kalau user melihat ada dua LB, kadang diarahkan ke LB-1 dan kadang ke LB-2.

Cluster oriented failover memastikan hanya satu service yang aktif, dan tidak apa-apa bila tidak ada service yang aktif. Ini cocok untuk dipasang di database server, karena kita tidak mau database utama dan cadangan dua-duanya aktif. Bisa-bisa datanya tidak tersimpan dengan benar (split brain). Untuk lebih jelas tentang cara kerja cluster-oriented failover, bisa dibaca di sini.

Nah, mudah2an sampe di sini jelas bahwa load balancing dan failover itu dua hal yang tidak saling terkait (orthogonal) dan biasanya dikombinasikan untuk mendapatkan konfigurasi yang robust dan performant.

Setahu saya konsep2x Clustering diatas berlaku pada saat hit pertama. Pertanyaan saya.. Bagaimana jika request sudah terlayani tetapi ditengah-tengah proses server tiba2x down.. Apakah proses tersebut langsung di alihkan ke server yang lagi up? Jika iya apakah proses akan di restart dari awal atau server yang sedang up bisa melanjutkan sisa dari proses yang belum dikerjakan di server yang telah down?

Sticky Session

Tidak selalu, tergantung konfigurasinya. Ada konfigurasi sticky session. Artinya, pada hit pertama, si user akan diberikan penanda, biasanya berbentuk cookie. Pada hit berikutnya, LB akan melihat cookienya, dan mengarahkan ke server yang sebelumnya sudah mengurus si user ini.

Ada juga konfigurasi non-sticky. Artinya tiap hit dianggap hit baru, dan didistribusikan ke semua server sesuai algoritma yang dipilih, round robin, weighted, atau dynamic, sesuai penjelasan di atas.

Mau pilih yang mana? Ya tergantung kemampuan LB nya. Ada yang bisa 2-2 nya sehingga bisa pilih, dan ada juga yang rada stupid sehingga terpaksa pakai non-sticky. Istilahnya, LBnya layer berapa? Kalo layer 7 biasanya bisa sticky, kalo layer 4 ya gak bisa. Lebih jauh tentang urusan layer-layeran ini bisa dibaca di sini dan di sini

Nah, apa impact sticky vs non-sticky? Ini pengaruhnya ke session data. Session data adalah data sementara masing-masing user. Karena sifatnya sementara, maka biasanya tidak disimpan secara persistent di tabel database. Contoh paling klasik adalah isi shopping cart. Itu barang belum diorder, tapi sudah dipilih, sehingga biasanya belum disimpan di database.

Kalo pake non-sticky, si user pertama milih barang di server X. Pada saat dia pilih barang kedua, dilayani server Y. Karena pilihan pertama ada di server X, ya pas dia pilih barang kedua, cuma tercatat 1 barang padahal harusnya 2.

Ini tidak terjadi kalo kita pakai sticky balancer. Request kedua dan seterusnya akan diarahkan ke server X lagi.

Jadi, sticky atau non-sticky itu impactnya ke temporary data user, sering disebut dengan istilah session data atau user state.

Nah, setelah jelas apa dampaknya sticky vs non-sticky, mari kita lanjut ke pertanyaan selanjutnya.

Kalau untuk Java EE Application Server apakah untuk pertanyaan saya di atas sudah ada featurenya atau perlu ada tambahan produk lagi untuk bisa sharing informasi terhadap state suatu proses yang dijalankan di satu server sehingga jika server tersebut down proses bisa dilanjutkan di server yang lain tanpa merestart proses?

Session Replication

Mengenai urusan session/state management, ini sangat tergantung merek application server yang digunakan. Secara umum, settingan standar appserver biasanya simpan data session di memori. Kalau kita enable cluster, misalnya terdiri dari 4 worker, maka data session ini biasanya akan direplikasi ke satu worker lain. Pada saat worker utama mati, request berikutnya akan diarahkan ke worker cadangannya, sehingga user gak kehilangan data belanjaan. Biasanya, satu state itu disimpan ke 2 worker saja, bukan direplikasi ke semua untuk alasan efisiensi bandwidth.

Pada penjelasan di atas banyak sekali saya gunakan kata ‘biasanya’. Ini karena kapabilitas dan konfigurasi masing-masing merek appserver sangat berbeda sehingga sulit untuk menggeneralisir kondisinya.

Lalu bagaimana? Saya biasanya mengambil pendekatan yang universal, yang jalan di semua appserver, sehingga tidak perlu pusing menghafal appserver apa bisa apa settingnya gimana. Teknik universalnya sederhana: aplikasi webnya dibuat stateless. Jangan ada simpan data di memori. Simpan semua di database, atau di distributed cache (misalnya memcached).

Di Java, data yang ada di memori antara lain : session variable, static variable, context variable. Di PHP, CMIIW cuma session dan global variable aja.

Karena selama ini saya menggunakan teknik ini, jadi saya kurang up to date terhadap appserver apa bisa apa settingnya gimana. Demikian juga tentang load balancer apa support sticky atau tidak, saya tidak pernah memikirkannya. Pokoknya simpan state di distributed cache atau database, setelah itu mau pakai appserver Tomcat, Jetty, Glassfish, Weblogic, terserah. Mau pakai load balancer Apache HTTPD, Nginx, lighty, HAProxy, Pound, Ultramonkey, juga terserah.

Demikian sekilas sharing mengenai load balancing dan clustering. Semoga menjadi cerah.


Development Stack 2011

Posting ini adalah update dari posting tiga tahun yang lalu. Tidak banyak yang berubah dalam stack ini, yang bisa berarti dua hal: pilihan tiga tahun yang lalu sudah tepat atau malas belajar selama 3 tahun ini. Mudah-mudahan alasannya yang pertama :D

Update : Gradle tidak jadi dipakai, karena kita tidak mau maintain 2 skillset. Maven 2 ternyata stabil dan bekerja sesuai harapan. Hudson terlibat kerusuhan dengan Oracle, akhirnya fork jadi Jenkins.

Presentation Layer

  • Spring MVC

  • SiteMesh

  • Dojo Toolkit

  • ExtJS

  • Spring Security

  • Jasper Report

  • Jackson

Business Layer

  • Spring Framework

  • Hibernate

Library lain yang sering digunakan

  • Logback

  • Joda Time

  • Velocity

  • JPos

Infrastruktur

  • Version Control : Git + Gitosis

  • Testing Tools : JUnit, DBUnit, JMeter, Sonar

  • Issue Tracker : Redmine

  • Build Tools : Gradle, Maven

  • Continuous Integration : Hudson Jenkins

  • OS Programmer : Ubuntu Desktop

  • OS Server : Ubuntu Server, Debian

Deployment Target

  • Database Server : MySQL, Oracle

  • Application Server : Tomcat, Glassfish

Praktis perubahan yang terjadi hanyalah dari Subversion ganti menjadi Git. Nah, bagaimana menurut Anda? Pilihan tepat atau malas belajar?


Sharing Repository Git

Skenario : selama ini kita coding di laptop sendiri saja. Kemudian ada kebutuhan untuk kolaborasi dengan orang lain melalui Git. Bagaimana caranya? Baiklah mari kita bahas di artikel ini.

Inisialisasi Repository Git

Pertama, kita inisialisasi dulu repository Git. Masuk ke dalam folder project dan ketikkan

git init

Git akan membuat repository kosong di dalam folder project, ditandai dengan adanya folder baru bernama .git

Selanjutnya, kita akan memasukkan semua file dan folder project kita ke dalam repository. Yang harus dimasukkan adalah file source code, baik itu Java, HTML, XML, dan sebagainya. Yang tidak perlu dimasukkan adalah file hasil kompilasi atau hasil generate. Kita perlu mendaftarkan file yang tidak ingin disimpan dalam file konfigurasi yang bernama .gitignore

File ini harus kita buat sendiri menggunakan text editor. Berikut contoh isi filenya, bila kita coding menggunakan Eclipse atau Netbeans

[gist id=773975]

Setelah kita setting ignore file, berikutnya kita masukkan semua file dan folder ke dalam antrian.

git add . 

Kemudian, simpan ke repository

git commit -m "commit pertama project XXX"

Project sudah tersimpan di repository Git di komputer lokal kita. Mari kita upload ke server, atau dikenal dengan istilah push.

Share Repository

Kita memerlukan server di mana kita memiliki ijin akses untuk melakukan push. Cara memperoleh ijin akses tidak dibahas pada artikel ini. Silahkan buat account di Github atau Gitorious. Bila ingin push ke repository perusahaan, minta informasinya pada admin Anda.

Setelah kita mendapatkan URL server yang bisa kita gunakan, daftarkan sebagai remote. Berikut perintahnya.

git remote add <namaremote> <URL>

Contohnya seperti ini

git remote add github git@github.com:endymuhardin/project-terbaru-saya.git

Pastikan remotenya sudah terdaftar dengan perintah berikut

git remote -v

Terakhir, mari kita push dengan perintah berikut

git push <namaremote> <namabranch>

Contohnya

git push github master

Hore, project kita sudah naik ke server. Kita tinggal share URL tersebut ke rekan kerja kita.