Tim di LMAX memiliki presentasi tentang bagaimana mereka dapat melakukan 100rb TPS kurang dari 1 ms latensi . Mereka telah membuat cadangan presentasi itu dengan blog , kertas teknis (PDF) dan kode sumbernya sendiri.
Baru-baru ini, Martin Fowler menerbitkan sebuah makalah yang luar biasa tentang arsitektur LMAX dan menyebutkan bahwa mereka sekarang mampu menangani enam juta pesanan per detik dan menyoroti beberapa langkah yang diambil tim untuk naik urutan urutan besar dalam kinerja.
Sejauh ini saya sudah menjelaskan bahwa kunci kecepatan Business Logic Processor adalah melakukan semuanya secara berurutan, dalam memori. Hanya melakukan ini (dan tidak ada yang benar-benar bodoh) memungkinkan pengembang untuk menulis kode yang dapat memproses 10K TPS.
Mereka kemudian menemukan bahwa berkonsentrasi pada elemen sederhana dari kode yang baik dapat membawa ini ke kisaran 100K TPS. Ini hanya membutuhkan kode yang diperhitungkan dengan baik dan metode-metode kecil - pada dasarnya ini memungkinkan Hotspot untuk melakukan pekerjaan yang lebih baik untuk mengoptimalkan dan agar CPU menjadi lebih efisien dalam menyimpan kode ketika sedang berjalan.
Butuh sedikit lebih pintar untuk naik urutan besarnya. Ada beberapa hal yang menurut tim LMAX bermanfaat untuk mencapainya. Salah satunya adalah menulis implementasi kustom dari koleksi Java yang dirancang untuk menjadi cache-friendly dan hati-hati dengan sampah.
Teknik lain untuk mencapai tingkat kinerja teratas adalah dengan menaruh perhatian pada pengujian kinerja. Saya sudah lama memperhatikan bahwa orang berbicara banyak tentang teknik untuk meningkatkan kinerja, tetapi satu hal yang benar-benar membuat perbedaan adalah mengujinya
Fowler menyebutkan bahwa ada beberapa hal yang ditemukan, tetapi dia hanya menyebut pasangan.
Adakah arsitektur, perpustakaan, teknik, atau "hal" lain yang membantu untuk mencapai tingkat kinerja seperti itu?
sumber
Jawaban:
Ada berbagai macam teknik untuk pemrosesan transaksi berkinerja tinggi dan yang ada di artikel Fowler hanyalah salah satu dari sekian banyak teknik yang ada. Daripada mendaftar banyak teknik yang mungkin atau mungkin tidak berlaku untuk situasi siapa pun, saya pikir lebih baik untuk membahas prinsip-prinsip dasar dan bagaimana LMAX menangani sejumlah besar dari mereka.
Untuk sistem pemrosesan transaksi skala tinggi, Anda ingin melakukan semua hal berikut sebanyak mungkin:
Minimalkan waktu yang dihabiskan di tingkat penyimpanan paling lambat. Dari tercepat hingga paling lambat pada server modern yang Anda miliki: CPU / L1 -> L2 -> L3 -> RAM -> Disk / LAN -> WAN. Lompatan dari bahkan disk magnetik modern tercepat ke RAM paling lambat adalah lebih dari 1000x untuk akses sekuensial ; akses acak bahkan lebih buruk.
Minimalkan atau hilangkan waktu yang dihabiskan untuk menunggu . Ini berarti berbagi negara sesedikit mungkin, dan, jika negara harus dibagi, menghindari kunci eksplisit bila memungkinkan.
Sebarkan beban kerja. CPU belum mendapatkan jauh lebih cepat dalam beberapa tahun terakhir, tetapi mereka telah mendapatkan lebih kecil, dan 8 core sangat umum pada server. Di luar itu, Anda bahkan dapat menyebarkan pekerjaan melalui beberapa mesin, yang merupakan pendekatan Google; hal yang hebat tentang ini adalah bahwa ia menskala segala sesuatu termasuk I / O.
Menurut Fowler, LMAX mengambil pendekatan berikut untuk masing-masing:
Simpan semua status dalam memori setiap saat. Sebagian besar mesin database sebenarnya akan melakukan ini, jika seluruh database dapat masuk dalam memori, tetapi mereka tidak ingin meninggalkan apa pun untuk kesempatan, yang dapat dimengerti pada platform perdagangan real-time. Untuk melakukan ini tanpa menambahkan satu ton risiko, mereka harus membangun banyak cadangan ringan dan infrastruktur failover.
Gunakan antrian bebas kunci ("pengganggu") untuk aliran acara masukan. Berbeda dengan antrian pesan tahan lama tradisional yang pasti tidak bebas kunci, dan pada kenyataannya biasanya melibatkan transaksi yang didistribusikan dengan sangat lambat .
Tidak banyak. LMAX melempar yang ini di bawah bus atas dasar bahwa beban kerja saling tergantung; hasil satu mengubah parameter untuk yang lain. Ini adalah peringatan kritis , dan yang secara eksplisit dipanggil Fowler. Mereka membuat beberapa penggunaan concurrency dalam rangka memberikan kemampuan failover, tapi semua logika bisnis diproses pada thread tunggal .
LMAX bukan satu-satunya pendekatan untuk OLTP skala tinggi. Dan meskipun itu cukup brilian dalam dirinya sendiri, Anda tidak perlu menggunakan teknik-teknik yang canggih untuk melakukan tingkat kinerja itu.
Dari semua prinsip di atas, # 3 mungkin yang paling penting dan paling efektif, karena, sejujurnya, perangkat keras itu murah. Jika Anda dapat mempartisi beban kerja dengan benar di setengah lusin inti dan beberapa lusin mesin, maka langit adalah batas untuk teknik Komputasi Paralel konvensional . Anda akan terkejut betapa banyak throughput yang Anda dapat lakukan dengan apa-apa selain sekelompok antrian pesan dan distributor round-robin. Ini jelas tidak seefisien LMAX - sebenarnya bahkan tidak dekat - tetapi throughput, latensi, dan efektivitas biaya adalah masalah yang terpisah, dan di sini kita berbicara secara khusus tentang throughput.
Jika Anda memiliki jenis kebutuhan khusus yang sama dengan yang dilakukan LMAX - khususnya, keadaan bersama yang sesuai dengan kenyataan bisnis yang bertentangan dengan pilihan desain tergesa-gesa - maka saya akan menyarankan untuk mencoba komponen mereka, karena saya belum melihat banyak lain yang sesuai dengan persyaratan tersebut. Tetapi jika kita hanya berbicara tentang skalabilitas tinggi maka saya mendorong Anda untuk melakukan lebih banyak penelitian ke dalam sistem terdistribusi, karena mereka adalah pendekatan kanonik yang digunakan oleh sebagian besar organisasi saat ini (Hadoop dan proyek terkait, ESB dan arsitektur terkait, CQRS yang juga Fowler juga menyebutkan, dan sebagainya).
SSD juga akan menjadi game-changer; bisa dibilang, mereka sudah ada. Anda sekarang dapat memiliki penyimpanan permanen dengan waktu akses yang mirip dengan RAM, dan meskipun SSD tingkat server masih sangat mahal, mereka akhirnya akan turun harga begitu tingkat adopsi tumbuh. Ini telah diteliti secara luas dan hasilnya cukup membingungkan dan hanya akan menjadi lebih baik dari waktu ke waktu, sehingga keseluruhan konsep "simpan semuanya dalam ingatan" jauh lebih penting daripada dulu. Jadi sekali lagi, saya akan mencoba untuk fokus pada konkurensi jika memungkinkan.
sumber
Saya pikir pelajaran terbesar untuk dipelajari dari ini adalah Anda harus mulai dengan dasar-dasarnya:
Selama pengujian kinerja, Anda membuat profil kode Anda, menemukan kemacetan, dan memperbaikinya satu per satu.
Terlalu banyak orang yang melompat langsung ke bagian "perbaiki satu per satu". Mereka menghabiskan banyak waktu menulis "implementasi kustom dari koleksi java", karena mereka hanya tahu bahwa seluruh alasan sistem mereka lambat adalah karena kesalahan cache. Itu mungkin faktor yang berkontribusi, tetapi jika Anda langsung mengubah kode tingkat rendah seperti itu, Anda mungkin akan kehilangan masalah lebih besar menggunakan ArrayList ketika Anda harus menggunakan LinkedList, atau bahwa alasan sebenarnya sistem Anda adalah lambat karena ORM Anda memuat anak-anak dari suatu entitas dengan malas dan karenanya melakukan 400 perjalanan terpisah ke database untuk setiap permintaan.
sumber
Secara khusus tidak akan mengomentari kode LMAX karena saya pikir itu cukup banyak dijelaskan, tetapi di sini ada beberapa contoh hal yang telah saya lakukan yang menghasilkan peningkatan kinerja yang terukur.
Seperti biasa, ini adalah teknik yang harus diterapkan setelah Anda tahu bahwa Anda memiliki masalah dan perlu meningkatkan kinerja - jika tidak, Anda mungkin hanya akan melakukan optimasi prematur.
Bantu kompiler JIT dengan bidang pembuatan akhir , metode dan kelas - kelas final memungkinkan optimisasi spesifik yang benar - benar membantu kompiler JIT. Contoh spesifik:
Ganti kelas koleksi dengan array - ini menghasilkan kode yang kurang dapat dibaca dan lebih sulit untuk dipertahankan tetapi hampir selalu lebih cepat karena menghapus lapisan tipuan dan manfaat dari banyak optimisasi akses array yang bagus. Biasanya ide yang baik dalam inner loop / kode sensitif kinerja setelah Anda mengidentifikasinya sebagai hambatan, tetapi hindari sebaliknya demi keterbacaan!
Gunakan primitif sedapat mungkin - primitif secara fundamental lebih cepat daripada persamaan berbasis objeknya. Secara khusus, tinju menambahkan sejumlah besar overhead dan dapat menyebabkan jeda GC buruk. Jangan biarkan primitif apa pun dikotak jika Anda peduli dengan kinerja / latensi.
Minimalkan penguncian tingkat rendah - kunci sangat mahal pada tingkat rendah. Temukan cara untuk menghindari penguncian sepenuhnya, atau mengunci pada tingkat kasar sehingga Anda hanya perlu mengunci jarang pada blok data yang besar dan kode tingkat rendah dapat melanjutkan tanpa harus khawatir sama sekali tentang masalah penguncian atau masalah konkurensi.
sumber
final
beberapa JIT mungkin mengetahuinya, yang lain mungkin tidak. Ini tergantung implementasi (seperti juga banyak tips penyesuaian kinerja). Setuju tentang alokasi - Anda harus membandingkan ini. Biasanya saya menemukan lebih baik untuk menghilangkan alokasi, tetapi YMMV.Selain sudah dinyatakan dalam jawaban yang bagus dari Aaronaught, saya ingin mencatat bahwa kode seperti itu mungkin cukup sulit untuk dikembangkan, dipahami, dan didebug. "Meskipun sangat efisien ... sangat mudah untuk mengacaukan ..." sebagai salah satu dari mereka yang disebutkan di blog LMAX .
Diberikan di atas, saya pikir mereka yang memilih Disruptor dan pendekatan serupa lebih baik memastikan bahwa mereka memiliki sumber daya pengembangan yang cukup untuk mempertahankan solusi mereka.
Secara keseluruhan, pendekatan Disruptor terlihat cukup menjanjikan bagi saya. Bahkan jika perusahaan Anda tidak mampu menggunakannya misalnya untuk alasan yang disebutkan di atas, pertimbangkan meyakinkan manajemen Anda untuk "menginvestasikan" beberapa upaya untuk mempelajarinya (dan SEDA secara umum) - karena jika mereka tidak melakukannya maka ada peluang bahwa suatu hari nanti pelanggan mereka akan membiarkan mereka mendukung beberapa solusi yang lebih kompetitif yang membutuhkan server 4x, 8x dll.
sumber