Sunday, September 18, 2016

Optimal Memory Partitioning with Linux Explicit Huge Pages

Salah satu tantangan yang saya rasakan ketika membuat sebuah platform virtualisasi adalah bagaimana secara efektif platform tersebut dapat mengalokasikan memori untuk virtual machine secara fleksibel dan handal. Seringkali ketika kita tidak memikirkan hal tersebut, memori yang tersedia di hypervisor tidak selalu sepenuhnya tersedia secara efektif. Ketika memori diperlukan untuk menghidupkan sebuah virtual machine, bisa jadi memori yang tersedia sudah dipegang oleh mekanisme Linux Page Cache atau proses di hypervisor yang lain. Sehingga memori yang bebas digunakan oleh virtual machine sulit untuk diperoleh angka persisnya berapa. Terkadang kita tidak menyadari bahwa sebetulnya memori yang bebas itu sudah menipis sehingga ketika menghidupkan virtual machine tambahan, hypervisor harus melakukan swapping sehingga kinerja keseluruhan menjadi turun.

Hypervisor pun sebetulnya juga membutuhkan resource komputasi yang cukup untuk melakukan aktivitasnya. Sebuah hypervisor berkapasitas 128 GB memori, tentu bukan berarti kita dapat menghidupkan 16 virtual machine berkapasitas 8 GB. Kita harus memikirkan juga untuk menyisakan sebagian memori dari 128 GB tersebut khusus untuk dikonsumsi oleh hyperivisor. Pendekatan yang dilakukan oleh cloud provider besar seperti Google Cloud Platform dan Microsoft Azure, adalah dengan menyediakan paket-paket sizing virtual machine yang sedikit dikurangi kapasitas memorinya dari kapasitas yang umum. 

Skema Sizing Microsoft Azure

Pada skema Microsoft Azure di atas, terlihat bahwa untuk setiap tipe virtual machine yang ditawarkan besar kapasitas memori adalah sedikit di bawah angka standar dari deret eksponensial 2 (1 GB, 2 GB, 4 GB, 8 GB, 16 GB, 32 GB, 64 GB, 128 GB). Semakin besar memori yang akan dialokasikan ke sebuah virtual machine, semakin besar pula selisihnya dengan angka umum.

Skema Sizing Google Cloud Platform

Skema yang serupa ternyata juga terlihat pada skema ukuran virtual machine yang disediakan di Google Cloud Platform. Walaupun tidak seagresif pengalokasian pada Microsoft Azure, Google Cloud Platform juga terlihat menyediakan sebagian memori yang seharusnya dialokasikan mengikuti deret eksponensial 2.

Kedua contoh tersebut dapat diaplikasikan pada cloud provider besar seperti Microsoft Azure dan Google Cloud Platform karena jumlah hypervisor node yang mereka miliki juga sangat banyak. Namun bagaimana pada kasus topologi yang sederhana. Misalnya saja pada server development di Nostratech, bernama Arjuna, yang hanya memiliki kapasitas memori 96 GB. Pengalokasian seperti model tersebut selain cukup menyulitkan dalam perhitungan, dalam jumlah virtual machine yang banyak juga akan sangat banyak memori yang tidak termanfaatkan dengan baik.

Sebagai latar belakang, Arjuna merupakan development platform di Nostratech yang saya rancang dengan menggunakan teknologi Linux KVM sebagai hypervisor dan OpenZFS sebagai storage management layer-nya. Kedua teknologi tersebut bisa dikatakan banyak menggunakan memori sehingga saya merasa cukup tertantang ketika merancang Arjuna. Saya tidak pernah suka dengan swap space, karena menurut saya ketika sudah terjadi swapping proses apapun juga akan menjadi lambat dan tidak efektif lagi. Sehingga saya tidak mengalokasikan swap space sama sekali pada Arjuna. Berikut adalah pembagian memori yang saya lakukan pada Arjuna:


Pada skema tersebut terlihat dengan jelas pembagian 96 GB memori ke masing-masing pemetaannya. Linux Page Cache merupakan mekanisme caching pada Linux dan untuk mengaturnya membutuhkan parameter yang cukup kompleks dan tidak secara eksplisit terlihat berapa penggunakan maksimumnya. Untuk itulah pendekatan yang saya lakukan terbalik. Saya merancang untuk mengalokasikan 8 GB untuk OpenZFS ARC caching, dan 80 GB untuk virtual machine. Sehingga sisa 8 GB dapat secara bebas dimanfaatkan oleh Linux Page Cache. Namun bagaimana saya dapat menjamin saya dapat mengalokasikan 80 GB untuk virtual machine? Di sinilah saya memanfaatkan teknologi explicit huge pages pada Linux.

Linux mengakses memori dalam bentuk satuan kecil yang bernama pages. Besaran asli dari pages adalah sekitar 4 kB. Huge pages [1][2] merupakan terobosan selanjutnya yang memungkinkan besaran dari pages ditingkatkan menjadi 2 MB hingga 1 GB. Sehingga pengalokasian memori dapat lebih efektif karena jumlah call yang diperlukan menjadi lebih sedikit untuk jumlah pengalokasian memori yang sama.

Linux memiliki 2 tipe huge pages, transparent huge pages dan explicit huge pages. Perbedaan dari keduanya adalah pada transparent huge pages kernel Linux sendiri yang melakukan pengaturan proses apa dan menggunakan page size yang mana yang tepat. Sedangkan pada explicit huge pages sejak dari awal boot, kernel sudah melakukan alokasi partisi memori sehingga menjamin keseinambungan dari memori yang dialokasikan. Arjuna menggunakan explicit huge pages, sehingga setiap kali boot Arjuna memiliki pemetaan memori seperti gambar sebelumnya.

Untuk konfigurasi yang perlu dilakukan adalah cukup dengan menambahkan kernel boot parameter berikut ini:
transparent_hugepage=never default_hugepagesz=2M hugepagesz=2M hugepages=40960

Sedangkan untuk melihat berapa sisa kapasitas memori dari partisi explicit huge pages dapat menggunakan perintah berikut ini:
grep Huge /proc/meminfo

Agar Linux KVM dapat memanfaatkan partisi memori huge pages tersebut, perlu disisipkan sedikit konfigurasi pada QEMU command line-nya:
-mem-path /dev/hugepages

Jika menggunakan libvirt XML, maka perlu menambahkan:
<memoryBacking>
<hugepages/>
</memoryBacking>

Selamat mencoba!

[1] https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
[2] https://wiki.debian.org/Hugepages




No comments:

Post a Comment