BEAM Binariesni tushunish: DNS kutubxonamizni qanday qilib o‘ta tezkor (hech qanday NIFsiz) qildik

BEAM Binariesni tushunish: DNS kutubxonamizni qanday qilib o‘ta tezkor (hech qanday NIFsiz) qildik

Okt 20, 2026 beam elixir erlang dns performance optimization binary protocols backend development

Agar siz NameOcean’dagi kabi domen ro‘yxatdan o‘tkazish, DNS hosting va bulutli infratuzilma bilan ishlaydigan platformani boshqarayotgan bo‘lsangiz, unumdorlik shunchaki "bo‘lsa yaxshi" degan narsa emas, balki ishonchlilikning asosi hisoblanadi. Aynan shuning uchun biz Erlang ekotizimidagi aqlli optimizatsiya hikoyalarini ko‘rganda hayajonlanamiz va ulardan birini siz uchun tahlil qilishni istaymiz.

Yaqinda biz DNSimple jamoasi tomonidan ularning ochiq manbali DNS kutubxonasi — dns_erlangni optimizatsiya qilish bo‘yicha qilingan qiziqarli chuqur tahlil bilan tanishdik. Ularning natijalari hayratlanarli edi: har bir so‘rov uchun 12% kamroq CPU va soniyasiga 14% ko‘proq so‘rovlar xizmat ko‘rsatildi — va bularning barchasi hech qanday NIFlarsiz, faqatgina sof BEAM optimizatsiyalari orqali amalga oshirildi. Elixir yoki Erlang’da yuqori o‘tkazuvchanlikdagi tizimlarni qurayotgan har bir kishi uchun bu o‘qish kerak bo‘lgan muhim ma’lumotdir.

Keling, buni nima imkon berishini ko‘rib chiqamiz.

BEAM Binari Mental Modeli

Bu ko‘plab Elixir dasturchilarini hayratga soladigan narsa: qisqa siklda binarlarga ma’lumot qo‘shish (append) siz o‘ylagandek qimmatga tushmaydi.

Agar siz quyidagicha yozsangiz:

def build_response(acc, []) do
  acc
end
def build_response(acc, [h | t]) do
  build_response(<<acc::binary, h>>, t)
end

Siz buni $O(n^2)$ deb kutishingiz mumkin — har bir iteratsiya yangi binar yaratadi va hamma narsani nusxalaydi. Ammo BEAM bundan ham aqlliroq.

Binarlar o‘zgarmas (immutable) bo‘lganligi sababli, kompilyator agar acc avvalgi qo‘shish natijasida endigina yaratilgan bo‘lsa va unga boshqa hech qanday havola (reference) bo‘lmasa, to‘g‘ridan-to‘g‘ri o‘sha mavjud xotiraga yozish xavfsiz ekanligini isbotlay oladi. Birinchi qo‘shish biroz bo‘sh joy ajratadi, keyingi qo‘shishlar esa o‘sha joyga yoziladi. Natija nima? Har bir qo‘shish uchun amortizatsiyalangan $O(1)$ — xuddi C++ dagi std::vector ishlashi kabi.

Qayerda muammo bor? Agar binaringiz "qochib ketsa" (escape) — ya’ni u process dictionary’ga saqlansa, chaqiruvchiga qaytarilsa yoki boshqa narsaga qo‘shilsa — bayram tugaydi. Siz yana nusxalash (copying) bosqichiga qaytasiz.

Bu model binar protokollar bilan ishlashda hamma joyda uchraydi. DNS javoblarini iterativ ravishda qurayotganingizda, accumulator oqimini qisqa va aniq saqlash juda muhimdir.

Sub-binari: Tekin kesish (asosan)

Binarlarni moslashtirish (matching) BEAM "sub-binari" deb ataydigan narsani yaratadi — bular asl ma’lumotni nusxalamasdan, unga ishora qiluvchi kichik terminlardir. Agar siz quyidagicha yozsangiz:

<<Header:12/binary, Rest/binary>> = Packet

Hech qanday ma’lumot nusxalanmaydi. Rest shunchaki asl paket ichidagi "oyna"dir.

Lekin odamlarni chalg‘itadigan nozik jihat shundaki: siz rekursiv ravishda moslashtirishni amalga oshirganingizda, BEAM ichki ravishda moslash kontekstini (match context) saqlab qoladi, bu deyarli baytlarni aylanib o‘tuvchi ko‘rsatkich (cursor) kabi ishlaydi. Agar siz uni haqiqatda "qochib ketishiga" ruxsat bermasangiz (ya’ni uni qaytarmasangiz, saqlamasangiz yoki biror joyga o‘tkazmasangiz), u sub-binari shaklida materiallashmaydi.

Bu DNS parsing uchun juda muhim. Har bir so‘rov binar ko‘rinishida keladi, protokol tuzilmasiga moslanadi va javob ishlab chiqarishi kerak. Qachon siz yangi ish yaratyotganingizni yoki shunchaki ma’lumotni ko‘rayotganingizni tushunish — kengayuvchan (scalable) parser bilan yuklama ostida qiynaladigan parser o‘rtasidagi farqdir.

