PS Saat menulis artikel ini, tidak ada satu pun IP yang dirugikan , proyek aslinya, meskipun jenuh dengan semangat pembajakan (server gratis dari game berbayar!), Tidak melanggar hak apa pun, kode pemegang hak cipta tidak digunakan di sana, dan server sepenuhnya didasarkan pada penelitian klien dan suara game yang dibeli dengan jujur rasa pengembang. Karya ini hanya menceritakan tentang tantangan yang dihadapi penulis dan metode asli untuk menyelesaikannya, baik di proyek lama maupun modern. Saya mohon maaf sebelumnya atas gaya naratif dari cerita tersebut, bukan hanya dengan mencantumkan fakta.
pengantar
Anda dapat berdebat sebanyak yang Anda suka. Net bukan untuk server, tetapi menurut saya saat itu (dan sekarang) ide yang sangat masuk akal bahwa Anda dapat menulis logika dalam bentuk skrip, mengkompilasi dan memuatnya saat bepergian, tanpa terlalu memikirkan alokasi memori, perakitan puing-puing, petunjuk, dan banyak lagi. Faktanya, ini memungkinkan Anda untuk mendelegasikan skrip logika bisnis ke pengembang yang kurang berkualifikasi, hanya terbatas pada Peninjauan Kode. Tetapi untuk melakukan ini, Anda perlu memastikan bahwa kernel itu sendiri berfungsi tanpa kegagalan, dan kernel mulai gagal bahkan pada 10-15 online, baik pada tahun 2004 maupun pada tahun 2020.
Pada tahun 2004, semuanya berputar di sekitar Windows Server 2003, .Net 1.1, MSSQL 2000. Server dan hosting disediakan oleh penyedia Wnet, dan kemudian server baru dikumpulkan dengan sumbangan dari pemain. Proyek ini tidak sepenuhnya komersial, dan pendapatan minimal dari spanduk dan akun premium digunakan untuk peningkatan.Server modern berjalan di Mono di bawah Debian dalam mode kompatibilitas .Net 4.7, dengan MariaDB untuk data, dihosting di cloud Hetzner. Sudah lama tidak ada idealis dengan mata membara yang percaya bahwa game harus gratis, dan sumbangan serta penjualan item game membunuh semua minat. Sekarang karakter ini telah berubah menjadi cukup abu-abu, mengubah antusiasmenya terhadap pengalaman, dan yakin bahwa startup harus membawa kesenangan dan pendapatan.
Tapi kisahnya bukan tentang itu, tetapi tentang server yang ditulis sendiri dan masalah mereka.
Bab 1. Penyakit menular
. , , , . , , . , , . Visual Studio, - , . EventLog .Pada tahun 2020, aplikasi server, pada prinsipnya, hanya aplikasi konsol, berjalan di layar terpisah di Linux. Tidak ada lagi pilihan untuk diluncurkan di bawah Visual Studio, tetapi logger menjadi sangat maju selama bertahun-tahun, UnhandledExceptions muncul seperti kelinci di jaringan, dan pada prinsipnya tidak ada kode asli. Yang, bagaimanapun, tidak menyelamatkan saya dari crash dengan OOM dan StackOverflowException. Kedalaman tumpukan dalam kasus StackOverflowException telah berkembang sepuluh kali lipat, mengisi ratusan kilobyte log dengan pesan berjenis sama dan menolak untuk menulis pelacakan tumpukan normal. Tapi bagaimanapun juga, mengarahkan ke >> log.txt dengan cepat memungkinkan untuk memahami siapa yang harus disalahkan dan di mana. Bot Telegram membantu secara terpisah, menandakan bahwa proses server telah mati.
— , Console.Out Console.Error. UnhandledExceptionHandler, . AutoFlush = true, , .
cmd — , . , , , - — , . - — .Net >> log.txt.
UnhandledExceptionHandler : OutOfMemoryException ( ), StackOverflowException Unmanaged . , — Access Violation - OOM.
Access Violation — ZLib ( ICSharpCode.SharpZipLib), OpenSSL ( SRP-6), MySQL ( System.Data MSSQL ).
, Socket.BeginReceive . .Net Thread Pool ( , IO Threads) , UnhandledExceptionHandler. , BeginReceive->EndReceive->BeginReceive , BeginReceive .
Semua ini secara signifikan meningkatkan gambar dan server mulai lebih jarang crash, terutama hanya ketika memori habis.
Maka itu hanya masalah teknologi. Studi tentang log menunjukkan bahwa stack overflow tidak terwujud dalam inti, tetapi dalam logika bisnis: roket bertabrakan dengan roket atau tambang lain, mereka meledak, ini memicu ledakan roket pertama, dan seterusnya dalam lingkaran. Secara keseluruhan, ini adalah momen kerja yang normal, tapi saat itulah saya merasa aneh déjà vu melawan iblis yang telah lama terlupakan di masa lalu. Dan kemudian penyebab wabah baru (atau lama terlupakan) muncul - kurangnya sumber daya.
Bab 2. Senang
— 256 , ! - , , , , — , OOM - . , — Visual Studio ( , ), WinDbg (), - dotTrace (). , . — , 1.7, . . 100%. , , , — ~100 . Maoni Stephens Rico Mariani GC, LOH (Large Object Heap) .Net. , (pin) , Gen 2, — LOH,Server modern dengan memori kurang dari 4GB menyebabkan seringai, dan Anda dapat menambahkan 8-16 gigabyte ekstra untuk solusi cloud dalam beberapa klik dan sekali restart. Namun demikian, ketika memori mulai bocor dan beban prosesor melonjak hingga 100-150% (berdasarkan 800% untuk 8 inti), saya kembali merasa seperti siswa berusia 20 tahun, membakar gigabyte dan gigaflop di kotak api mesin yang rakus. Aneh, tidak normal, dan bodoh. Sangat tidak menyenangkan, seperti sebelumnya, permainan terus berjalan normal (meskipun dengan kelambatan), tetapi tidak ada yang terganggu. Nah, sampai ingatannya habis tentunya.. — , , , (, .Net 1.1 Generics!). — , - , . Marshal.AllocHGlobal ( - , ). , , . , , , 100% CPU - . Interop WSASend/WSAReceive ( Windows , .Net) . - , .Net : BeginSend/BeginReceive , , 100% CPU.
, , , , , . , - 100% , !
, 2005 Workstation GC Server GC .Net 2.0 Preview. — , GC , 5-10% CPU.
, , Thread Pool Net 1.1 Workstation GC , ( !) ( 100% ).
BeginSend/BeginReceive Windows IOCP . , , , OOM 100% .
Selama bertahun-tahun, Lightweight Threads (alias Serat) berhasil muncul dan menghilang karena itu kami tidak lagi memiliki akses ke utas sistem di .Net, hanya untuk yang disebut. Thread Terkelola, dan di Mono masih belum ada akses ke ProcessThread - hanya ada stub di dalamnya. Diagnostik utas menjadi jauh lebih rumit, tetapi sekarang saya menggunakan Kumpulan Utas saya sendiri, semua utas dihitung dan diberi nama, untuk masing-masing utas statistik yang akurat disimpan, yang mana yang saat ini berjalan, berapa lama waktu yang dibutuhkan untuk tugas tertentu. Karena ini, dengan cepat ternyata untuk melacak bahwa sekarang masalahnya ada di kode saya, dan bukan di sistem, dan statistik utas menunjukkan bahwa zhor dikaitkan dengan eksekusi logika bisnis, hanya beberapa tindakan dilakukan 100 kali lebih sering dari yang seharusnya. Sekarang saya tidak terbatas pada sumber daya,oleh karena itu, saya dengan tenang menyediakan panggilan setiap skrip dan pengatur waktu dengan pencatatan tambahan, mengukur waktu pelaksanaan setiap peristiwa, dan dalam percobaan seminggu saya dapat dengan yakin mengatakan apa masalahnya. Ternyata ada NPC tertentu yang mencoba menyerang NPC lain dan keduanya terjebak di batu, sehingga mereka tidak bisa bergerak dan usaha mereka untuk saling menembak langsung terhenti karena kurangnya Line Of Sight. Tetapi pada saat yang sama, setiap siklus menghitung perilaku (15 md), mereka mencoba menghitung jalur, mulai menembak, tetapi karena ketidakmungkinan menembak, senjata tidak dimuat ulang dan pada siklus berikutnya semuanya diulang. Selama beberapa hari permainan, ratusan NPC semacam itu direkrut dan mereka akhirnya memakan semua sumber daya server. Solusinya adalah memperbaiki perilaku dan mengurangi situasi yang macet, dan pada saat yang sama waktu muat ulang yang singkat bahkan untuk bidikan yang tidak berhasil.
Dan kemudian server mulai membeku.
Bab 3. Dingin
Musim gugur 2005 tidak mudah - Saya mengalami situasi yang tidak pasti dengan pekerjaan saya, sewa apartemen tiba-tiba berlipat ganda. Saya hanya senang dengan server game - sudah ada ratusan server online, tetapi di sana masalahnya juga dimulai - seluruh dunia mulai membeku. Dalam kasus terbaik, ping terus berjalan atau beberapa timer berfungsi. Dan terkadang semuanya macet, lalu lintas berhenti dan Anda harus mematikan aplikasi server dan memulainya lagi. Seperti sebelumnya, tidak mungkin untuk terhubung dengan debugger ke server yang sedang berjalan karena konsumsi dan rem yang signifikan. Untuk beberapa alasan, Visual Studio akan crash atau macet dari ini.Pada salah satu hari yang dingin di bulan Oktober tahun 2020, rencana kedatangan live streamer terganggu karena server tiba-tiba berhenti berfungsi. Otorisasi berfungsi, tetapi tidak mungkin untuk memasuki dunia, bot Telegram diam. Pencarian cepat untuk masalah tidak menunjukkan apa pun di log, tidak ada masalah memori, dan tidak ada utas yang kelaparan. Itu berhenti begitu saja. Setelah mengatakan dengan lantang beberapa kali sesuatu tentang kucing dari matriks dan wanita berperilaku tidak senonoh, saya pergi mencari jalan buntu. Setelah Microsoft membeli Miguel de Icaz dan Xamarin, dokumentasi Mono adalah pemandangan yang menyedihkan - sebagaimana adanya, tetapi tidak relevan, atau tidak mengarah ke mana pun. Misalnya, 3/4 data dari halamantentang debugging di mono dengan gdb tidak berlaku dan tidak berfungsi. Saya dapat terhubung ke server yang dibekukan melalui gdb, tetapi perintah memanggil mono_pmip dan lainnya memberikan jawaban yang tidak dapat dipahami, sebagian besar tentang kesalahan sintaks. Secara ajaib, saya menyadari bahwa gdb ingin saya mentransmisikan parameter dan hasil dari perintah mono_ * ke jenis tertentu, jadi saya akhirnya bisa mendapatkan daftar utas yang dibekukan dalam pemblokiran silang. Tetapi angka dalam daftar tidak cocok dengan perintah ps atau ManagedThreadId dari server. Logging yang diperpanjang, yang saya lakukan untuk menemukan prosesor terbakar, banyak membantu - dari situ saya dapat memahami paket dan timer mana yang dieksekusi terakhir dan secara bertahap mulai mempersempit lingkaran tersangka. Sebagai kejahatan, pemblokiran silang tidak dengan dua utas, tetapi dengan tiga, jadi tidak mungkin untuk mendapatkan gambaran yang lebih detail.Kemudian saya teringat tentang penggaruk lama dan mulai melihat kode untuk menggunakan kunci. Ternyata, beberapa pemfaktoran ulang telah berlalu selama bertahun-tahun dan SpinLock secara bertahap digantikan oleh Monitor.Enter / Monitor.Exit, dan seringkali dengan kunci sederhana. Dan kemudian tiba-tiba saya menarik perhatian sayaArtikel Eric Gunnerson, yang mengatakan bahwa Anda dapat melakukannya dengan lebih mudah: gunakan Monitor.TryEnter di mana saja dengan batas waktu, dan jika kunci gagal, maka berikan pengecualian. Ini adalah metode yang sangat sederhana dan sangat efektif - jika di suatu tempat panggilan TryEnter menunggu lebih dari 30 detik dan jatuh (dan penundaan seperti itu bukan tipikal logika), maka tempat ini harus diselidiki dan diperiksa siapa yang bisa mengambil untuk waktu yang lama dan tidak diberi objek kunci. Menaburkan abu di kepala saya, saya menyadari bahwa saya dapat membersihkan semuanya dengan cara ini 15 tahun yang lalu, tidak perlu menemukan kembali roda dengan menghitung “kedalaman lubang”. Tapi mungkin itu yang terbaik.
— , . , - . , - . SOS.dll. Son Of Strike WinDbg .Net , , . , .Net GC. - sos.dll 50. , , , . , — deadlock!
, . — . — , , , , ! , . SpinLock try/finally . , , — , SpinLock , , , , , . 8 , . , : , , “ ”. , . , , — .
, , Xeon 5130x2 8 . 2000, 2500, . , , , , -, . .
Nah, kemudian pengendara ke-4 datang ke proyek baru, seperti emulator. Hanya saja dia tidak punya waktu untuk menjadi populer. Meski begitu, kehadiran sebanyak tiga masalah kritis tepat di awal proyek dengan cepat membuatnya pingsan. Dan game itu sama sekali tidak mainstream. Tapi ini juga bukan topik untuk artikel ini.
PPS Artikel ini menggunakan ilustrasi oleh seniman tak dikenal Parsakoira dengan tanda tangan "ChoW # 227 :: VOTING :: 4 Horsemen of the Apocalypse", mungkin dari website conceptart.com yang sudah meninggal:
https://www.pinterest.com/pin/460141286926583086/
https : //www.pinterest.com/pin/490681321879914768/