Replikasi Natif MySQL untuk Load Balancing Aplikasi PHP

Situs www.tambahngetop.com yang Anda buat dengan PHP dan MySQL semakin lama semakin popular, pageviewnya meningkat terus, dan demikian juga beban server sebagai konsekuensinya. Sesuatu harus dilakukan. Anda sudah mengkonfigurasi server untuk bekerja seoptimal mungkin, dan akhirnya Anda memutuskan untuk memisah database server pada mesin tersendiri. Tapi seiring dengan bertambahnya fitur-fitur pada situs tersebut, penggunanya juga terus bertambah banyak. Hingga suatu hari Anda mendapati database server Anda macet karena tidak mampu lagi menangani beban yang sudah semakin tinggi. Anda tahu bahwa replikasi natif MySQL seharusnya dapat membantu menyelesaikan masalah ini. Tapi bagaimana menggunakannya dalam sebuah skema load-balancing? Dalam tulisan ini dibahas load balancing MySQL menggunakan MyMultiplex, sebuah query multiplexer/dispatcher khusus untuk PHP dan MySQL, yang memungkinkan aplikasi-aplikasi PHP memanfaatkan replikasi natif MySQL dengan perubahan kode yang minimal.

MySQL dan Replikasi

Sebuah database yang direplikasi berarti bahwa database dari sebuah mesin sumber—biasa disebut sebagai mesin master—diduplikasi ke satu atau lebih mesin lain—biasa disebut sebagai mesin-mesin slave. Dengan tersedianya sejumlah server yang memiliki isi database yang persis sama, maka ketersediaan dan kinerja sistem dapat ditingkatkan. Ketersediaan ditingkatkan dengan membuat backup online yang senantiasa up-to-date dengan database master. Kinerja ditingkatkan dengan memultipleksi query sehingga beban tidak lagi terpusat pada satu mesin, tapi terbagi di antara master dan mesin-mesin slave.
Sejak versi 3.23.15 yang dirilis bulan April 2000, MySQL mendukung replikasi satu arah [4]. Satu mesin berperan sebagai master, dan mesin-mesin lain sebagai slave. Replikasi satu arah berarti bahwa replikasi MySQL tidak dirancang untuk menangani distributed update di mana update pada beberapa mesin master dalam waktu yang kurang lebih bersamaan dapat disinkronisasikan satu sama lain.
Prinsip kerja replikasi MySQL boleh dibilang cukup sederhana: mesin master me-log setiap update database pada sebuah file log biner. Mesin-mesin slave melalui thread replikasinya membuat koneksi ke master, dan mengejar update pada master berdasarkan log biner tersebut.
Pada rilis MySQL versi-versi berikutnya, implementasi replikasi natif ini semakin solid, dan juga ditambahkan beberapa perintah untuk mempermudah monitoring dan administrasinya. Tanpa banyak kesulitan, orang mengadopsi fitur ini untuk membuat hot-standby backup [2].

Konfigurasi Replikasi Natif

Berikut ini adalah langkah-langkah untuk mengaktifkan replikasi natif MySQL. Contoh yang diberikan di sini mengasumsikan mesin master dengan alamat IP 192.168.0.1 dan satu mesin slave dengan alamat IP 192.168.0.2.

Persiapan

Instal MySQL di mesin slave. Ini haruslah mesin yang berbeda dari mesin master. Anda tidak dapat bereksperimen dengan menjalankan master dan slave pada mesin yang sama dengan port TCP yang berbeda. Sebaiknya master dan slave menggunakan versi MySQL yang sama, dan manual MySQL menyarankan versi 3.23.29 ke atas.

Konfigurasi Master

Di mesin master, buat account dengan privilege FILE, misalkan:
GRANT FILE ON *.* TO repl@192.168.0.2 IDENTIFIED BY 'replpass';
 
Account ini diperlukan oleh thread replikasi slave untuk membuat koneksi ke mesin master. Thread replikasi slave bekerja berdasarkan update log biner pada master, sehingga update log biner ini harus diaktifkan pada master dengan menambahkan baris berikut pada my.cnf master:
[mysqld]