Nima uchun butun son (Integer) ko‘rinishi siz o‘ylagandan ko‘ra muhimroq

64-bitli BEAM’da butun sonlar o‘z turi belgisi (type tag) uchun bir nechta bitlarni egallaydi. Bu esa haqiqiy qiymat uchun 60 bit qoladi. Shu joyga sig‘adigan butun sonlar "kichik butun sonlar" (small integers) deb ataladi — ular jarayon registrlari ichida yashaydigan, heap’ga (xotira maydoniga) hech qachon tegmaydigan bevosita qiymatlardir.

Biroz kattaroq bo‘lgan har qanday narsa "bignum"ga aylanadi, bu esa heap ajratilishini va chiqindilarni yig‘ish (garbage collection) hisob-kitobini talab qiladi. Bu esoterik tuyulishi mumkin, lekin binar protokollar talab qiladigan bitlar bilan ishlashda bu juda muhim bo‘lib qoladi.

Ushbu texnika SWAR (SIMD Within A Register) deb ataladi — bir nechta qiymatlarni bitta butun songa jamlash, shunda siz CPU darajasida ular bilan parallel ravishda amallar bajara olasiz. DNS uchun bu har bir amalda ko‘plab baytlar hajmindagi ma’lumotni parsing qilishni anglatadi. Ammo bu faqat siz jamlagan qiymatlar "kichik butun son" diapazoniga sig‘sa ishlaydi.

Agar ular sig‘masa, siz nafaqat xotira ajratish xarajatlarini to‘laysiz, balki potentsial ravishda boshqacha holatda mavjud bo‘lmagan garbage collection sikllarini ham ishga tushirasiz. Soniyasiga millionlab so‘rovlar bo‘lganda, bu sikllar katta farq qiladi.

Bu sizning kodingiz uchun nima anglatadi?

Amaliy xulosa shuki: jiddiy unumdorlik yutuqlariga erishish uchun sizga NIFlar yoki C tiliga murojaat qilish shart emas. Siz BEAM ma’lumotga qanday qarayotganini tushunishingiz kerak.

Ichiga singib ketish kerak bo‘lgan bir nechta qoliplar:

1. Binar accumulatorlarni qisqa tuting. Faqat qo‘shishga (append-only) asoslangan sikllar sizning do‘stingizdir. Binar "qochib ketgan"idan so‘ng, xarajat modeli keskin o‘zgaradi.

2. Iloji bo‘lsa, joyida moslashtiring (match in place). Ma’lumotni nusxalash o‘rniga, uni ko‘rish uchun pattern matching’dan foydalaning. BEAM bunga moslashtirilgan.

3. Butun son o‘lchamlarini nazorat qiling. Arifmetik yoki bit manipulyatsiyasini bajarayotganda, qiymatlaringiz "kichik butun son" diapazonida qolishini hisobga oling.

4. Reduktsiyalar (reductions) bilan profillashni unutmang. BEAM ishlarni reduksiyalar (taxminan funksiya chaqiruvlari) ko‘rinishida rejalashtiradi. Kamroq funksiya chaqiruvida ko‘proq moslashtirishni amalga oshiradigan "issiq" sikl, scheduler (rejalashtiruvchi) nuqtai nazaridan kamroq ish bajaradi.

Binar protokollar bilan ishlaydigan tizimlarni qurayotgan har bir kishi uchun — xoh u DNS bo‘lsin, xoh WebSocket freymlari yoki maxsus protokol implementatsiyalari — bu qoliplar bevosita amal qiladi. BEAM sizga tezkor kod yozish uchun ajoyib vositalarni beradi, ammo ular faqat siz modelni tushunsangizgina foydali bo‘ladi.

Biz BEAM semantikasi haqida chuqurroq tushuncha bilan 90% foydani hech qanday murakkabliksiz olish mumkin bo‘lgan vaziyatlarda, jamoalar NIF yoki Rust NIFlarga murojaat qilganini ko‘rdik. Runtime (ishga tushirish muhiti) biz o‘ylaganimizdan ko‘ra aqlliroq — bizning vazifamiz esa unga o‘z imkoniyatlarini ko‘rsatishga imkon beradigan kod yozishdir.

NameOcean’da biz har doim keng ko‘lamli unumdorlik haqida o‘ylaymiz. Keyingi loyihangiz uchun Vibe Hosting’ni ishga tushirayotgan bo‘lishingizdan qat’i nazar yoki yuqori trafikli ilova uchun DNS’ni boshqarayotgan bo‘lishingizdan qat’i nazar, ushbu asoslarni tushunish sizga ishlar jadallashganda ham tez ishlaydigan tizimlarni qurishga yordam beradi.

Omadli kod yozishlar, binarlaringiz esa har doim samarali qo‘shilsin!

Read in other languages:

PL IT BG RU CS EL TR SV FI RO PT NB HU NL FR DE ES DA ZH-HANS EN