Bagaimana jika kueri basis data Anda tidak berjalan cukup cepat? Bagaimana Anda tahu jika kueri menggunakan sumber daya komputasi secara optimal atau dapat dipercepat? Pada konferensi HighLoad ++ terakhir di Moskow, saya berbicara tentang introspeksi kinerja kueri - dan apa yang disediakan DBMS ClickHouse, dan tentang fitur OS yang harus diketahui semua orang.

Setiap kali saya membuat permintaan, saya prihatin tidak hanya dengan hasilnya, tetapi juga dengan apa yang dilakukan permintaan ini. Misalnya, ini berfungsi selama satu detik. Apakah banyak atau sedikit? Saya selalu berpikir: mengapa tidak setengah detik? Lalu saya mengoptimalkan sesuatu, mempercepatnya, dan itu berfungsi selama 10 ms. Saya biasanya puas. Tapi tetap saja, dalam hal ini saya mencoba untuk membuat ekspresi wajah tidak senang dan bertanya: "Mengapa tidak 5 ms?" Bagaimana saya bisa mengetahui berapa waktu yang dihabiskan untuk memproses permintaan? Bisakah prinsipnya dipercepat?
Biasanya, kecepatan pemrosesan permintaan adalah aritmatika sederhana. Kami menulis kode - mungkin secara optimal - dan kami memiliki beberapa perangkat dalam sistem. Perangkat memiliki spesifikasi. Misalnya, kecepatan baca dari cache L1. Atau jumlah pembacaan acak yang dapat dilakukan SSD. Kita semua tahu itu. Kita perlu mengambil karakteristik ini, menambah, mengurangi, mengalikan, membagi, dan memeriksa jawabannya. Tapi ini dalam kasus yang ideal, ini hampir tidak pernah terjadi. Hampir. Bahkan, ini kadang terjadi di ClickHouse.
Mari kita pertimbangkan fakta-fakta sepele tentang perangkat apa dan sumber daya apa di server kami.

Prosesor, memori, disk, jaringan. Saya secara khusus mengatur sumber daya ini sedemikian rupa, mulai dari yang paling sederhana dan paling nyaman untuk ditinjau dan dioptimalkan, dan diakhiri dengan yang paling tidak nyaman dan kompleks. Sebagai contoh, saya menjalankan permintaan dan melihat bahwa program saya tampaknya bersandar pada CPU. Apa artinya ini? Apa yang akan saya temukan ada semacam loop dalam, fungsi yang paling sering dieksekusi, menulis ulang kode, mengkompilasi ulang, dan sekali - program saya berjalan lebih cepat.
Jika Anda menghabiskan terlalu banyak RAM, maka semuanya menjadi sedikit lebih rumit. Anda perlu memikirkan kembali struktur data, memeras beberapa bit. Bagaimanapun, saya me-restart program saya, dan itu menghabiskan lebih sedikit RAM. Benar, ini sering merugikan prosesor.
Jika semuanya tergantung pada disk, maka ini juga lebih sulit, karena saya dapat mengubah struktur data pada disk, tetapi saya harus mengonversi data ini nanti. Jika saya membuat rilis baru, orang harus melakukan semacam migrasi data. Ternyata disk sudah jauh lebih rumit, dan lebih baik untuk dipikirkan terlebih dahulu.
Dan jaringannya ... Saya benar-benar tidak suka jaringan itu, karena seringkali sama sekali tidak jelas apa yang terjadi di dalamnya, terutama jika itu adalah jaringan antar benua, antar pusat data. Ada sesuatu yang melambat di sana, dan itu bahkan bukan jaringan Anda, bukan server Anda, dan Anda tidak dapat melakukan apa pun. Satu-satunya hal yang dapat Anda pikirkan adalah bagaimana data akan dikirimkan dan bagaimana meminimalkan interaksi melalui jaringan.
Itu terjadi bahwa tidak ada sumber daya tunggal dalam sistem digunakan, dan program hanya menunggu sesuatu. Faktanya, ini adalah kasus yang sangat umum, karena sistem kami terdistribusi, dan mungkin ada banyak proses dan aliran yang berbeda, dan seseorang menunggu yang lain, dan semua ini perlu terhubung satu sama lain untuk mempertimbangkannya dengan baik.