log-bin

server-id = 1
 
Baris log-bin mengaktifkan update log biner, dan server-idadalah nomor unik yang digunakan untuk membedakan antara master, slave pertama, kedua, dan berikutnya.
Selanjutnya kita perlu membuat duplikat database yang mau direplikasi dari master ke slave—istilah orang pintar: mengambil snapshot database. Tidak boleh ada operasi penulisan pada database ketika snapshot database tersebut sedang diambil. Maka dari itu biasanya MySQL master di-shutdown menjelang pengambilan snapshot.
Cara yang sederhana untuk mengambil snapshot adalah menggunakan tar dan mengupload arsip tar yang dihasilkan ke mesin slave. Namun cara ini bermasalah jika ukuran database master sangat besar, karena dengan demikian waktu yang diperlukan menjadi sangat lama, yang berarti downtime yang sangat lama.
Jika hal ini tidak dapat diterima, maka diperlukan cara lain untuk mempersingkat waktu pengambilan snapshot ini, misalkan dengan menggunakan rsync. Jalankan rsync di mesin slave melalui cron. Dengan demikian, setelah shutdown MySQL master, rsync hanya perlu mensinkronisasi perubahan data yang terjadi setelah rsync terakhir. Cara lain yang memungkinkan pengambilan snapshot tanpa perlu shutdown MySQL adalah dengan skrip Perl mysqlsnapshot [1] (tapi saya belum pernah mencobanya).
Sekarang start MySQL server di master. Mulai saat ini MySQL master me-log setiap update yang terjadi setelah snapshot diambil. Anda dapat memonitor status dari log biner melalui perintah SHOW MASTER STATUS di konsol mysql.

Konfigurasi Slave

Pada mysql.cnf slave, tambahkan:
[mysqld]

server-id = <integer positif unik>

master-host = <hostname atau alamat IP>

master-user = <username>

master-password = <password>
 
Jika MySQL master aktif di port selain 3306, maka tambahkan:
master-port = <nomor TCP port>
 
Jika hanya database tertentu saja yang mau direplikasi, maka tambahkan:
replicate-do-db = <nama database>
 
Kopikan hasil snapshot dari master tadi ke slave. Jika Anda menggunakan rsync tentu saja langkah ini tidak perlu.
Restart slave. Anda dapat memantau status dari thread replikasi melalui perintah SHOW SLAVE STATUS di konsol mysql.

Load Balancing dengan MyMultiplex

Untuk menggunakan replikasi natif ini dalam sebuah skema load balancing, aplikasi harus memultipleksi query, yaitu mengirimkan query ke master dan slave-slave secara bergantian. Dua hal yang perlu diperhatikan di sini adalah: pertama, slave tidak punya mekanisme redireksi query (seperti yang biasa dijumpai pada implementasi LDAP). Ini berarti aplikasilah yang bertanggung jawab untuk memastikan bahwa setiap operasi tulis (updating query) hanya terjadi di mesin master. Update langsung pada slave tidak akan direplikasi ataupun diredireksi ke master, sehingga jika ini sampai terjadi maka akan muncul inkonsistensi di antara master dan slave.
Kedua, LOCK TABLESdan UNLOCK TABLES diarahkan hanya ke mesin master, karena perintah-perintah locking tersebut biasanya disertai dengan operasi tulis. Query SELECT setelah LOCK TABLES dan sebelum UNLOCK TABLES juga perlu dipastikan terjadi hanya di mesin master. Ini karena ketika terjadi update di master, secepat apapun slave mengejar update tersebut, selalu ada selisih waktu di mana isi database di slave belum konsisten dengan isi database master.
Tidak sulit, tapi yang menjadi masalah adalah biasanya aplikasi-aplikasi yang ada (termasuk mungkin aplikasi yang Anda buat) tidak dirancang untuk menggunakan replikasi natif ini, sehingga diperlukan modifikasi kode yang tidak sedikit untuk itu. Lain halnya jika Anda memang sejak awal memang merancang aplikasi PHP Anda untuk mendukung fitur load balancing MySQL, di mana Anda dapat menggunakan SQL Relay [5] ataupun SQLB [6].
Untuk menghindari modifikasi kode aplikasi yang sudah jadi dan telanjur kompleks, maka query multiplexing sebaiknya diimplementasikan di layer antarmuka database sambil mempertahankan API yang ada. Sayangnya desain antarmuka database di PHP tidak begitu modular, orang tidak bisa membuat wrapper layer dalam PHP di atas API MySQL di mana wrapper tersebut memiliki fungsi-fungsi yang persis sama seperti pada API MySQL tersebut. Sebagai perbandingan adalah DBI di bahasa Perl, yang cukup fleksibel sehingga orang dapat membuat multiplexer query sebagai sebuah driver DBI Perl DBI murni. 

