Basis data deret waktu (TSDB) di Prometheus 2 adalah contoh luar biasa dari solusi teknik yang menawarkan peningkatan besar dibandingkan penyimpanan v2 di Prometheus 1 dalam hal kecepatan akumulasi data, eksekusi kueri, dan efisiensi sumber daya. Kami menerapkan Prometheus 2 di Percona Monitoring and Management (PMM) dan saya berkesempatan untuk memahami kinerja Prometheus 2 TSDB. Pada artikel kali ini saya akan membahas tentang hasil observasi tersebut.
Beban Kerja Prometheus Rata-rata
Bagi mereka yang terbiasa berurusan dengan database tujuan umum, beban kerja khas Prometheus cukup menarik. Tingkat akumulasi data cenderung stabil: biasanya layanan yang Anda pantau mengirimkan jumlah metrik yang kira-kira sama, dan perubahan infrastruktur relatif lambat.
Permintaan informasi bisa datang dari berbagai sumber. Beberapa di antaranya, seperti peringatan, juga berupaya mencapai nilai yang stabil dan dapat diprediksi. Lainnya, seperti permintaan pengguna, dapat menyebabkan lonjakan, meskipun hal ini tidak terjadi pada sebagian besar beban kerja.
Tes beban
Selama pengujian, saya fokus pada kemampuan mengumpulkan data. Saya menerapkan Prometheus 2.3.2 yang dikompilasi dengan Go 1.10.1 (sebagai bagian dari PMM 1.14) pada layanan Linode menggunakan skrip ini:
Semua pengujian berikut dilakukan pada server Linode dengan delapan inti virtual dan memori 32 GB, menjalankan 20 simulasi beban yang memantau dua ratus instans MySQL. Atau, dalam istilah Prometheus, 800 target, 440 goresan per detik, 380 ribu rekaman per detik, dan 1,7 juta rangkaian waktu aktif.
Disain
Pendekatan yang biasa dilakukan pada database tradisional, termasuk yang digunakan oleh Prometheus 1.x, adalah dengan storage.tsdb.min-block-duration
, yang menentukan berapa lama rekaman akan disimpan di memori sebelum di-flush ke disk (defaultnya adalah 2 jam). Jumlah memori yang dibutuhkan akan bergantung pada jumlah deret waktu, label, dan scrap yang ditambahkan ke aliran masuk bersih. Dalam hal ruang disk, Prometheus bertujuan untuk menggunakan 3 byte per record (sampel). Di sisi lain, kebutuhan memori jauh lebih tinggi.
Meskipun dimungkinkan untuk mengonfigurasi ukuran blok, tidak disarankan untuk mengonfigurasinya secara manual, sehingga Anda terpaksa memberikan Prometheus memori sebanyak yang diperlukan untuk beban kerja Anda.
Jika tidak ada cukup memori untuk mendukung aliran metrik yang masuk, Prometheus akan kehabisan memori atau pembunuh OOM akan mengaksesnya.
Menambahkan swap untuk menunda kerusakan saat Prometheus kehabisan memori tidak terlalu membantu, karena menggunakan fungsi ini menyebabkan konsumsi memori yang sangat besar. Saya pikir ini ada hubungannya dengan Go, pengumpul sampahnya dan cara menangani swap.
Pendekatan menarik lainnya adalah mengkonfigurasi blok head untuk dipindahkan ke disk pada waktu tertentu, alih-alih menghitungnya dari awal proses.
Seperti yang Anda lihat dari grafik, pengosongan ke disk terjadi setiap dua jam. Jika Anda mengubah parameter durasi blok-min menjadi satu jam, maka penyetelan ulang ini akan terjadi setiap jam, dimulai setelah setengah jam.
Jika Anda ingin menggunakan grafik ini dan grafik lainnya dalam instalasi Prometheus, Anda dapat menggunakan ini
Kami memiliki blok aktif yang disebut blok kepala yang disimpan dalam memori; blok dengan data lama tersedia melalui mmap()
. Hal ini menghilangkan kebutuhan untuk mengonfigurasi cache secara terpisah, namun juga berarti Anda perlu menyisakan ruang yang cukup untuk cache sistem operasi jika Anda ingin menanyakan data yang lebih lama dari yang dapat ditampung oleh blok head.
Ini juga berarti konsumsi memori virtual Prometheus akan terlihat cukup tinggi, dan hal ini tidak perlu dikhawatirkan.
Poin desain menarik lainnya adalah penggunaan WAL (write forward log). Seperti yang Anda lihat dari dokumentasi penyimpanan, Prometheus menggunakan WAL untuk menghindari kerusakan. Sayangnya, mekanisme khusus untuk menjamin kelangsungan data tidak terdokumentasi dengan baik. Prometheus versi 2.3.2 mem-flush WAL ke disk setiap 10 detik dan opsi ini tidak dapat dikonfigurasi pengguna.
Pemadatan
Prometheus TSDB dirancang seperti penyimpanan LSM (Log Structured Merge): blok kepala dipindahkan secara berkala ke disk, sementara mekanisme pemadatan menggabungkan beberapa blok untuk menghindari pemindaian terlalu banyak blok selama kueri. Di sini Anda dapat melihat jumlah blok yang saya amati pada sistem pengujian setelah seharian memuat.
Jika Anda ingin mempelajari lebih lanjut tentang penyimpanan tersebut, Anda dapat memeriksa file meta.json, yang berisi informasi tentang blok yang tersedia dan bagaimana blok tersebut terbentuk.
{
"ulid": "01CPZDPD1D9R019JS87TPV5MPE",
"minTime": 1536472800000,
"maxTime": 1536494400000,
"stats": {
"numSamples": 8292128378,
"numSeries": 1673622,
"numChunks": 69528220
},
"compaction": {
"level": 2,
"sources": [
"01CPYRY9MS465Y5ETM3SXFBV7X",
"01CPYZT0WRJ1JB1P0DP80VY5KJ",
"01CPZ6NR4Q3PDP3E57HEH760XS"
],
"parents": [
{
"ulid": "01CPYRY9MS465Y5ETM3SXFBV7X",
"minTime": 1536472800000,
"maxTime": 1536480000000
},
{
"ulid": "01CPYZT0WRJ1JB1P0DP80VY5KJ",
"minTime": 1536480000000,
"maxTime": 1536487200000
},
{
"ulid": "01CPZ6NR4Q3PDP3E57HEH760XS",
"minTime": 1536487200000,
"maxTime": 1536494400000
}
]
},
"version": 1
}
Pemadatan di Prometheus terikat pada waktu blok kepala dipindahkan ke disk. Pada titik ini, beberapa operasi serupa dapat dilakukan.
Tampaknya pemadatan tidak dibatasi dengan cara apa pun dan dapat menyebabkan lonjakan I/O disk yang besar selama eksekusi.
Lonjakan beban CPU
Tentu saja, hal ini memiliki dampak yang agak negatif pada kecepatan sistem, dan juga menimbulkan tantangan serius bagi penyimpanan LSM: bagaimana melakukan pemadatan untuk mendukung tingkat permintaan yang tinggi tanpa menyebabkan terlalu banyak overhead?
Penggunaan memori pada proses pemadatan juga terlihat cukup menarik.
Kita dapat melihat bagaimana, setelah pemadatan, sebagian besar memori berubah status dari Cached menjadi Free: ini berarti informasi yang berpotensi berharga telah dihapus dari sana. Penasaran apakah itu digunakan di sini fadvice()
atau teknik minimalisasi lainnya, atau karena cache telah dibebaskan dari blok yang dihancurkan selama pemadatan?
Pemulihan setelah kegagalan
Pemulihan dari kegagalan membutuhkan waktu, dan untuk alasan yang bagus. Untuk aliran masuk sejuta rekaman per detik, saya harus menunggu sekitar 25 menit hingga pemulihan dilakukan dengan mempertimbangkan drive SSD.
level=info ts=2018-09-13T13:38:14.09650965Z caller=main.go:222 msg="Starting Prometheus" version="(version=2.3.2, branch=v2.3.2, revision=71af5e29e815795e9dd14742ee7725682fa14b7b)"
level=info ts=2018-09-13T13:38:14.096599879Z caller=main.go:223 build_context="(go=go1.10.1, user=Jenkins, date=20180725-08:58:13OURCE)"
level=info ts=2018-09-13T13:38:14.096624109Z caller=main.go:224 host_details="(Linux 4.15.0-32-generic #35-Ubuntu SMP Fri Aug 10 17:58:07 UTC 2018 x86_64 1bee9e9b78cf (none))"
level=info ts=2018-09-13T13:38:14.096641396Z caller=main.go:225 fd_limits="(soft=1048576, hard=1048576)"
level=info ts=2018-09-13T13:38:14.097715256Z caller=web.go:415 component=web msg="Start listening for connections" address=:9090
level=info ts=2018-09-13T13:38:14.097400393Z caller=main.go:533 msg="Starting TSDB ..."
level=info ts=2018-09-13T13:38:14.098718401Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536530400000 maxt=1536537600000 ulid=01CQ0FW3ME8Q5W2AN5F9CB7R0R
level=info ts=2018-09-13T13:38:14.100315658Z caller=web.go:467 component=web msg="router prefix" prefix=/prometheus
level=info ts=2018-09-13T13:38:14.101793727Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536732000000 maxt=1536753600000 ulid=01CQ78486TNX5QZTBF049PQHSM
level=info ts=2018-09-13T13:38:14.102267346Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536537600000 maxt=1536732000000 ulid=01CQ78DE7HSQK0C0F5AZ46YGF0
level=info ts=2018-09-13T13:38:14.102660295Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536775200000 maxt=1536782400000 ulid=01CQ7SAT4RM21Y0PT5GNSS146Q
level=info ts=2018-09-13T13:38:14.103075885Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536753600000 maxt=1536775200000 ulid=01CQ7SV8WJ3C2W5S3RTAHC2GHB
level=error ts=2018-09-13T14:05:18.208469169Z caller=wal.go:275 component=tsdb msg="WAL corruption detected; truncating" err="unexpected CRC32 checksum d0465484, want 0" file=/opt/prometheus/data/.prom2-data/wal/007357 pos=15504363
level=info ts=2018-09-13T14:05:19.471459777Z caller=main.go:543 msg="TSDB started"
level=info ts=2018-09-13T14:05:19.471604598Z caller=main.go:603 msg="Loading configuration file" filename=/etc/prometheus.yml
level=info ts=2018-09-13T14:05:19.499156711Z caller=main.go:629 msg="Completed loading of configuration file" filename=/etc/prometheus.yml
level=info ts=2018-09-13T14:05:19.499228186Z caller=main.go:502 msg="Server is ready to receive web requests."
Masalah utama dari proses pemulihan adalah konsumsi memori yang tinggi. Meskipun dalam situasi normal server dapat bekerja secara stabil dengan jumlah memori yang sama, jika crash, server mungkin tidak dapat pulih karena OOM. Satu-satunya solusi yang saya temukan adalah menonaktifkan pengumpulan data, membuka server, membiarkannya pulih, dan melakukan boot ulang dengan pengumpulan diaktifkan.
Pemanasan
Perilaku lain yang perlu diingat selama pemanasan adalah hubungan antara kinerja rendah dan konsumsi sumber daya yang tinggi segera setelah permulaan. Selama beberapa, tetapi tidak semua permulaan, saya mengamati beban serius pada CPU dan memori.
Kesenjangan dalam penggunaan memori menunjukkan bahwa Prometheus tidak dapat mengonfigurasi semua koleksi dari awal, dan beberapa informasi hilang.
Saya belum menemukan alasan pasti atas tingginya beban CPU dan memori. Saya menduga hal ini disebabkan oleh pembuatan deret waktu baru di head block dengan frekuensi tinggi.
Beban CPU melonjak
Selain pemadatan, yang menghasilkan beban I/O yang cukup tinggi, saya melihat lonjakan serius pada beban CPU setiap dua menit. Semburan tersebut lebih lama ketika aliran input tinggi dan tampaknya disebabkan oleh pengumpul sampah Go, dengan setidaknya beberapa inti terisi penuh.
Lompatan ini tidak terlalu signifikan. Tampaknya ketika hal ini terjadi, titik masuk dan metrik internal Prometheus menjadi tidak tersedia, sehingga menyebabkan kesenjangan data selama periode waktu yang sama.
Anda juga dapat melihat bahwa eksportir Prometheus mati selama satu detik.
Kita dapat melihat korelasinya dengan pengumpulan sampah (GC).
Kesimpulan
TSDB di Prometheus 2 cepat, mampu menangani jutaan rangkaian waktu dan pada saat yang sama ribuan catatan per detik menggunakan perangkat keras yang cukup sederhana. Pemanfaatan CPU dan I/O disk juga mengesankan. Contoh saya menunjukkan hingga 200 metrik per detik per inti yang digunakan.
Untuk merencanakan perluasan, Anda perlu mengingat jumlah memori yang cukup, dan ini harus berupa memori nyata. Jumlah memori yang digunakan yang saya amati adalah sekitar 5 GB per 100 catatan per detik aliran masuk, yang bersama dengan cache sistem operasi memberikan sekitar 000 GB memori yang terisi.
Tentu saja, masih banyak pekerjaan yang harus dilakukan untuk menjinakkan lonjakan CPU dan I/O disk, dan hal ini tidak mengherankan mengingat betapa mudanya TSDB Prometheus 2 dibandingkan dengan InnoDB, TokuDB, RocksDB, WiredTiger, namun semuanya memiliki kesamaan. masalah di awal siklus hidupnya.
Sumber: www.habr.com