Hal yang paling sederhana adalah melihat pemanfaatan sumber daya, pada beberapa nilai numerik. Misalnya, Anda memulai beberapa top, dan dia menulis: prosesor 100%. Atau jalankan iostat, dan dia menulis: disk 100%. Benar, ini sering tidak cukup. Satu orang akan melihat bahwa program bersandar pada disk. Apa yang bisa dilakukan? Anda dapat dengan mudah mencatat ini dan pergi untuk beristirahat, memutuskan bahwa semuanya, tidak ada yang dapat dioptimalkan. Namun pada kenyataannya, masing-masing perangkat di dalamnya sendiri cukup rumit. Prosesor memiliki banyak perangkat komputasi untuk berbagai jenis operasi. Disk mungkin memiliki array RAID. Jika ada SSD, maka ada di dalam prosesornya sendiri, pengontrolnya sendiri, yang membuatnya tidak jelas apa. Dan satu nilai - 50% atau 100% - tidak cukup. Aturan dasar: jika Anda melihat bahwa beberapa sumber daya digunakan 100%, jangan menyerah. Seringkali, Anda masih bisa meningkatkan sesuatu. Tetapi itu terjadi dan sebaliknya. Katakan Anda melihat bahwa daur ulang adalah 50%, tetapi tidak ada yang bisa dilakukan.
Mari kita lihat lebih dekat.

Sumber daya termudah dan paling nyaman adalah prosesor. Anda lihat di bagian atas, dikatakan bahwa prosesornya 100%. Tetapi harus diingat bahwa ini bukan prosesor 100%. Program teratas tidak tahu apa yang dilakukan prosesor di sana. Dia terlihat dari perspektif perencana OS. Yaitu, sekarang semacam program thread berjalan pada prosesor. Prosesor melakukan sesuatu, dan kemudian 100% akan ditampilkan jika rata-rata dari waktu ke waktu. Pada saat yang sama, prosesor melakukan sesuatu, dan tidak jelas seberapa efektif itu. Itu dapat menjalankan sejumlah instruksi berbeda per siklus. Jika ada beberapa instruksi, prosesor itu sendiri dapat menunggu sesuatu, misalnya, memuat data dari memori. Pada saat yang sama, hal yang sama akan ditampilkan di atas - 100%. Kami menunggu prosesor untuk mengikuti instruksi kami. Dan apa yang dia lakukan di dalam tidak jelas.
Akhirnya, hanya ada menyapu ketika Anda berpikir bahwa program Anda bersandar pada prosesor. Ini benar, tetapi untuk beberapa alasan prosesor memiliki frekuensi yang lebih rendah. Mungkin ada banyak alasan: terlalu panas, keterbatasan daya. Untuk beberapa alasan, di pusat data ada batasan daya, atau penghematan energi bisa dihidupkan. Kemudian prosesor akan secara konstan beralih dari frekuensi yang lebih tinggi ke frekuensi yang lebih rendah, tetapi jika beban Anda tidak stabil, maka ini tidak akan cukup dan rata-rata kode akan dieksekusi lebih lambat. Lihat turbostat untuk frekuensi prosesor saat ini. Periksa panas berlebih di dmesg. Jika sesuatu seperti itu terjadi, itu akan berkata: "Terlalu panas. Frekuensi turun. "
Jika Anda tertarik pada berapa banyak cache yang ada di dalam, berapa banyak instruksi yang dieksekusi per siklus, gunakan catatan perf. Catat beberapa sampel program. Lebih lanjut akan mungkin untuk melihatnya menggunakan stat atau laporan perf.

