Blog

Bagaimana Satu Chat Berat Boleh Menjatuhkan API Kami

Pada 28 September, kira-kira 17 minit selepas satu keluaran, kedua-dua pelayan API pengeluaran kami kehabisan memori pada masa yang sama, dimulakan semula, dan selama lebih kurang lima minit pengimbang beban tidak mempunyai pelayan sihat untuk menghantar trafik. Pembetulan pertama kami memberikan API dua kali ganda memori. Punca sebenar muncul kemudian pada hari itu: membuka satu chat tertentu meminta API memuatkan 53 MB mesej dalam satu permintaan. Sejarah chat kini dimuatkan dalam halaman yang dihadkan mengikut saiz serta bilangan, dan chat itu dibuka dengan halaman pertama 5 MB dan bukannya ranap.

Apa yang tumbang

API kami berjalan sebagai kontena pada setiap satu daripada dua pelayan di belakang pengimbang beban. Setiap kontena mempunyai had memori 384 MiB. Dalam keadaan rehat ia menggunakan 130–140 MiB, jadi had itu kelihatan seperti ruang yang mencukupi.

Kedua-dua kontena mencapai had itu serentak dan ranap dengan mesej “JavaScript heap out of memory”. Heap ialah memori yang digunakan proses Node.js untuk objek yang sedang dikerjakannya. Oleh kerana kedua-dua pelayan gagal serentak, tiada lagi tempat untuk menghala permintaan. Itu jenis gangguan terburuk bagi persediaan dua pelayan: lebihan hanya membantu apabila kegagalan tidak berlaku pada masa yang sama.

Pembetulan pertama: lebih ruang

Masanya menunjuk kepada deployment. Selepas keluaran, giliran ejen yang diganggu oleh deployment disambung semula dan menyimpan transkripnya sekali lagi, dan lonjakan kerja itu kelihatan sebagai punca yang jelas bagi lonjakan memori.

Jadi perubahan pertama menaikkan had API daripada 384 MiB kepada 768 MiB. Kami menggunakannya secara langsung pada kedua-dua pelayan pada hari yang sama, dan memasukkannya ke dalam konfigurasi deployment supaya deployment seterusnya tidak diam-diam mengembalikan 384. Pembetulan yang dibuat secara manual pada pelayan yang kemudian dibatalkan oleh deployment seterusnya ialah cara biasa gangguan yang sama kembali semula.

Memori tambahan ialah margin keselamatan yang munasabah. Ia bukan penjelasan.

Punca sebenar: satu permintaan, 71 MB

Kemudian pada hari itu kami menghasilkan semula ranap itu pada salinan satu chat, menggunakan had memori lama pengeluaran. Salinan itu sahaja telah meranapkan API, tanpa sebarang deployment terlibat.

Apabila anda membuka projek, aplikasi web meminta API untuk sejarah chat itu. Titik akhir itu memulangkan 30 mesej terbaru secara penuh. Bagi kebanyakan chat, 30 mesej adalah kecil. Bagi chat ini, 30 mesej terbaru ialah 53 MB dalam pangkalan data dan respons 71 MB. Beberapa balasan ejen berukuran 4–10 MB setiap satu, kebanyakannya transkrip sub-ejen: ejen pembantu yang dimulakan oleh ejen utama untuk mengerjakan sebahagian tugas secara selari, yang kerja penuhnya disimpan bersama balasan.

Membina respons itu sahaja memerlukan lebih heap daripada yang API ada. Dan setiap kali projek itu dibuka atau disegarkan, permintaan dihantar semula. Satu chat sahaja boleh menjatuhkan mana-mana pelayan yang dihalakan kepadanya, dan kerana halaman boleh dimuat semula, ia boleh sampai ke kedua-duanya.

“30 mesej” tidak pernah menjadi had saiz yang sebenar. Ia ialah had bilangan yang kebetulan kecil untuk chat biasa.

Pembetulan: halaman yang dihadkan mengikut saiz serta bilangan

Satu halaman sejarah kini ialah 30 mesej atau kira-kira 4 MB daripadanya, mana yang tercapai dahulu.