MyMultiplex[3] menyediakan layer wrapper yang dibutuhkan ini, seraya mempertahankan API MySQL PHP, sehingga aplikasi tidak perlu ditulis ulang karena fungsi-fungsi MySQL yang dipakai aplikasi tetap sama. Gambar1 memperlihatkan aliran query dari aplikasi sampai ke MySQL pada aplikasi biasa tanpa load balancing, dan Gambar 2 jika MyMultiplex digunakan pada aplikasi dengan beberapa MySQL server yang di-load balance.


MyMultiplex dapat didownload di pope.perlmonk.org/php/, dan versi terbaru pada saat tulisan ini dibuat adalah 0.92. MyMultiplex terdiri dari dua bagian, yaitu patch untuk ekstensi MySQL PHP, dan MyMultiplex.phl, sebuah library PHP yang perlu di-include oleh aplikasi PHP. Untuk menggunakan MyMultiplex Anda membutuhkan source code PHP dan client library MySQL. Berikut ini adalah langkah-langkah instalasi MyMultiplex:

Mengkompilasi Ulang PHP

Gunakan mysql.c.diff dan mysql.h.diff dari MyMutiplex untuk mempatch ekstensi MySQL PHP sebelum mengkompilasi ulang PHP:

$ gunzip -c php-4.0.x.tar.gz | tar xf -

$ cd php-4.0.x

$ cd ext/mysql

$ patch <mysql.c.diff

$ patch <mysql.h.diff
 
Kemudian lanjutkan dengan langkah-langkah instalasi sesuai petunjuk yang disertakan dalam distribusi PHP.

Sisipkan MyMultiplex.phl

MyMultiplex.phl mendefinisikan ulang fungsi-fungsi MySQL PHP, sehingga file ini perlu diinclude oleh setiap halaman yang menggunakan fungsi-fungsi tersebut. Idealnya adalah jika aplikasi Anda memiliki satu file sentral yang pasti diinclude oleh semua halaman—misalkan file konfigurasi global—maka sebaiknya MyMultiplex.phl diinclude di dalam file tersebut. Namun jika ini tidak mungkin, sebagai gantinya Anda dapat menggunakan direktif auto_prepend_filedi dalam php.ini, sekalipun ini agak mahal:

auto_prepend_file = MyMultiplex.phl
 
Pastikan MyMultiplex.phl berada dalam include path.

Ubah Connect String

Jika semula aplikasi Anda hanya membuka koneksi database ke satu mesin, maka sekarang ia perlu disiapkan untuk membuka koneksi ke beberapa mesin sekaligus. Caranya yaitu dengan mengubah connect string pada pemanggilan mysql_connect(). Sebagai contoh, misalkan semula aplikasi Anda membuka koneksi ke mesin 192.168.0.1 sebagai berikut:

$server = '192.168.0.1';

$link = mysql_connect($server, $user, $pass)

or die("Can't open database connection");
 
Kemudian sekarang Anda mau mengubahnya untuk membuka koneksi ke mesin master yang beralamat IP 192.168.0.1 dan ke sebuah mesin slave pada alamat 192.168.0.2, maka string $server menjadi:
$server = '192.168.0.1;master|192.168.0.2';
Jika MySQL mendengarkan pada port selain 3306, maka nomor port perlu disebutkan. Misalkan jika pada mesin master di atas, MySQL mendengarkan pada port 3307, maka:
$server = '192.168.0.1:3307;master|192.168.0.2';
Masing-masing mesin dinyatakan dengan kombinasi nama host (atau alamat IP) dan nomor port MySQL daemon pada mesin tersebut. Nomor port default bersifat opsional. Satu mesin dengan mesin yang lain dipisahkan oleh karakter pipe (|). Di antara mesin-mesin tersebut, harusada satu mesin master, dan ini dinyatakan dengan menambahkan ";master" di belakang nama host atau alamat IP mesin yang bersangkutan.