Begitu juga sebaliknya. Katakanlah Anda melihat ke atas dan prosesornya kurang dari 50% didaur ulang. Misalkan Anda memiliki 32 core prosesor virtual di sistem Anda dan 16 core fisik. Pada prosesor Intel, ini karena hyper-threading ganda. Tetapi ini tidak berarti bahwa core tambahan tidak berguna. Itu semua tergantung pada beban. Misalkan Anda memiliki beberapa operasi aljabar linier yang dioptimalkan dengan baik atau Anda memiliki hash untuk menambang bitcoin. Kemudian kodenya akan jelas, banyak instruksi akan dieksekusi per siklus, tidak akan ada cache yang salah, salah duga cabang, juga. Dan hyper-threading tidak membantu. Ini membantu ketika Anda memiliki satu inti menunggu sesuatu, sementara yang lain secara bersamaan dapat menjalankan instruksi dari utas lainnya.
ClickHouse memiliki kedua situasi. Misalnya, ketika kita melakukan agregasi data (GROUP BY) atau memfilter dengan set (IN subquery), kita akan memiliki tabel hash. Jika tabel hash tidak cocok dengan cache prosesor, cache misses akan terjadi. Ini hampir tidak bisa dihindari. Dalam hal ini, hyper-threading akan membantu kami.
Secara default, ClickHouse hanya menggunakan core prosesor fisik, tidak termasuk hyper-threading. Jika Anda tahu bahwa permintaan Anda dapat memanfaatkan hyper-threading, cukup gandakan jumlah utas: SET utas utas = 32, dan permintaan Anda akan lebih cepat.
Kebetulan prosesor tersebut digunakan dengan sempurna, tetapi Anda melihat grafik dan melihat, misalnya, 10%. Dan jadwal Anda, misalnya, adalah lima menit dalam kasus terburuk. Bahkan jika itu hanya satu detik, masih ada semacam nilai rata-rata. Bahkan, Anda terus-menerus memiliki permintaan, mereka dieksekusi dengan cepat, dalam 100 ms setiap detik, dan ini normal. Karena ClickHouse mencoba untuk mengeksekusi permintaan secepat mungkin. Dia sama sekali tidak mencoba untuk sepenuhnya dan terus-menerus menggunakan dan memanaskan prosesor Anda.

Mari kita lihat lebih dekat, opsi yang agak rumit. Ada kueri dengan ekspresi dalam subquery. Di dalam subquery, kami memiliki 100 juta angka acak. Dan kami hanya memfilter hasil ini.
Kami melihat gambar seperti itu. Ngomong-ngomong, siapa yang akan mengatakan dengan alat apa saya bisa melihat gambar yang indah ini? Benar sekali - perf. Saya sangat senang Anda mengetahui hal ini.
Saya membuka perf, berpikir bahwa sekarang saya mengerti segalanya. Saya membuka daftar assembler. Di sana saya menulis seberapa sering pelaksanaan program pada instruksi tertentu, yaitu, seberapa sering ada instruksi pointer. Di sini angkanya dalam persen, dan ada tertulis bahwa hampir 90% dari waktu tes% edx,% instruksi edx dieksekusi, yaitu, memeriksa empat byte untuk nol.
Pertanyaannya adalah: mengapa prosesor membutuhkan waktu begitu lama untuk hanya membandingkan empat byte dengan nol? (jawaban dari hadirin ...) Tidak ada sisa dari divisi ini. Ada sedikit pergeseran, lalu ada instruksi crc32q, tetapi seolah-olah pointer instruksi tidak pernah terjadi di sana. Dan generasi nomor acak tidak ada dalam daftar ini. Ada fungsi yang terpisah, dan itu dioptimalkan dengan sangat baik, tidak melambat. Sesuatu yang lain melambat di sini. Eksekusi kode berhenti pada instruksi ini dan menghabiskan banyak waktu. Loop kosong? Tidak. Mengapa saya harus memasukkan loop kosong? Juga, jika saya memasukkan loop menganggur, itu juga akan terlihat di perf. Tidak ada pembagian dengan nol, hanya ada perbandingan dengan nol.
Prosesor memiliki pipa, dapat menjalankan beberapa instruksi secara paralel. Dan ketika pointer instruksi ada di suatu tempat, ini tidak berarti sama sekali bahwa itu mengeksekusi instruksi ini. Mungkin dia menunggu instruksi lain.
Kami memiliki tabel hash untuk memverifikasi bahwa beberapa nomor terjadi dalam beberapa set. Untuk ini, kami melakukan pencarian di memori. Ketika kami melakukan pencarian di memori, kami memiliki cache miss, karena tabel hash berisi 100 juta angka, itu tidak dijamin untuk masuk ke cache apa pun. Jadi, untuk menjalankan instruksi pemeriksaan nol, data ini harus sudah dimuat dari memori. Dan kami menunggu sampai semuanya dimuat.

