Wow, ini adalah pertanyaan sederhana, yang berisi berbagai kemungkinan jawaban. Bagian yang lebih eksplisit dari pertanyaan Anda menanyakan apakah lebih mudah untuk berinteraksi dengan basis data Anda secara langsung atau melalui layanan web. Jawabannya sederhana: query database secara langsung. Pergi melalui layanan web menambahkan sejumlah latensi yang sama sekali tidak perlu untuk kode yang beroperasi di belakang firewall (pada umumnya). Layanan web misalnya memerlukan beberapa komponen untuk menerima permintaan, deserialize itu, permintaan DB, cerita berseri tanggapan dan mengembalikannya. Jadi, jika kode Anda semuanya beroperasi di belakang firewall, selamatkan diri Anda dari masalah dan minta saja DB secara langsung.
Namun membuat situs web scalable jauh melampaui pertanyaan yang awalnya Anda ajukan. Jadi maafkan saya jika saya menggunakan garis singgung di sini, tetapi saya pikir ini mungkin berguna mengingat Anda menyebutkan Facebook secara khusus.
Saya akan merekomendasikan Anda membaca tentang pekerjaan dan alat yang dibangun oleh Brad Fitzpatrick (pendiri LiveJournal dan sekarang di Google). Ketika saya bekerja dengannya di Six Apart, berikut adalah beberapa hal yang saya pelajari darinya, dan tentang arsitektur LiveJournal yang membuatnya sangat terukur.
Gunakan tabel database sempit sebagai lawan dari yang luas . Yang menarik tentang ini adalah mempelajari apa yang memotivasi arsitektur ini, yang menciptakan sistem yang mudah dan cepatditingkatkan. Jika Anda menggunakan tabel lebar, atau tabel di mana setiap bidang atau properti adalah kolom dalam tabel, ketika tiba saatnya untuk memutakhirkan skema database, misalnya menambahkan kolom baru, maka sistem akan perlu mengunci tabel sementara skema perubahan diterapkan. Ketika beroperasi pada skala ini berarti perubahan sederhana ke skema database dapat mengakibatkan pemadaman database yang besar. Yang jelas menyebalkan. Sebuah tabel sempit di sisi lain hanya menyimpan setiap properti individu yang terkait dengan objek sebagai satu baris dalam database. Oleh karena itu ketika Anda ingin menambahkan kolom baru ke database yang perlu Anda lakukan adalah INSERT rekaman ke dalam tabel, yang merupakan operasi non-penguncian. Ok, itu sedikit latar belakang, mari kita lihat bagaimana model ini diterjemahkan dalam sistem kerja seperti LiveJournal.
Katakanlah Anda ingin memuat 10 entri jurnal terakhir di blog seseorang, dan katakanlah setiap entri jurnal memiliki sepuluh properti. Dalam tata letak tabel lebar klasik, setiap properti akan berkorelasi dengan kolom pada tabel. Seorang pengguna kemudian akan meminta tabel sekali untuk mengambil semua data yang mereka butuhkan. Kueri akan mengembalikan 10 baris dan setiap baris akan memiliki semua data yang mereka butuhkan (misalnya PILIH * DARI entri ORDER DENGAN tanggal BATAS 10). Namun dalam tata letak tabel yang sempit sedikit berbeda. Dalam contoh ini sebenarnya ada dua tabel: tabel pertama (tabel A) menyimpan kriteria sederhana yang ingin dicari, misalnya id entri, id penulis, tanggal entri, dll. Tabel kedua (tabel B) kemudian menyimpan semua properti yang terkait dengan entri. Tabel kedua ini memiliki tiga kolom: entry_id, key dan value. Untuk setiap baris di tabel A, akan ada 10 baris di tabel B (satu baris untuk setiap properti). Oleh karena itu untuk mengambil dan menampilkan sepuluh entri terakhir, Anda perlu 11 pertanyaan. Kueri pertama memberi Anda daftar ID entri, dan kemudian sepuluh kueri berikutnya akan mengambil properti yang terkait dengan masing-masing entri yang dikembalikan dalam kueri pertama.
"Moly suci!" Anda berkata, "bagaimana mungkin ini lebih skalabel ?!" Benar-benar kontra-intuitif, bukan? Dalam skenario pertama kami hanya memiliki satu permintaan basis data, tetapi dalam solusi "lebih skalabel" kedua kami memiliki 11 permintaan basis data. Itu tidak masuk akal. Jawaban atas pertanyaan itu sepenuhnya bergantung pada peluru berikutnya.
Gunakan memcache secara bebas. Jika Anda tidak sadar, memcache adalah sistem caching berbasis jaringan yang terdistribusi, stateless, latensi rendah. Ini digunakan oleh Facebook, Google, Yahoo, dan hampir setiap situs web populer dan terukur di planet ini. Itu diciptakan oleh Brad Fitzpatrick sebagian untuk membantu mengimbangi overhead database yang melekat dalam desain database tabel sempit. Mari kita lihat contoh yang sama seperti yang dibahas di # 1 di atas, tapi kali ini, mari kita kenalkan memcache.
Mari kita mulai ketika pengguna pertama kali mengunjungi halaman dan tidak ada yang ada dalam cache. Anda mulai dengan menanyakan tabel A yang mengembalikan ID dari 10 entri yang ingin Anda tampilkan di halaman. Untuk setiap entri tersebut, Anda kemudian meminta basis data untuk mengambil properti yang terkait dengan entri itu, dan kemudian menggunakan properti tersebut merupakan objek yang dapat berinteraksi dengan kode Anda (misalnya objek). Anda kemudian menyembunyikan objek itu (atau bentuk serial objek itu) dalam memcache.
Saat kedua seseorang memuat halaman yang sama, Anda memulai dengan cara yang sama: dengan menanyakan tabel A untuk daftar ID entri yang akan Anda tampilkan. Untuk setiap entri, Anda pertama-tama pergi ke memcache dan berkata, "apakah Anda memiliki entri #X dalam cache?" Jika ya, maka memcache mengembalikan objek entri kepada Anda. Jika tidak, maka Anda perlu melakukan kueri database lagi untuk mengambil propertinya, merupakan objek dan menyimpannya dalam memcache. Sebagian besar waktu, kedua kalinya seseorang mengunjungi halaman yang sama hanya ada satu permintaan basis data, semua data lain kemudian ditarik langsung dari memcache.
Dalam praktiknya, apa yang akhirnya terjadi pada sebagian besar LiveJournal adalah bahwa sebagian besar data sistem, terutama data yang kurang volatil, di-cache dalam memcache dan permintaan tambahan ke database yang diperlukan untuk mendukung skema tabel sempit semuanya sudah sepenuhnya diimbangi.
Desain ini membuat penyelesaian masalah yang terkait dengan merakit daftar posting yang terkait dengan semua teman Anda ke dalam aliran, atau "dinding", jauh lebih mudah.
Selanjutnya, pertimbangkan mempartisi basis data Anda. Model yang dibahas di atas memunculkan masalah lain, dan itu adalah tabel sempit Anda akan cenderung sangat besar / panjang. Dan semakin banyak baris tabel tersebut semakin sulit tugas administrasi lainnya. Untuk mengimbangi ini, mungkin masuk akal untuk mengelola ukuran tabel Anda dengan mempartisi tabel di suatu tempat, sehingga kelompok pengguna dilayani oleh satu database, dan sekelompok pengguna lain dilayani oleh database terpisah. Ini mendistribusikan beban pada database dan membuat kueri tetap efisien.
Akhirnya, Anda membutuhkan indeks yang mengagumkan. Kecepatan pertanyaan Anda akan sangat tergantung pada seberapa baik tabel indeks Anda. Saya tidak akan menghabiskan terlalu banyak waktu untuk membahas apa itu indeks, kecuali untuk mengatakan bahwa itu sangat mirip dengan sistem katalog kartu raksasa untuk membuat mencari jarum di tumpukan jerami lebih efisien. Jika Anda menggunakan mysql maka saya sarankan menyalakan log permintaan lambat untuk memantau permintaan yang membutuhkan waktu lama untuk dipenuhi. Ketika kueri muncul di radar Anda (misalnya karena lambat), lalu cari tahu indeks apa yang perlu Anda tambahkan ke tabel untuk mempercepatnya.
"Terima kasih untuk semua latar belakang yang luar biasa ini, tetapi kudus, itu banyak kode yang harus saya tulis."
Belum tentu. Banyak perpustakaan telah ditulis yang membuat antarmuka dengan memcache sangat mudah. Masih perpustakaan lain telah mengodifikasi seluruh proses yang dijelaskan di atas; Data :: ObjectDriver di Perl hanyalah perpustakaan seperti itu. Sedangkan untuk bahasa lain, Anda perlu melakukan riset sendiri.
Saya harap Anda menemukan jawaban ini bermanfaat. Apa yang saya temukan lebih sering daripada tidak adalah bahwa skalabilitas suatu sistem sering turun semakin sedikit ke kode, dan semakin banyak ke penyimpanan data yang sehat dan strategi manajemen / desain teknis.