Di Mana MyMultiplex Digunakan?

MyMultiplex dibuat untuk mengatasi problem overload pada server database situs Astaga!com (www.astaga.com) yang menggunakan MySQL versi 3.23.39. Problem tersebut teramati tidak lama setelah migrasi back-end database yang tadinya menggunakan Oracle dan MS-SQL Server. MyMultiplex digunakan sejak 22 Juli 2001 hingga sekarang, dan baru pernah di-upgrade satu kali, yaitu versi 0.92 yang diacu sepanjang tulisan ini. Karena versi terbaru PHP saat itu adalah 4.0.6, maka ada kemungkinan patch yang disediakan MyMultiplex tidak bekerja untuk versi PHP yang lebih baru dari itu. Mudah-mudahan maintainernya tidak terlalu malas untuk mengupdatenya sehingga dapat dipakai pada PHP versi yang lebih baru.

Kapan Load Balancing?

Load balancing menggunakan replikasi natif MySQL hanya akan menolong jika karakteristik query aplikasi Anda didominasi oleh operasi pembacaan (read query). Hal ini dijelaskan panjang lebar dalam manual MySQL. Selain itu, jika Anda menemukan gejala overload pada sistem Anda, ada baiknya diselidiki lebih dulu sebab terjadinya overload itu. Setidaknya ada beberapa titik berikut yang potensial menjadi sebab munculnya gejala overload, yaitu pada aplikasi, desain database, hardware, dan kernel.

Aplikasi. Sebuah halaman web boleh jadi dibuat on-the-fly dari hasil sejumlah query. Mengcache hasil query akan sangat membantu, jika ini dimungkinkan.

Desain Database. Lalai mengindeks kolom yang menjadi kunci pencarian mengakibatkan MySQL melakukan search sekuensial yang semakin mahal untuk ukuran tabel yang semakin besar. MySQL juga tidak begitu bagus pada JOIN query yang melibatkan banyak tabel.

Hardware. Kurangnya RAM dapat mengakibatkan disk swapping yang ekstensif. Problem pada hard disk controller juga dapat memunculkan gejala overload. Menggunakan beberapa hard disk lebih menguntungkan, karena tabel yang paling tinggi aksesnya dapat dipindahkan pada hard disk tersendiri untuk mengurangi efek seek contention. 

Kernel. Beberapa versi kernel dari Linux dan FreeBSD diketahui mengandung bug pada implementasi SMP-nya, sehingga muncul gejala overload ketika MySQL digunakan pada mesin multiprosesor.
Jika Anda tidak menjumpai masalah pada hal-hal di atas, maka mungkin memang sudah waktunya sistem Anda membutuhkan load balancing MySQL.

Penutup

Sebagaimana upaya-upaya pihak ketiga yang bersifat work around, boleh jadi dalam MySQL versi 4.x mendatang MyMultiplex tidak dibutuhkan lagi. Namun setidaknya dalam MySQL versi 4.01 alfa—versi development terbaru pada saat tulisan ini dibuat—masih belum terlihat adanya implementasi awal dari query multiplexing ini sebagai fitur built-in MySQL, sehingga jika aplikasi PHP Anda membutuhkan load balancing MySQL hari ini juga, nampaknya MyMultiplex masih menjadi jawaban yang realistis.

URL

2. Using MySQL’s Built-In Replication To Maximize Availability: phpbuilder.com/columns/tanoviceanu20000912.php3
3. MyMultiplex: pope.perlmonk.org/php/

0 comments:

Post a Comment

Please Enable JavaScript!
Mohon Aktifkan Javascript![ Enable JavaScript ]
close
close