Sekarang sumber daya berikutnya, sedikit lebih kompleks - drive. SSD juga kadang-kadang disebut drive, meskipun ini tidak sepenuhnya benar. SSD juga akan disertakan dalam contoh ini.
Kami membuka, misalnya, iostat, itu menunjukkan pemanfaatan 100%.
Di konferensi, sering terjadi bahwa pembicara naik ke atas panggung dan berkata dengan pathos: βDatabases selalu berbatasan dengan disk. Oleh karena itu, kami membuat basis data dalam memori. Dia tidak akan melambat. " Jika seseorang mendekati Anda dan mengatakannya, Anda dapat mengirimnya dengan aman. Akan ada beberapa masalah - Anda berkata, saya menyelesaikannya. :)
Misalkan sebuah program bertumpu pada disk, utilisasi adalah 100. Tapi ini, tentu saja, tidak berarti bahwa kita menggunakan disk secara optimal.
Contoh tipikal adalah ketika Anda hanya memiliki banyak akses acak. Sekalipun aksesnya berurutan, maka Anda cukup membaca file secara berurutan, tetapi masih bisa lebih atau kurang optimal.
Misalnya, Anda memiliki array RAID, beberapa perangkat - katakanlah, 8 disk. Dan Anda baru saja membaca secara berurutan tanpa membaca sebelumnya, dengan ukuran buffer 1 MB, dan ukuran chunk di strip Anda di RAID juga 1 MB. Maka setiap bacaan Anda akan miliki dari satu perangkat. Atau, jika tidak sejajar, dari dua perangkat. Setengah megabyte akan pergi ke suatu tempat, setengah lagi megabyte di suatu tempat, dan seterusnya - disk akan digunakan secara bergantian: satu, lalu yang lain, lalu yang ketiga.
Itu perlu dibaca dulu. Atau, jika Anda memiliki O_DIRECT, tambah ukuran buffer. Artinya, aturannya adalah: 8 disk, ukuran chunk 1 MB, atur ukuran buffer hingga minimal 8 MB. Tetapi ini hanya akan bekerja secara optimal jika bacaan selaras. Dan jika tidak selaras, maka pertama-tama akan ada potongan tambahan, dan Anda perlu menambahkan lebih banyak, kalikan dengan beberapa lagi.
Atau, misalnya, Anda memiliki RAID 10. Dengan kecepatan apa Anda dapat membaca dari RAID 10 - misalnya, dari 8 disk? Apa keuntungannya? Empat kali lipat, karena ada cermin, atau delapan kali lipat? Sebenarnya, itu tergantung pada bagaimana RAID dibuat, dengan pengaturan potongan apa dalam garis-garis.
Jika Anda menggunakan mdadm di Linux, Anda dapat menentukan tata letak dekat dan tata letak jauh di sana, dengan hampir lebih baik untuk menulis, jauh untuk membaca.
Saya selalu merekomendasikan menggunakan tata letak jauh, karena ketika Anda menulis ke database analitik, biasanya tidak begitu kritis dalam waktu - bahkan jika ada lebih banyak menulis daripada membaca. Ini dilakukan oleh beberapa proses latar belakang. Tetapi ketika Anda membaca, Anda harus menyelesaikannya secepat mungkin. Jadi lebih baik untuk mengoptimalkan RAID untuk membaca dengan mengatur tata letak yang jauh.
Seperti keberuntungan, di Linux mdadm akan mengatur Anda ke tata letak dekat secara default, dan Anda akan mendapatkan hanya setengah kinerja. Ada banyak garu seperti itu.
Rake mengerikan lainnya adalah RAID 5 atau RAID 6. Semuanya berskala baik di sana dengan membaca dan menulis berurutan. Dalam RAID 5, multiplisitasnya adalah "jumlah perangkat minus satu." Ini berskala baik bahkan dengan pembacaan acak, tetapi tidak skala baik dengan pembacaan acak. Buat catatan di sembarang tempat, dan Anda perlu membaca data dari semua disk lain, minta mereka (XOR - kira-kira. Ed.) Dan tulis ke tempat lain. Untuk ini, cache strip tertentu digunakan, menyapu mengerikan. Di Linux, secara default Anda membuat RAID 5 dan itu akan melambat untuk Anda. Dan Anda akan berpikir bahwa RAID 5 selalu melambat, karena ini bisa dimengerti. Namun faktanya, alasannya adalah pengaturan yang salah.
Contoh lain. Anda membaca dari SSD, dan membeli sendiri SSD yang bagus, katanya 300 ribu bacaan acak per detik dalam spesifikasi. Dan untuk beberapa alasan Anda tidak dapat melakukannya. Dan Anda berpikir - ya mereka semua terletak pada spesifikasinya, tidak ada hal seperti itu. Tetapi semua pembacaan ini harus dilakukan secara paralel, dengan tingkat paralelisme maksimum. Satu-satunya cara untuk melakukan ini dengan cukup optimal adalah dengan menggunakan asinkron I / O, yang diimplementasikan menggunakan panggilan sistem io_submit, io_getevents, io_setup, dll.
By the way, data pada disk, jika Anda menyimpannya, Anda selalu perlu mengompres. Saya akan memberikan contoh dari latihan. Satu orang menghubungi kami di obrolan
dukungan ClickHouse dan berkata:
- ClickHouse memampatkan data. Saya melihatnya terletak pada prosesor. Saya memiliki SSD NVMe yang sangat cepat, mereka memiliki kecepatan baca beberapa gigabytes per detik. Apakah mungkin untuk menonaktifkan kompresi di ClickHouse?
"Tidak, tidak mungkin," kataku. - Anda harus menyimpan data terkompresi.
- Mari kita hentikan, hanya akan ada algoritma kompresi lain yang tidak melakukan apa-apa.
- Mudah. Masukkan huruf-huruf ini di baris kode ini.
"Memang, semuanya sangat sederhana," jawabnya sehari kemudian. - Ya.
- Seberapa banyak kinerja berubah?
"Gagal menguji," tulisnya satu hari kemudian. - Terlalu banyak data. Mereka tidak lagi muat di SSD.
Sekarang mari kita lihat seperti apa bacaan dari disk. Kami mulai dstat, ini menunjukkan kecepatan baca.
Contoh pertama dari dstat dan iostat Ini kolom baca - 300 MB / s. Kami membaca dari disk. Ini banyak atau sedikit - saya tidak tahu.
Sekarang saya menjalankan iostat untuk memeriksa ini. Di sini Anda dapat melihat rincian berdasarkan perangkat. Saya memiliki RAID, md2, dan delapan hard drive. Masing-masing dari mereka menunjukkan daur ulang, bahkan tidak mencapai 100% (50-60%). Tetapi yang paling penting adalah bahwa saya membaca dari setiap disk hanya dengan kecepatan 20-30 MB / s. Dan sejak kecil saya ingat aturan bahwa Anda dapat membaca di suatu tempat dari 100 MB / s dari hard drive. Untuk beberapa alasan, ini masih belum banyak berubah.
Contoh kedua dari dstat dan iostat Ini adalah contoh lain. Membaca lebih optimal. Saya menjalankan dstat, dan saya memiliki kecepatan baca 1 GB / s dari RAID 5 dari delapan drive ini. Apa yang ditunjukkan iostat? Ya, hampir 1 GB / s.
Sekarang drive akhirnya dimuat 100%. Benar, karena alasan tertentu, dua adalah 100%, dan sisanya adalah 95%. Mungkin, mereka masih sedikit berbeda. Tetapi dengan masing-masing dari mereka saya membaca 150 MB / s, bahkan lebih keren dari itu. Apa bedanya? Dalam kasus pertama, saya membaca dengan ukuran buffer tidak mencukupi dalam potongan tidak cukup. Sederhana saja, saya katakan kebenaran umum.
Omong-omong, jika Anda berpikir bahwa data masih tidak perlu dikompres untuk database analitis, yaitu, laporan dari konferensi HighLoad ++ Siberia (
kebiasaan berdasarkan laporan -
kira -
kira .). Panitia memutuskan untuk membuat laporan paling hardcore di Novosibirsk.

