Upload
others
View
8
Download
0
Embed Size (px)
Citation preview
Menginstrumentasi sistem terdistribusi
untuk visibilitas pengoperasian David Yanacek
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian Hak Cipta © 2019 Amazon Web Services, Inc. dan/atau afiliasinya. Hak cipta dilindungi undang-undang.
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
2
Menyelami log terlebih dahulu
Saat saya bergabung dengan Amazon setelah selesai kuliah, salah satu latihan orientasi saya
adalah mempersiapkan server amazon.com untuk berjalan di desktop pengembang saya. Saya
tidak langsung berhasil di percobaan pertama, dan saya tidak tahu di mana kesalahan saya. Rekan
kerja yang sangat membantu menyarankan saya untuk melihat log agar dapat mengetahui apa
yang salah. Untuk melakukannya, ia berkata bahwa saya harus "melakukan cat pada file log". Saya
merasa bahwa mereka sedang berkelakar atau membuat lelucon tentang kucing yang tidak saya
mengerti. Saya hanya menggunakan Linux di kampus untuk mengompilasi, menggunakan kontrol
sumber, dan menggunakan editor teks. Oleh karena itu saya tidak tahu bahwa "cat" sebenarnya
adalah perintah untuk mencetak file ke terminal yang dapat saya umpankan ke program lain
untuk mencari pola.
Rekan kerja saya memberi tahu tentang alat seperti cat, grep, sed, dan awk. Dilengkapi dengan
kumpulan alat baru tersebut, saya menyelami log server web amazon.com pada desktop
pengembang saya. Aplikasi server web telah diintrumentasi untuk mengeluarkan seluruh jenis
informasi yang bermanfaat ke dalam log-nya. Hal ini memungkinkan saya melihat konfigurasi apa
yang mencegah server web memulai, yang menunjukkan tempatmana terjadinya crash, atau yang
mengindikasikan tempat terjadinya kegagalan berbicara ke layanan hilir. Situs web tersusun atas
banyak bagian yang bergerak, dan pada awalnya ini adalah kotak hitam bagi saya. Namun, setelah
menyelami sistem terlebih dahulu, saya mempelajari cara kerja server dan cara berinteraksi
dengan dependensinya hanya dengan melihat output instrumentasi.
Mengapa instrumentasi
Setelah bertahun-tahun saya berpindah dari satu tim ke tim lain di Amazon, saya menemukan
bahwa instrumentasi merupakan lensa yang sangat bermanfaat, yang saya dan karyawan lain di
Amazon lihat untuk mempelajari cara kerja sistem. Namun, instrumentasi bermanfaat tidak hanya
untuk belajar tentang sistem. Ini adalah inti dari budaya pengoperasian di Amazon. Instrumentasi
yang hebat membantu kami melihat pengalaman yang kami berikan kepada pelanggan.
Instrumentasi berfokus pada kinerja pengoperasian di seluruh perusahaan. Dalam layanan yang
berhubungan dengan amazon.com, peningkatan latensi menyebabkan pengalaman belanja yang
buruk sehingga tingkat konversi menurun. Dengan pelanggan yang menggunakan AWS, mereka
bergantung pada ketersediaan tinggi dan latensi rendah dari layanan AWS.
Di Amazon, kami tidak hanya mempertimbangkan latensi rata-rata. Kami jauh lebih berfokus pada
titik luar latensi, seperti persentil ke-99,9 dan ke-9,99. Ini dikarenakan jika ada satu permintaan
lambat dari 1.000 atau 10.000 permintaan, berarti sama dengan pengalaman yang buruk. Kami
menemukan bahwa ketka kami mengurangi latensi persentil tinggi pada sistem, upaya kami
memiliki efek samping berupa pengurangan latensi median. Sebaliknya, kami menemukan bahwa
jika latensi median dikurangi, pengurangan latensi persentil tinggi lebih jarang berkurang.
Alasan lain kami berfokus pada latensi persentil tinggi adalah bahwa latensi tinggi di satu layanan
dapat memiliki efek pengganda di seluruh layanan lain. Amazon dibangun di atas arsitektur yang
berfokus pada layanan. Banyak layanan yang saling berkolaborasi untuk menyelesaikan suatu
tugas, seperti rendering halaman web di amazon.com. Hasilnya, peningkatan di latensi layanan
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
3
jauh di dalam rantai panggilan—bahkan jika peningkatan berada di persentil tinggi—memiliki
efek riak yang besar pada latensi yang dialami oleh pengguna akhir.
Sistem besar di Amazon tersusun atas banyak layanan yang saling berkooperasi. Tiap layanan
dikembangkan dan dioperasikan oleh satu tim ("layanan" besar terdiri dari beberapa layanan atau
komponen di balik layar). Tim yang memiliki layanan dikenal sebagai pemilik layanan. Setiap
anggota tim tersebut berpikir seperti seorang pemilik dan operator layanan, baik ia adalah seorang
pengembang perangkat lunak, teknisi jaringan, manajer, atau berada di posisi lainnya. Sebagai
pemilik, tim mengatur sasaran untuk kinerja pengoperasian dari seluruh layanan terkait. Kami juga
memastikan bahwa kami memiliki visibilitas ke dalam pengoperasian layanan untuk memastikan
bahwa kami akan memenuhi sasaran tersebut, untuk menghadapi masalah yang timbul, dan
menetapkan sasaran yang lebih tinggi bagi diri kami sendiri di tahun berikutnya. Untuk menetapkan
sasaran dan mendapat visibilitas tersebut, tim harus menginstrumentasi sistem.
Instrumentasi juga memungkinkan kami mendeteksi dan merespons kejadian pengoperasian
secara taktis. Instrumentasi mengumpankan data ke dasbor pengoperasian, sehingga operator
dapat melihat metrik real-time. Ini juga mengumpankan data ke alarm, yang memicu dan
melibatkan operator ketika sistem berperilaku dengan cara yang tidak diharapkan. Operator
menggunakan output terperinci dari instrumentasi untuk dengan cepat mendiagnosis mengapa
kesalahan terjadi. Dari sana, kami dapat memitigasi masalah, dan kembali lagi nanti untuk
mencegah agar masalah tidak terjadi lagi. Tanpa instrumentasi yang baik di seluruh kode, kami
menghabiskan waktu yang berharga untuk mendiagnosis masalah.
Apa yang perlu diukur
Untuk mengoperasikan layanan sesuai dengan standar kami yang tinggi dalam ketersediaan dan
latensi, kami sebagai pemilik layanan perlu mengukur bagaimana perilaku sistem kami.
Untuk mendapat telemetri yang diperlukan, pemilik layanan mengukur kinerja pengoperasian dari
beberapa tempat untuk mendapat beberapa perspektif mengenai bagaimana perilakunya secara
menyeluruh. Ini adalah hal yang rumit, bahkan dalam arsitektur yang sederhana.
Mempertimbangkan layanan yang pelanggan panggil melalui penyeimbang muatan: layanan
berbicara ke cache jarak jauh dan database jarak jauh. Kami ingin tiap komponen mengeluarkan
metrik tentang perilakunya. Kami juga menginginkan metrik mengenai bagaimana tiap komponen
memahami perilaku komponen lainnya. Saat metrik dari seluruh perspektif tersebut digabungkan,
pemilik layanan dapat melacak sumber masalah dengan cepat, dan menggali untuk menemukan
penyebabnya.
Banyak layanan AWS yang secara otomatis menyediakan wawasan pengoperasian tentang sumber
daya Anda. Contohnya, Amazon DynamoDB menyediakan metrik Amazon CloudWatch berisi
tingkat keberhasilan dan kesalahan serta latensi, seperti yang diukur oleh layanan. Namun, saat
kami membangun sistem yang menggunakan layanan tersebut, kami memerlukan lebih banyak
visibilitas ke dalam bagaimana sistem kami berperilaku. Instrumentasi memerlukan kode eksplisit
yang mencatat berapa lama tugas berlangsung, seberapa sering jalur kode tertentu digunakan,
metadata tentang apa yang dikerjakan tugas, dan manakah bagian tugas yang berhasil atau
gagal. Jika tim tidak menambahkan instrumentasi eksplisit, instrumentasi akan dipaksa untuk
mengoperasikan layanannya sendiri sebagai kotak hitam.
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
4
Contohnya, jika kami menerapkan pengoperasian API layanan yang menerima informasi produk
berdasarkan ID produk, kodenya mungkin tampak seperti contoh berikut. Kode ini mencari info
produk di cache lokal, diikuti dengan cache jarak jauh, diikuti dengan database:
public GetProductInfoResponse getProductInfo(GetProductInfoRequest
request) {
// check our local cache
ProductInfo info = localCache.get(request.getProductId());
// check the remote cache if we didn't find it in the local cache
if (info == null) {
info = remoteCache.get(request.getProductId());
localCache.put(info);
}
// finally check the database if we didn't have it in either cache
if (info == null) {
info = db.query(request.getProductId());
localCache.put(info);
remoteCache.put(info);
}
return info;
}
Jika saya mengoperasikan layanan ini, saya akan memerlukan banyak instrumentasi di kode ini
untuk dapat memahami perilakunya dalam produksi. Saya akan memerlukan kemampuan untuk
memecahkan masalah permintaan yang gagal atau lambat, dan memantau tren serta tanda
bahwa dependensi yang berbeda kurang diskalakan atau berprilaku buruk. Ini adalah kode yang
sama, dianotasi dengan beberapa pertanyaan yang harus dapat saya jawab tentang sistem
produksi sebagai satu kesatuan, atau untuk permintaan tertentu:
public GetProductInfoResponse getProductInfo(GetProductInfoRequest
request) {
// Which product are we looking up?
// Who called the API? What product category is this in?
// Did we find the item in the local cache?
ProductInfo info = localCache.get(request.getProductId());
if (info == null) {
// Was the item in the remote cache?
// How long did it take to read from the remote cache?
// How long did it take to deserialize the object from the cache?
info = remoteCache.get(request.getProductId());
// How full is the local cache?
localCache.put(info);
}
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
5
// finally check the database if we didn't have it in either cache
if (info == null) {
// How long did the database query take?
// Did the query succeed?
// If it failed, is it because it timed out? Or was it an invalid
query? Did we lose our database connection?
// If it timed out, was our connection pool full? Did we fail to
connect to the database? Or was it just slow to respond?
info = db.query(request.getProductId());
// How long did populating the caches take?
// Were they full and did they evict other items?
localCache.put(info);
remoteCache.put(info);
}
// How big was this product info object?
return info;
}
Kode untuk menjawab seluruh pertanyaan tersebut (dan pertanyaan lain) sedikit lebih panjang
dibanding logika bisnis sebenarnya. Beberapa pustaka dapat membantu mengurangi jumlah kode
instrumentasi, tetapi pengembang tetap harus bertanya tentang visibilitas yang akan diperlukan
pustaka tersebut, lalu pengembang harus mengerjakan pemasangan instrumentasi.
Saat Anda memecahkan masalah permintaan yang mengalir melalui sistem terdistribusi, Anda
dapat kesulitan memahami apa yang terjadi jika hanya melihat permintaan tersebut berdasarkan
satu interaksi. Untuk menyelesaikan puzzle ini, kami merasa terbantu dengan menyatukan seluruh
pengukuran tentang seluruh sistem tersebut. Sebelum kami dapat melakukannya, tiap layanan
harus diinstrumentasi untuk mencatat ID jejak untuk tiap tugas, dan untuk menyebarkan ID jejak
tersebut ke tiap layanan yang berkolaborasi pada tugas tersebut. Mengumpulkan instrumentasi di
seluruh sistem untuk ID jejak tertentu dapat dilakukan setelah fakta yang diperlukan, atau
mendekati real-time menggunakan layanan seperti AWS X-Ray.
Menelusuri
Instrumentasi memungkinkan pemecahan masalah di beberapa tingkat, dari melirik metrik untuk
melihat apakah ada anomali yang terlalu samar untuk memicu alarm, hingga melakukan
investigasi untuk menemukan penyebab anomali tersebut.
Pada tingkat tertinggi, instrumentasi diagregat menjadi metrik yang dapat memicu alarm dan
tampilan di dasbor. Metrik agregat tersebut memungkinkan operator memantau tingkat
permintaan keseluruhan, latensi panggilan layanan, dan tingkat kesalahan. Alarm dan metrik
tersebut membuat kami menyadari anomali atau perubahan yang harus diinvestigasi.
Setelah melihat anomali, kami harus mencari tahu mengapa anomali tersebut terjadi. Untuk
menjawab pertanyaan tersebut, kami mengandalkan metrik yang tersedia berkat lebih banyak
instrumentasi. Dengan menginstrumentasi waktu yang diperlukan untuk melakukan beragam
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
6
bagian dalam melayani permintaan, kami dapat melihat manakah bagian pemrosesan yang lebih
lambat dari kecepatan normal, atau lebih sering memicu kesalahan.
Meskipun pengatur waktu dan metrik agregat dapat membantu kami menyingkirkan penyebab
atau menyorot area investigasi, mereka tidak selalu menyediakan penjelasan yang lengkap.
Contohnya, kami mungkin dapat melihat dari metrik bahwa kesalahan muncul dari pengoperasian
API tertentu, namun metrik mungkin tidak mengungkapkan rincian yang cukup tentang mengapa
pengoperasian tersebut gagal. Pada titik ini, kami melihat data log mentah dan terperinci yang
dikeluarkan oleh layanan untuk jendela waktu tersebut. Log mentah lalu menunjukkan sumber
masalah—baik kesalahan tertentu yang sedang terjadi, atau aspek tertentu pada permintaan yang
memicu beberapa kasus edge.
Bagaimana kami menginstrumentasi
Instrumentasi memerlukan pengodean. Ini berarti bahwa saat kami menerapkan fungsi baru, kami
memerlukan waktu untuk menambahkan kode tambahan guna mengindikasikan apa yang terjadi,
baik berhasil atau gagal, dan berapa lama waktu yang diperlukan. Karena instrumentasi
merupakan tugas pengodean umum, praktik muncul di Amazon selama bertahun-tahun untuk
mengatasi pola yang umum: standardisasi untuk pustaka instrumentasi umum, dan standardisasi
untuk pelaporan metrik berbasis log terstruktur.
Standardisasi pustaka instrumentasi metrik membantu penulis pustaka memberikan konsumen
visibilitas pustaka mereka tentang bagaimana pustaka beroperasi. Contohnya, klien HTTP yang
biasa digunakan terintegrasi dengan pustaka umum tersebut, jadi jika tim layanan menerapkan
panggilan jarak jauh ke layanan lain, secara otomatis mereka mendapat instrumentasi tentang
panggilan tersebut.
Saat aplikasi yang diinstrumentasikan berjalan dan melakukan pekerjaan, data telemetri yang
dihasilkan ditulis ke file log terstruktur. Umumnya dikeluarkan sebagai satu entri log per
"unit pekerjaan", baik itu merupakan permintaan ke layanan HTTP, atau pesan yang ditarik
dari antrean.
Di Amazon, pengukuran di aplikasi tidak diagregat dan sesekali dibuang ke sistem agregasi metrik.
Seluruh pengatur waktu dan penghitung untuk tiap bagian pekerjaan tertulis di dalam file log.
Dari sana, log diproses dan metrik agregat dikomputasi setelah fakta oleh beberapa sistem lain.
Dengan cara ini, kami akhirnya mendapat semuanya, dari metrik pengoperasian agregat leve;
tinggi hingga data pemecahan masalah terperinci pada tingkat permintaan, seluruhnya dengan
satu pendekatan ke kode instrumentasi. Di Amazon kami membuat log terlebih dahulu, lalu
memproduksi metrik agregat.
Instrumentasi melalui logging
Kami umumnya menginstrumentasi layanan untuk mengeluarkan dua jenis data log: data
permintaan dan data debugging. Data log permintaan biasanya direpresentasikan sebagai sebuah
entri log terstruktur untuk tiap unit pekerjaan. Data ini berisi properti tentang permintaan dan
siapa yang membuat permintaan, apa tujuan permintaan, penghitung seberapa sering tiap hal
terjadi, dan pengatur waktu untuk berapa lama suatu hal berlangsung. Log permintaan berperan
sebagai log audit dan jejak bagi semua hal yang terjadi di layanan. Data debugging meliputi data
tidak terstruktur atau terstruktur secara longgar dari baris debugging apa pun yang dikeluarkan
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
7
aplikasi. Umumnya ini adalah entri log tidak terstruktur seperti kesalahan Log4j atau baris log
peringatan. Di Amazon, kedua jenis data tersebut dikeluarkan ke dalam file log terpisah, sebagian
untuk alasan riwayat, tetapi juga karena melakukan analisis pada format entri homogen dapat
memudahkan Anda.
Agen seperti CloudWatch Logs Agent memproses kedua jenis data log secara real-time dan
mengirimkan log ke CloudWatch Logs. Setelah itu, CloudWatch Logs memproduksi metrik agregat
tentang layanan dalam waktu mendekati real-time. Alarm Amazon CloudWatch membaca metrik
agregat tersebut dan memicu alarm.
Meskipun mahal untuk melakukan logging begitu banyak perincian tentang setiap permintaan,
di Amazon kami merasa bahwa ini adalah hal sangat penting yang harus dilakukan. Lagipula,
kami perlu menginvestigasi ketersediaan blip, lonjakan latensi, dan masalah yang dilaporkan
pelanggan. Tanpa log yang terperinci, kami tidak dapat menjawab pelanggan, dan kami tidak
akan dapat meningkatkan layanan mereka.
Mendapatkan perincian
Topik pemantauan dan alarm sangatlah luas. Di artikel ini, kami tidak akan membahas topik seperti
mengatur dan menyetel ambang batas alarm, mengelola dasbor pengoperasian, mengukur kinerja
dari sisi server dan sisi klien, secara terus-menerus menjalankan aplikasi "canary", serta memilih
sistem yang tepat untuk menggunakan metrik agregat juga menganalisis log.
Artikel ini berfokus pada perlunya menginstrumentasi aplikasi demi menghasilkan data
pengukuran mentah yang tepat. Kami akan menjelaskan hal yang diupayakan tim di Amazon agar
disertakan (atau dihindari) saat menginstrumentasi aplikasi mereka.
Praktik terbaik log permintaan
Di bagian ini, saya akan menjelaskan kebiasaan baik yang kami pelajari selama bekerja di Amazon
tentang logging data "per unit pekerjaan" terstruktur. Sebuah log yang memenuhi kriteria
tersebut berisi penghitung yang mewakili seberapa sering hal-hal terjadi, pengatur waktu berisi
durasi yang diperlukan, dan properti yang menyertakan metadata mengenai tiap unit pekerjaan.
Bagaimana cara kami menghasilkan log
Mengeluarkan satu entri log permintaan untuk setiap unit pekerjaan. Unit pekerjaan
umumnya adalah permintaan yang layanan kami terima atau pesan yang ditarik dari
antrean. Kami menulis satu entri log layanan untuk tiap permimtaan yang layanan kami
terima. Kami tidak menggabungkan beberapa unit yang bekerja sama. Dengan begini, saat
memecahkan masalah permintaan gagal, kami memiliki satu entri log yang dapat dilihat.
Entri ini berisi parameter input yang relevan tentang permintaan untuk melihat apa yang
sedang dicoba, informasi tentang siapa pemanggilnya, dan seluruh informasi pengatur
waktu juga penghitung dalam satu tempat.
Mengeluarkan tidak lebih dari satu entri log permintaan untuk permintaan tertentu.
Pada implementasi layanan nonblok, mungkin tampak mudah untuk mengeluarkan entri
log terpisah bagi tiap tahap dalam jalur pipa pemrosesan. Kami justru lebih sering berhasil
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
8
dalam memecahkan masalah sistem tersebut dengan memasang pipa pegangan ke
sekeliling satu "objek metrik" di antara tahap pada jalur pipa, lalu mengurutkan metrik
sebagai sebuah unit setelah seluruh tahap telah selesai. Memiliki beberapa antri log per
unit pekerjaan dapat mempersulit analisis log, dan berkali-kali lipat meningkatkan
overhead logging yang mahal. Jika kami menulis layanan nonblok baru, kami mencoba
merencanakan siklus hidup logging metrik terlebih dahulu, karena akan menjadi sangat
sulit untuk memfaktorkan kembali dan memperbaikinya nanti.
Membagi tugas yang telah lama berjalan ke dalam beberapa entri log. Berlawanan
dengan rekomendasi sebelumnya, jika kami memliki tugas berdurasi beberapa menit
yang telah berjalan lama atau tugas berdurasi beberapa jam yang seperti alur kerja, kami
dapat memutuskan untuk mengeluarkan entri log terpisah secara berkala sehingga kami
dapat menentukan jika kemajuan sedang berlangsung, atau di manakah terjadinya
penurunan kecepatan.
Mencatat rincian tentang permintaan sebelum melakukan hal seperti validasi. Kami
merasa penting bagi pemecahan masalah dan logging audit untuk menghasilkan log
informasi yang cukup tentang permintaan agar kami tahu apa yang ingin coba dicapai. Kami
juga menemukan bahwa penting untuk me-log informasi ini sedini mungkin, sebelum
permintaan memiliki peluang untuk ditolak oleh validasi, otentikasi, atau logika
pembatasan. Jika kami me-logging informasi dari permintaan masuk, kami memastikan
untuk mensanitasi input (enkode, tandai, dan potong) sebelum kami membuat log.
Contohnya, kami tidak ingin menyertakan string panjang berukuran 1 MB di entri log
layanan jika pemanggil meneruskannya. Melakukan hal tersebut berisiko membuat disk
kami penuh dan menghabiskan lebih banyak penyimpanan log dibanding dugaan kami.
Contoh lainnya dari sanitasi adalah memfilter karakter kontrol ASCII atau menandai urutan
yang relevan dengan format log. Hal ini dapat membingungkan jika pemanggil meneruskan
entri log layanan mereka sendiri, dan dapat memasukkannya ke dalam log kami! Lihat juga:
https://xkcd.com/327/
Merencanakan cara untuk me-log saat verbositas meningkat. Untuk memecahkan
beberapa jenis masalah, log tidak akan memiliki rincian yang cukup tentang permintaan
bermasalah untuk menemukan alasan kegagalan mereka. Informasi tersebut munkin
tersedia di layanan, tetapi volume informasi mungkin terlalu besar untuk membenarkan
logging sepanjang waktu. Memiliki kenop konfigurasi yang dapat Anda putar untuk
meningkatkan verbositas log secara sementara saat Anda menginvestigasi masalah
merupakan tindakan yang cukup membantu. Anda dapat memutar kenop pada host
individu, atau untuk klien individu, atau pada tingkat sampel di seluruh armada. Anda
harus ingat untuk memutar kembali kenop setelah selesai.
Memilih nama yang pendek untuk metrik (tapi tidak terlalu pendek). Amazon telah
menggunakan serialisasi log layanan yang sama selama lebih dari 15 tahun. Pada
serialisasi ini, tiap nama penghitung dan pengatur waktu diulang pada teks biasa di setiap
entri log layanan. Untuk membantu meminimalkan overhead logging, kami menggunakan
nama yang singkat namun deskriptif untuk pengatur waktu. Amazon mulai mengadopsi
format serialisasi baru yang berdasarkan pada protokol serialisasi biner yang dikenal
sebagai Amazon Ion. Tentunya, penting untuk memilih format yang dapat dipahami alat
analisis log dan juga seefisien mungkin dalam melakukan serialisasi, membatalkan
serialisasi, dan menyimpan.
Memastikan volume log cukup beasr untuk menangani logging pada throughput maks.
Kami menguji muatan layanan pada muatan berkelanjutan maksimum (atau bahkan
kelebihan muatan) selama berjam-jam. Kami harus memastikan bahwa ketika layanan
kami menangani lalu lintas berlebih, layanan tetap memiliki sumber daya untuk mengirim
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
9
log secara off-box pada tingkat ketika mereka menghasilkan entri log baru, atau akhirnya
disk akan penuh. Anda juga dapat mengonfigurasi logging agar terjadi di partisi sistem file
yang berbeda dengan partisi akar, sehingga sistem tidak terhenti dalam menghadapi
logging yang berlebihan. Kami mendiskusikan mitigasi lainnya nanti, seperti
menggunakan sampling dinamis yang proporsional dengan throughput, tapi
bagaimanapun strateginya, pengujian adalah hal yang paling penting.
Mempertimbangkan perilaku sistem saat disk penuh. Saat disk server penuh, server
tidak dapat me-log ke disk. Saat hal tersebut terjadi, haruskah layanan berhenti menerima
permintaan, atau menjatuhkan log dan melanjutkan pengoperasian tanpa pemantauan?
Pengoperasian tanpa logging sangatlah berisiko, jadi kami menguji sistem untuk
memastikan bahwa server dengan disk yang hampir penuh dapat terdeteksi.
Menyinkronkan jam. Gagasan mengenai "waktu" pada sistem terdistribusi sangatlah luar
biasa rumit. Kami tidak bergantung pada sinkronisasi jam dalam algoritme terdistribusi,
namun tetap perlu untuk membuat log. Kami menjalankan daemon seperti Chrony atau
ntpd untuk sinkronisasi jam, dan kami memantau server untuk perubahan jam. Untuk
memudahkan Anda, lihat Amazon Time Sync Service.
Mengeluarkan jumlah nol untuk metrik ketersediaan. Penghitungan kesalahan
bermanfaat, namun persentase kesalahan juga tidak kalah bermanfaat. Untuk
menginstrumentasi metrik "persentase ketersediaan", strategi yang kami temukan
bermanfaat untuk mengeluarkan 1 saat permintaan berhasil dan 0 saat permintaan gagal.
Lalu statistik "rata-rata" dari metrik yang dihasilkan adalah tingkat ketersediaan. Secara
sengaja mengeluarkan poin data 0 juga dapat bermanfaat pada situasi lain. Contohnya,
jika aplikasi melakukan pemilihan pemimpin, mengeluarkan 1 secara berkala ketika satu
proses adalah pemimpin, dan 0 ketika proses bukan pemimpin dapat bermanfaat untuk
memantau status pengikut. Dengan cara ini, jika proses berhenti mengeluarkan 0, artinya
lebih mudah untuk mengetahui bahwa ada sesuatu yang rusak di dalamnya, dan tidak
akan dapat mengambil alih jika terjadi sesuatu kepada pemimpin.
Apa yang kami log
Me-log ketersediaan dan latensi seluruh dependensi. Kami menemukan bahwa hal ini
sangat membantu dalam menjawab pertanyaan "mengapa permintaan lambat?" atau
"mengapa permintaan gagal?" Tanpa log ini, kami hanya dapat membandingkan grafik
dependensi dengan grafik layanan, lalu menebak apakah satu lonjakan pada latensi
layanan dependensi menyebabkan kegagalan permintaan yang sedang kami investigasi.
Banyak kerangka kerja layanan dan klien yang mengukur metrik secara otomatis, namun
kerangka kerja lain (seperti AWS SDK, misalnya), memerlukan instrumentasi manual.
Memisahkan metrik dependensi per panggilan, per sumber daya, per kode status, dll.
Jika kami berinteraksi dengan dependensi yang sama berkali-kali di unit pekerjaan yang
sama, kami menyertakan metrik tentang tiap panggilan secara terpisah, dan memperjelas
sumber daya mana yang berinteraksi dengan tiap permintaan. Contohnya, saat memanggil
Amazon DynamoDB, beberapa tim menemukan bahwa menyertakan metrik penentuan
waktu dan latensi per tabel akan membantu, serta per kode kesalahan, dan bahkan per
jumlah pengulangan. Tindakan ini memudahkan pemecahan masalah kasus ketika layanan
menjadi lambat karena pengulangan akibat kegagalan pemeriksaan kondisional. Metrik
tersebut juga mengungkapkan kasus berupa peningkatan latensi yang dirasikan klien
benar-benar akibat pengulangan pembatasan atau pemberian nomor melalui kumpulan
hasil, dan bukan dari kehilangan paket atau latensi jaringan.
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
10
Mencatat kedalaman antrean memori saat mengaksesnya. Jika permintaan berinteraksi
dengan antrean, dan kami menarik objek dari atau memasukkan sesuatu ke dalamnya,
kami mencatat kedalaman antrean saat ini ke objek metrik saat hal tersebut berlangsung.
Untuk antean dalam memori, memperoleh informasi ini sangatlah murah. Untuk antrean
terdistribusi, metadata ini mungkin tersedia secara gratis sebagai respons dari panggilan
API. Logging ini akan membantu menemukan backlog dan sumber latensi di masa
mendatang. Selain itu, saat kami mengeluarkan sesuatu dari antrean, kami mengukur
berapa lama hal tersebut berada di dalam antrean. Hal ini berarti kami perlu
menambahkan metrik "waktu penambahan antrean" ke pesan terlebih dahulu sebelum
kami memasukkannya ke antrean.
Menambahkan penghitung tambahan untuk setiap alasan kesalahan. Pertimbangkan
menambahkan kode yang menghitung alasan kesalahan spesifik untuk setiap permintaan
gagal. Log aplikasi akan menyertakan informasi yang menyebabkan kegagalan, dan pesan
pengecualian terperinci. Namun, kami juga menemukan bahwa melihat tren alasan
kesalahan pada metrik dari waktu ke waktu tanpa perlu menggali informasi tersebut di log
aplikasi juga bermanfaat. Lebih praktis untuk memulai dengan metrik terpisah bagi tiap
kelas pengecualian kegagalan.
Mengelola kesalahan menurut kategori penyebab. Jika seluruh kesalahan ditumpuk ke
dalam metrik yang sama, metrik menjadi bising dan tidak bermanfaat. Paling tidak, kami
telah menemukan pentingnya memisahkan kesalahan yang merupakan "kesalahan klien"
dari kesalahan yang merupakan "kesalahan server". Di luar itu, pemisahan lebih jauh
mungkin bermanfaat. Contohnya di DynamoDB, klien dapat membuat permintaan
tulis kondisional yang mengembalikan kesalahan jika item yang mereka modifikasi tidak
sesuai dengan prakondisi pada permintaan. Kesalahan tersebut sangat jelas, dan kami
berharap agar ini tidak sering terjadi. Sedangkan kesalahan "permintaan tidak valid" dari
klien cenderung merupakan bug yang harus kami perbaiki.
Me-log metadata penting tentang unit pekerjaan. Pada log metrik terstruktur, kami juga
menyertakan cukup metadata tentang permintaan sehingga nanti kami dapat
menentukan dari mana permintaan berasal dan apa yang permintaan coba lakukan. Ini
meliputi metadata yang pelanggan harapkan kami miliki di dalam log saat mereka
menghubungi karena menemukan masalah. Contohnya, DynamoDB me-log nama tabel
yang berinteraksi dengan permintaan, dan metadata seperti apakah pengoperasian baca
merupakan bacaan yang konsisten atau bukan. Namun, DynamoDB tidak me-log data
yang disimpan ke atau diterima dari database.
Melindungi log dengan kontrol akses dan enkripsi. Karena log berisi beberapa tingkat
informasi sensitif, kami mengambil langkah untuk melindungi dan mengamankan data
tersebut. Pengukuran tersebut termasuk mengenkripsi log, membatasi akses ke operator
yang memecahkan masalah, dan mendasari akses tersebut secara rutin.
Menghindari memasukkan informasi yang terlalu sensitif ke log. Log harus berisi
beberapa informasi sensitif agar bermanfaat. Di Amazon, kami menemukan bahwa
penting bagi log untuk menyertakan informasi yang cukup demi mengetahui dari mana
asal permintaan tertentu, namun tidak memasukkan informasi yang terlalu sensitif, seperti
parameter permintaan yang tidak memengaruhi perutean atau perilaku pemrosesan
permintaan. Contohnya, jika kode menguraikan pesan pelanggan, dan penguraian
tersebut gagal, penting untuk tidak me-log payload demi melindungi privasi pelanggan,
sesulit melakukan pemecahan masalah nanti. Kami menggunakan alat untuk mengambil
keputusan tentang apa yang dapat dimasukkan ke log dengan mengikutsertakannya,
bukan dengan mengeluarkannya, untuk mencegah logging parameter sensitif baru yang
ditambahkan nanti. Layanan seperti Amazon API Gateway memungkinkan mengonfigurasi
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
11
data mana yang akan disertakan ke dalam log akses, yang bertindak sebagai mekanisme
keikutsertaan yang baik.
Me-log ID jejak dan menyebarkannya di panggilan backend. Permintaan pelanggan
tertentu sepertinya akan melibatkan banyak layanan yang saling bekerja sama. Ini dapat
berarti dua atau tiga layanan untuk banyak permintaan AWS, jauh lebih banyak layanan
untuk permintaan amazon.com. Untuk memahami apa yang terjadi saat kami
memecahkan masalah sistem terdistribusi, kami menyebarkan ID jejak yang sama di antara
sistem tersebut sehingga kami dapat mengurutkan log dari beragam sistem untuk melihat
di mana kegagalan terjadi. ID jejak adalah sejenis ID permintaan meta yang distempel ke
unit pekerjaan terdistribusi oleh layanan "pintu depan" yang merupakan titik awal bagi
unit pekerjaan. AWS X-Ray adalah satu layanan yang dapat membantu dengan
menyediakan beberapa penyebaran ini. Kami menemukan bahwa meneruskan jejak ke
dependensi merupakan tindakan yang penting. Pada lingkungan multithreaded, sangat
sulit dan rentan terjadi kesalahan bagi kerangka kerja untuk melakukan penyebaran ini
atas nama kami, jadi kami telah terbiasa meneruskan ID jejak, dan konten permintaan lain
(seperti objek metrik!) dalam tanda tangan metode kami. Kami juga menemukan bahwa
meneruskan objek Konteks di tanda tangan metode kami sangat bermanfaat, sehingga
kami tidak perlu memfaktirkan ulang saat menemukan pola yang serupa untuk diteruskan
di masa mendatang. Untuk tim AWS, ini tidak hanya tentang pemecahan masalah sistem
kami, ini juga tentang pelanggan yang memecahkan masalah mereka. Pelanggan
mengandalkan jejak AWS X-Ray yang diteruskan di antara layanan AWS saat layanan
saling berinteraksi atas nama pelanggan. Oleh karena itu, kami perlu menyebarkan ID jejak
AWS X-Ray di antara layanan sehingga mereka mendapat data jejak yang lengkap.
Me-log metrik latensi yang berbeda tergantung pada kode status dan ukuran.
Kesalahan sering terjadi dengan cepat—seperti penolakan akses, pembatasan, dan respons
kesalahan validasi. Jika klien mulai dibatasi pada tingkat tinggi, latensi mungkin tampak
baik. Untuk menghindari polusi metrik ini, kami me-log pengatur waktu terpisah untuk
respons yang berhasil, dan berfokus pada metrik tersebut di dasbor dan alarm kami,
bukan menggunakan metrik Waktu umum. Sama halnya jika ada pengoperasian yang
dapat melambat tergantung ukuran input dan ukuran respons, kami mempertimbangkan
untuk mengeluarkan metrik latensi yang dikategoorikan, seperti SmallRequestLatency dan
LargeRequestLatency. Selain itu, kami memastikan permintaan dan respons dibatasi
dengan tepat untuk menghindari pembatasan yang rumit dan mode kegagalan, namun
bahkan dalam layanan yang didesain dengan saksama, teknik bucket metrik ini dapat
mengisolasi perilaku pelanggan dan menjauhkan kebisingan dari dasbor.
Praktik terbaik log aplikasi
Bagian ini menjelaskan perilaku baik yang telah kami pelajari di Amazon tentang logging data log
debug tidak terstruktur.
Membuat log aplikasi bebas dari spam. Meskipun kami memiliki pernyataan log tingkat
INFO dan DEBUG pada jalur permintaan untuk membantu pengembangan serta
debugging dalam lingkungan uji, kami memilih untuk menonaktifkan tingkat log tersebut
dalam produksi. Daripada mengandalkan log aplikasi untuk informasi pelacakan
permintaan, kami menganggap log layanan sebagai lokasi untuk informasi jejak tempat
kami memproduksi metrik dengan mudah dan melihat tren agregat dari waktu ke waktu.
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
12
Namun, tidak ada peraturan yang jelas di sini. Pendekatan kami adalah secara terus-
menerus meninjau log untuk melihat apakah log terlalu bising (atau tidak cukup bising),
dan menyesuaikan tingkat log dari waktu ke waktu. Contohnya, saat menyalami log, kami
sering menemukan pernyataan log yang terlalu bising, atau metrik yang kami harapkan
kami memilikinya. Untungnya, peningkatan tersebut sering kali mudah dibuat, jadi kami
telah terbiasa untuk mengisi item backlog tindak lanjut cepat guna menjaga log kami agar
tetap bersih.
Menyertakan ID permintaan yang sesuai. Saat kami memecahkan masalah kesalahan di
log aplikasi, kami sering kali ingin melihat rincian mengenai permintaan atau pemanggil
yang memicu kesalahan. Jika kedua log berisi ID permintaan yang sama, kami dapat
dengan mudah melompat dari satu log ke lainnya. Pustaka logging aplikasi akan
menuliskan ID permintaan yang sesuai jika dikonfigurasi dengan tepat, dan jika ID
permintaan diatur sebagai ThreadLocal. Jika aplikasi di-multithread, pertimbangkan untuk
memberikan perhatian khusus guna mengatur ID permintaan yang tepat saat thread mulai
bekerja pada permintaan baru.
Membatasi tingkat spam kesalahan log aplikasi. Umumya, layanan tidak akan
mengeluarkan banyak hal ke log aplikasi, tapi jika layanan mulai menunjukkan kesalahan
dalam volume besar, layanan mungkin secara mendadak mulai menuliskan entri log yang
sangat besar dalam tingkat tinggi dengan jejak tumpukan. Sebuah cara yang kami
temukan untuk menghindari hal ini adalah dengan membatasi tingkat dari seberapa sering
logger tertentu akan me-log.
Lebih memilih string format daripada String#format atau rangkaian string.
Pengoprasian API log aplikasi lama menerima satu pesan string, bukan api string format
varargs log4j2. Jika kode diinstrumentasikan dengan pernyataan DEBUG, tetapi produksi
dikonfigurasi pada tingkat KESALAHAN, mungkin saja ini dapat menyia-nyiakan pekerjaan
memformat string pesan DEBUG yang diabaikan. Beberapa pengoperasian API logging
mendukung penerusan pada objek arbitrer yang akan dipanggil metode toString()-nya
hanya jika entri log akan dituliskan.
Me-log ID permintaan dari panggilan layanan yang gagal. Jika layanan dipanggul dan
mengembalikan kesalahan, layanan tampaknya mengembalikan ID permintaan. Kami
menemukan bahwa penting menyertakan ID permintaan di log agar saat kami perlu
menindaklanjuti pemilik layanan tersebut, kami memiliki cara bagi mereka untuk dengan
mudah menemukan entri log layanan yang sesuai milik mereka. Kesalahan batas waktu
membuat hal ini tidak mudah dilakukan karena layanan mungkin belum mengembalikan
ID permintaan, atau pustaka klien mungkin belum menguraikannya. Walau demikian, jika
kami mendapat ID permintaan kembali dari layanan, kami membuat log-nya.
Praktik terbaik layanan throughput tinggi
Untuk sebagian besar layanan di Amazon, logging pada setiap permintaan tidak membebankan
overhead biaya yang tinggi. Layanan throughput tinggi masuk ke dalam area abu-abu, namun
kami masih sering me-log pada setiap permintaan. Contohnya, wajar untuk menganggap bahwa
DynamoDB, pada puncaknya melayani 20 juta permintaan per detik dari lalu lintas internal
Amazon saja, tidak akan me-log cukup banyak, tetapi kenyataannya DynamoDB me-log setiap
permintaan untuk pemecahan masalah dan untuk audit serta alasan kepatuhan. Berikut adalah
benerapa kiat tingkat tinggi yang kami gunakan di Amazon untuk membuat logging lebih efisien
pada throughput per host yang lebih tinggi:
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
13
Sampling log. Daripada menulis setiap entri, pertimbangkan untuk menulis setiap entri N.
Tiap entri juga menyertakan berapa banyak entri yang dilewati sehingga sistem agregat
metrik dapat memperkirakan volume log yang sebenaranya pada metrik yang
dikomputasi. Algoritme sampling lainnya seperti sampling reservoir menyediakan lebih
banyak sampel representatif. Algoritme lain memperioritaskan logging kesalahan atau
permintaan lambat daripada permintaan cepat yang berhasil. Tetapi dengan sampling,
kemampuan hilang untuk membantu pelanggan dan memecahkan masalah kegagalan
teretntu. Beberapa persayaratan kepatuhan tidak mengizinkannya.
Memindahkan serialisasi dan penghapusan log ke thread terpisah. Ini adalah perubahan
yang mudah dan umum digunakan.
Rotasi log yang sering terjadi. Merotasi file log yang me-log setiap jam mungkin
membuat Anda merasa nyaman karena memiliki lebih sedikit file yang harus dikerjakan,
namun dengan merotasi setiap menit, beberapa hal meningkat. Contohnya, agen yang
membaca dan mengompres file log akan membaca file dari cache halaman, bukan disk,
lalu CPU serta IO dari log pengompresan dan pengiriman akan disebarkan selama jam
tersebut, bukan selalu memicu di akhir jam.
Menulis log sebelum dikompres. Jika agen pengiriman log mengompres log sebelum
mengirimkannya ke layanan pengarsipan, CPU dan disk sistem akan mengalami lonjakan
secara berkala. Mengamortisasi biaya ini dan mengurangi IO disk setengahnya mungkin
dilakukan dengan streaming log yang dikompres ke disk. Namun, tindakan ini dapat
memunculkan beberapa risiko. Kami menemukan bahwa bermanfaat untuk menggunakan
algoritme kompresi yang dapat menangani file jika terjadi crash aplikasi.
Menulis ke ramdisk / tmpfs. Mungkin lebih mudah bagi layanan untuk menulis log ke
memori hingga log dikirim ke server daripada menulis log ke disk. Menurut pengalaman
kami, tindakan ini bekerja paling baik dengan rotasi log setiap menit daripada rotasi log
setiap jam.
Agregat dalam memori. Jika Anda perlu menangani ratusan dari ribuan transaksi per
detik pada satu mesin, mungkin terlalu mahal untuk menulis satu entri log per
permintaan. Namun, Anda kehilangan banyak kemampuan observasi jika melewatkannya,
sehingga kami menemukan bahwa bermanfaat untuk tidak mengoptimalkan terlalu dini.
Memantau penggunaan sumber daya. Kami memerhatikan seberapa dekat kami dengan
pencapaian beberapa batas penskalaan. Kami mengukur IO dan CPU per server, dan
berapa banyak sumber daya tersebut yang dikonsumsi oleh agen logging. Saat kami
melakukan uji muatan, kami menjalankannya cukup lama sehingga kami dapat
membuktikan bahwa agen pengiriman log dapat mengimbangi throughput kami.
Memiliki alat analisis log yang tepat
Di Amazon, kami mengoperasikan layanan yang kami tulis, jadi kami semua harus menjadi ahli
dalam memecahkan masalahnya. Termasuk mampu melakukan analisis log dengan mudah. Kami
memiliki banyak alat yang dapat digunakan, dari analisis log lokal untuk mencari di log dengan
jumlah yan cukup kecil, hingga analisis log tersdistribusi untuk menyaring dan mengagregat hasil
dari log dengan volume besar.
Kami menemukan bahwa penting untuk berinvestasi dalam alat dan buku panduan analisis log
bagi tim. Jika saat ini log berukuran kecil, tetapi layanan diharapkan untuk tumbuh seiring waktu,
kami memerhatikan kapan alat terbaru kami berhenti menskalakan, sehingga kami dapat
berinvestasi untuk mengadopsi solusi analisis log terdistribusi.
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
14
Analisis log lokal
Proses analisis log mungkin memerlukan pengalaman dalam beragam utilitas baris perintah Linux.
Contohnya, "temukan alamat IP pembicara teratas di log" yang umum hanyalah:
cat log | grep -P "^RemoteIp=" | cut -d= -f2 | sort | uniq -c | sort -nr |
head -n20
Namun, ada banyak alat lain yang bermanfaat untuk menjawab pertanyaan yang lebih rumit
dengan log kami, termasuk:
jq: https://stedolan.github.io/jq/
RecordStream: https://github.com/benbernard/RecordStream
Analisis log terdistribusi
Layanan analisis data besar apa pun dapat digunakan untuk melakukan analisis log terdistribusi
(contohnya, Amazon EMR, Amazon Athena, Amazon Aurora, dan Amazon Redshift). Namun,
beberapa layanan dilengkapi dengan sistem logging, contohnya Amazon CloudWatch Logs.
Wawasan CloudWatch Logs
AWS X-Ray: https://aws.amazon.com/xray/
Amazon Athena: https://aws.amazon.com/athena/
Penutup
Sebagai seorang pemilik layanan dan pengembang perangkat lunak, saya menghabiskan banyak
waktu untuk melihat output instrumentasi—grafik di dasbor, file log individu—dan menggunakan
alat analisis log terdistribusi seperti CloudWatch Logs Insights. Itu adalah beberapa hal kesukaan
yang saya lakukan. Saat saya butuh istrirahat setelah menyelesaikan beberapa tugas yang
menantang, saya memulihkan tenaga dan menghadiahi diri saya dengan menyelami log. Saya
memulai dengan pertanyaan seperti "mengapa metrik ini melonjak di sini?" atau "dapatkah latensi
pengoperasian ini menjadi lebih rendah?" Saat pertanyaan saya berakhir dengan kebuntuan, saya
sering menemukan beberapa pengukuran yang dapat bermanfaat dalam kode, jadi saya
menambahkan instrumentasi, pengujiam, dan mengirim tinjauan kode ke rekan-rekan tim saya.
Terlepas dari fakta bahwa banyak metrik yang dilengkapi dengan layanan terkelola yang kami
gunakan, kami perlu memikirkan dengan matang dalam menginstrumentasi layanan kami sendiri
sehingga kami memiliki visibilitas yang diperlukan untuk mengoperasikannya secara efektif.
Selama kejadian pengoperasian, kami perlu menentukan dengan cepat mengapa kami memiliki
masalah dan apa yang dapat kami lakukan untuk memitigasi masalah tersebut. Memiliki metrik
yang tepat di dasbor kami sangatlah penting agar kami dapat melakukan diagnosis tersebut
dengan cepat. Selain itu, karena kami selalu mengubah layanan, menambahkan fitur baru juga
mengubah cara fitur berinteraksi dengan dependensinya, latihan memperbarui dan
menambahakan intrumentasi yang tepat akan berlangsung selamanya.
Menginstrumentasi sistem terdistribusi untuk visibilitas pengoperasian
15
Tautan
"Look at your data," oleh eks Amazonian John Rauser:
https://www.youtube.com/watch?v=coNDCIMH8bk (termasuk bagian 13:22, saat ia benar-
benar mencetak log agar dapat melihat mereka dengan lebih baik)
"Investigating anomalies" oleh eks Amazonian John Rauser:
https://www.youtube.com/watch?v=-3dw09N5_Aw
"How humans see data" oleh eks Amazonian John Rauser:
https://www.youtube.com/watch?v=fSgEeI2Xpdc
https://www.akamai.com/uk/en/about/news/press/2017-press/akamai-releases-
spring-2017-state-of-online-retail-performance-report.jsp