Ia berfungsi dalam dua langkah:

  1. Minta saiz dahulu. API meminta pangkalan data untuk ID dan saiz tersimpan bagi mesej terbaru, tanpa kandungannya. Pertanyaan itu murah walau sebesar mana pun mesej.
  2. Muatkan hanya yang muat. Bergerak dari yang terbaru ke yang terlama, ia menambah mesej sehingga mesej seterusnya akan menolak halaman melebihi 4 MB. Hanya baris-baris itu kemudian dimuatkan sepenuhnya.

Dua peraturan memastikan ini selamat:

  • Mesej terbaru sentiasa masuk ke halaman, tidak kira saiznya. Halaman yang tidak memulangkan apa-apa akan menyebabkan chat tersekat, tanpa cara untuk tatal ke belakang.
  • Tiada apa yang dipotong. Tiada mesej dipotong atau digugurkan. Baki chat dimuatkan melalui kawalan “Tatal ke atas untuk mesej lebih awal” yang sudah digunakan untuk mesej lama, satu halaman pada satu masa.

Kami menemui satu tempat lagi dengan bentuk yang sama. Apabila anda menghentikan satu giliran, API memeriksa beberapa balasan terakhir untuk melihat sama ada mana-mana kosong dan patut dibersihkan. Ia melakukannya dengan memuatkan lapan mesej penuh. Pada chat dengan balasan berbilang megabait, itu masalah yang sama dalam bentuk yang lebih kecil. Kini ia bertanya kepada pangkalan data soalan ya-atau-tidak — adakah mesej ini mempunyai sebarang kandungan? — tanpa memuatkan kandungan itu sendiri.

Cara kami menyemaknya

Pada salinan chat itu, dijalankan dengan had 384 MiB yang lama:

  • Halaman pertama ialah 5 MB. Sebelum ini, permintaan yang sama meranapkan API.
  • Lima tab pelayar yang membuka chat serentak memuncak pada 154 MB memori.
  • Menatal ke belakang melalui keseluruhan chat memulangkan kesemua 190 mesej, setiap satu tepat sekali, mengikut urutan.

Logik pemilihan halaman juga mempunyai ujian unit, termasuk satu yang dibina daripada saiz sebenar mesej terbaru chat itu. Halaman pertama kembali dengan satu mesej, menyatakan bahawa ada lagi, dan halaman seterusnya bermula pada mesej selepasnya.

Apa yang kami pelajari

  • Bilangan bukan had saiz. Mana-mana titik akhir yang memulangkan “N yang terbaru” bagi sesuatu yang boleh membesar tanpa had juga memerlukan bajet bait. Data akhirnya akan menemui jurang itu.
  • Suspek yang paling jelas tidak selalunya punca. Deployment ialah pencetus sebenar bagi kerja tambahan, dan memori tambahan itu berbaloi. Tetapi ranap itu berulang tanpa deployment, dan tanpa menghasilkan semula ia kami akan berhenti pada peningkatan memori.
  • Dua pelayan gagal bersama apabila menerima permintaan yang sama. Lebihan melindungi daripada satu pelayan mati. Ia tidak melindungi daripada permintaan yang membunuh mana-mana pelayan yang dicapainya, terutamanya yang akan dicuba semula secara semula jadi oleh pengguna dengan memuat semula.
  • Betulkan dalam konfigurasi, bukan hanya pada kotak. Peningkatan memori dimasukkan ke dalam konfigurasi deployment pada hari yang sama, supaya deployment seterusnya mengekalkannya.

Ini ialah cerita memori kedua terkini yang melibatkan output ejen. Yang pertama ialah label status yang menggilirkan 690 MB rentetan. Jika anda menggunakan sub-ejen di Mythex, anda boleh membaca tentang cara ia berfungsi dalam dokumentasi.

Mythex · Pricing · Bina apa sahaja dengan AI · Templat laman web dan aplikasi · Mythex dibandingkan · Glosari pembinaan aplikasi AI · Alat percuma untuk membina aplikasi dengan AI · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)