Contoh selanjutnya adalah memori. Melanjutkan kebenaran umum. Pertama, di Linux, tidak pernah melihat pertunjukan gratis apa. Bagi yang menonton, mereka secara khusus membuat situs linuxatemyram.com. Masuklah, akan ada penjelasan. Anda tidak perlu melihat jumlah memori virtual juga, karena apa bedanya, berapa banyak ruang alamat yang dialokasikan oleh program? Lihatlah berapa banyak memori fisik yang digunakan.
Dan satu lagi menyapu dengan yang bahkan tidak jelas bagaimana bertarung. Ingat: fakta bahwa pengalokasi sering tidak suka memberikan memori ke sistem adalah normal. Mereka membuat mmap, tetapi munmap tidak lagi melakukannya. Memori tidak akan kembali ke sistem. Program ini berpikir - Saya tahu lebih baik bagaimana saya akan menggunakan memori. Saya akan menyerahkannya sendiri. Karena panggilan sistem mmap dan munmap cukup lambat. Mengubah ruang alamat, mengatur ulang cache TLB prosesor - lebih baik tidak melakukan ini. Namun, OS masih memiliki kemampuan untuk membebaskan memori dengan benar menggunakan panggilan sistem madvise. Ruang alamat akan tetap ada, tetapi secara fisik memori dapat dibongkar.
Dan tidak pernah mengaktifkan swap pada server produksi dengan database. Anda berpikir - tidak ada cukup memori, saya akan memasukkan swap. Setelah itu, permintaan akan berhenti bekerja. Ini akan memecahkan waktu tanpa akhir.

