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-id
adalah 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 TABLES
dan 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_file
di 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, harus
ada 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
1.
mysqlsnapshot: family.zawodny.com/jzawodn/mysql/mysqlsnapshot/
2.
Using MySQL’s Built-In Replication To Maximize
Availability: phpbuilder.com/columns/tanoviceanu20000912.php3
3.
MyMultiplex: pope.perlmonk.org/php/
4.
Replication in MySQL: www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Replication
5.
SQL Relay: www.firstworks.com/sqlrelay.html
0 comments:
Post a Comment