Dengan jaringan menyapu terlalu khas. Jika Anda membuat koneksi TCP setiap kali, dibutuhkan beberapa waktu sebelum ukuran jendela yang benar dipilih, karena protokol TCP tidak tahu seberapa cepat akan diperlukan untuk mengirimkan data. Dia beradaptasi dengan ini.
Atau bayangkan - Anda sedang mentransfer file, dan Anda memiliki latensi besar di jaringan Anda dan kehilangan paket yang layak. Maka sama sekali tidak jelas apakah itu benar untuk menggunakan TCP untuk mentransfer file. Saya pikir itu salah, karena TCP menjamin konsistensi. Di sisi lain, Anda dapat mentransfer satu setengah file dan yang lainnya pada saat yang sama. TCP- TCP . , , , TCP . .
100- , . 10 -, , , . . .

? β . , , , 10 . , .

: Β« - Β» β . iotop, , , iops.
, . .
top -, , clickHouse-server - , - . , , Shift+H, . , ClickHouse . ParalInputsProc, . BackgrProcPool β merges . , .
? ClickHouse, , . BackgroundProcessingPool. 15 . 16 1, 1 β . 16? , Linux β , : Β«16 . Β». :)
clickhouse-benchmark. clickhouse-client. , clickhouse-client, . - . .
: clickhouse-benchmark + perf top . clickhouse-benchmark, , , , , . peft top. peft top, . , - -, uniq: UniquesHashSet. . , . , .
, , . β -. , , XOR - . -. - -. , -.
, , crc32q. , , - , - .
, ClickHouse. , , . ClickHouse.

. , β , SHOW PROCESSLIST. . , SELECT * FROM system processes. : , , . ClickHouse top.
ClickHouse ? background-. Background- β merges. , merges , SELECT * FROM system.merges.
, . -. . β ClickHouse. . , , . , . - traf_testing. ? , , . ClickHouse .

. , . , , , , . query_log. β , - , SELECT , - . query_log , . - . β , . : .
, , β merge, inserts, . part_log. , .

query_log clickhouse-benchmark. select , , stdin clickhouse-benchmark.
query_log - , .

, , . . SET send_logs_level = 'trace', , .
, . , 98%. , . Ini sangat sederhana. SET send_logs_level = 'trace', , . - : merging aggregated data, . 1% . , .
, , query_log.
. SELECT * FROM system.query_log . . , , , query_log. . β , , , . .

ClickHouse . β system.events, system.metrics system.asynchronous_metrics. Events β , , . 100 . β 10 . system.metrics β . , 10 , 10 .
system.asynchronous_metrics , . . β . , system.asynchronous_metrics β , - . , .
, . SHOW PROCESSLIST . query_log, .

, . , . , . , , . , Linux, . Linux . , . , . .
, OSReadChars OSReadBytes. ? , , , . , . , , , . , - , .
, . - . , 40 , 6,7 . . , ,
. , , .
, 1,3 , 5 . Mengapa , β page cache. ?
. . , , . . : 3,2 , β 2,5 . , , , . Mengapa -, : read ahead. , β ? -, β 4 , , 512 KB. . , . , - read ahead.

. . , . , , ReadBytes β , . 3 , 3 . , , .
β IOWait. 87 . 7 , IOWait β 87. ? β . . , , 87 . , - .
β CPUWait. , , , . - β , . CPU. CPU. - , . β , , user space. , - . Baiklah
β , Linux. - , . , , .
Dan sekarang hal paling canggih yang kita miliki: query_thread_log. Dengannya, Anda dapat memahami waktu yang terbuang untuk setiap utas eksekusi query.Saya mencari permintaan saya, pilih dengan query_id dan menunjukkan metrik "Jumlah waktu prosesor yang dihabiskan di ruang pengguna". Inilah aliran kami. Untuk pemrosesan paralel permintaan, 16 utas dialokasikan. Masing-masing dari mereka menghabiskan 800 ms. Dan kemudian 16 utas lainnya dialokasikan untuk menggabungkan status fungsi agregat, 0,25 detik dihabiskan untuk masing-masingnya. Sekarang saya bisa mengerti persis apa yang dibutuhkan setiap permintaan.Laporan video di HighLoad ++: