Engineering Notes
2.6K subscribers
166 photos
2 videos
5 files
229 links
Kanalda asosan backend engineeringga oid postlar yozib boriladi.

Ba'zi postlarda xatoliklar bor.
Postlar foydali bo’lgan bo’lsa adminni duo qilib qo’ying. Rahmat.

Contact: @Bobosher_Musurmonov
LinkedIn: https://www.linkedin.com/in/bobosher-musurmonov
Download Telegram
Forwarded from Bobosher Musurmonov
#javob
MemoryError dasturingiz ishlashi uchun RAM yetmay qolganda sodir bo'ladi. Hozir siz katta ehtimol bilan katta hajmdagi ma'lumotlarni to'g'ri pythonga chiqarib(bunda ma'lumot to'liq RAMda saqlanib turadi) ishlashga harakat qilayapsiz. Bu biror fayl yoki database bo'lishi mumkin.
Yaxshisi, hamma ma'lumotni bittada olmasdan, bir qismini olib, u bilan ishlab bo'lgach, xotirani bo'shatib keyingi qismga o'tib va h.k. ishlang.
Forwarded from Bobosher Musurmonov
#javob

GIL nima va nega kerakligini tushunish uchun concurrency nima, lock nima, nega kerak, dead lock nima, qanday oldini olish mumkin va h.k. lar haqida ozgina ma'lumot olish kerak.

Concurrency bu bir nechta thread(oqim)larning bitta processorda ishlashi. Umuman olganda, threadlar processorda juda kichik instructionlarga ajratilib(Assemblyga o'xshash), navbatma-navbat bajariladi. Bu instruksiyalar juda kichkina bo'lgani va processor bir soniyada bunaqa instruksiyalardan milliardlab bajargani uchun bizga xuddi bir vaqtda ishlayotgandek taassurot qoldiradi.

Concurrency paytida ba'zi o'zgaruvchilarni ikkita thread bir vaqtda o'zgartirishi, buning orqasidan noto'g'ri natijalar kelib chiqishi mumkin(masalan, a=0 o'zgaruvchiga 2 marta 1 qo'shib, natija 1 chiqishi mumkin). Mana bu race condition deyiladi.

Race conditionning oldini olishning bir usuli sifatida lock o'ylab topilgan. Lockning ishlashi quyidagicha: biror thread biror o'zgaruvchining qiymatini o'zgartirmoqchi bo'lgan paytda uni "qulflab" qo'yadi. Shunda o'zgaruvchini bir vaqtda faqat bitta thread o'zgartira oladi. Bu qiymatni olmoqchi bo'lgan boshqa thread qulf ochilishini kutib, ochilgandan keyin yangi qiymatni olib ishlataveradi.

Lock juda yaxshi yechim, lekin bitta jiddiy muammosi bor. Deylik, bitta thread a o'zgaruvchini "lock" qilgan va b ning qiymatini olmoqchi. Ikkinchi thread b ni "lock" qilgan va a ning qiymatini olmoqchi. Shunda ikkita thread yopiq sikl hosil qilib bir-birini qulflab qo'yadi. Bu esa dastur o'sha joyda "tiqilib qolishi"ga olib keladi. Mana bu holat "dead lock" deyiladi.

Pythonda xotira boshqaruvi avtomatik bajariladi. Ya'ni qaysidir qiymat ishlatilmasa, python uni avtomatik aniqlab, xotiradan bo'shatadi. Buni amalga oshirish uchun python reference count degan narsadan foydalanadi. Sodda qilib aytganda, o'sha qiymatdan necha kishi foydalanayotganini sanab turadi. O'sha raqam 0 ga tushganda(demak, hech kim ishlatmayapti) garbage collector o'sha qiymatni xotiradan o'chiradi.

Race condition hamma joyda sodir bo'lishi mumkin. Shu jumladan reference countda ham. Lekin bu yerda sodir bo'lsa kerakli ma'lumotlar o'chib ketishi yoki keraksiz ma'lumot xotirada qolib ketishi kabi muammolar kelib chiqadi. Buning oldini olish uchun Python reference count uchun ham lock ishlatadi. Lekin yuqorida aytilganidek, dead lock muammosini ham hisobga olish kerak. Shuning uchun Python hamma uchun bitta GIL(Global Interpreter Lock) ishlatadi. Bu ham oddiy lock kabi ishlaydi, lekin u interpreterda saqlanadi. Qaysidir thread biror o'zgaruvchini o'zgartirmoqchi bo'lsa interpreter GILni o'sha threadga vaqtinchalik berib turadi. Thread esa undan o'zgaruvchini emas, uning qiymatidagi reference countni qulflashda foydalanadi. Ishini tugatib bo'lgach, u GILni yana interpreterga qaytaradi va interpreter GILni boshqa threadga beradi...
Butun interpreterda bitta GIL bo'lgani uchun dead lock sodir bo'lmaydi. Sababi, qulf bitta, hech kim bir-birini qulflab qo'ymaydi.

Demak, GIL bizning dasturimizdagi o'zgaruvchilar bilan bo'ladigan race conditionning oldini olish uchun emas, Pythonning ichki, xotira boshqaruv tizimi to'g'ri ishlashi uchun xizmat qiladi.
👍5
Engineering Notes
#savol database_sync_to_async(Profile.objects.get)(user=user) Nega user=user ni get dan tashqarida yozildi?
#javob

Sababi, bu argumentni get() methodining ichiga yozsangiz get() methodi ishga tushadi va database_sync_to_async() bu funksiyadan qaytgan return valuega qarab ishlaydi.

Argumentlarni get() methodidan tashqarida bersangiz esa database_sync_to_async() funksiyasi mana shu methodni parameter sidatida oladi(sababi, u hali ishlamadi, funksiya holida turibdi) va async functionga o'tkazib beradi. Hosil bo'lgan yangi funksiyaga esa parameterlar beriladi.

Bu xuddi decoratorga o'xshash, aniqrog'i, decorator.
👍6
#javob

Python interpreted language bo'lsa-da, unda ham compilingga o'xshash jarayon bo'ladi.
Avval to'liq source code bytecode deb ataluvchi instruksiyalar ketma-ketligiga o'tkazib chiqiladi.
Bu instruksiyalarni esa Python virtual machine (biz bilgan python interpreter) olib, uni execute qiladi.

Odatda, bytecode __pycache__ folderining ichidagi .pyc fayllarga yozib qo'yiladi. Xuddi shu dastur keyingi safar run qilinganda esa Python kodni yana bytecodega o'tkazib chiqmasdan, tayyor turgan bytecodeni ishlatadi. Natijada tezlik oshadi. Har safar fayllardan o'zgarish bo'lganda ular yana qaytadan bytecodega o'tkaziladi. Lekin bu ba'zida sodir bo'lmasligi mumkin va natijada kodni o'zgartirsangiz ham, eski kod run bo'laveradi.
👍6
#javob

It includes non-index column values to the actual index (b-tree).

Let's say you have a table named "users" with id, name and a bunch of other columns.
If you include name column in the index on id field:
CREATE INDEX
idx_user_id_include_name
ON users(id)
INCLUDE name;

Each time you query that uses this index and only asks for the columns on the index:
SELECT id, name 
FROM users
WHERE id = 1;
PostgreSQL doesn't necessarily go to the actual table after finding the required row, since it can find both id and name field on the index. This is called index-only scan.

If you query some other columns (let's say age), PostgreSQL first finds the required row id from the index and go to that row on the table to get age value, since it's not presented on the index. Searching on the index and fetching from the actual table. This is called index scan.
👍2
Engineering Notes
#savol Djangoda fayllarni to'g'ridan-to'g'ri DBda saqlash mumkinmi? Buning qanday kamchiliklari bor? *qisqartirildi
#javob

Django default holatda fileni DBga yuklamaydi. Bu uchun alohida file system ishlatadi. Ya'ni mediafilelar serverda(yoki cloudda) ko'rsatilgan biror directoryda saqlanadi va DBda faqat o'sha files olib boradigan path saqlanadi. Client fileni so'raganda esa DB fileni bermasdan, uning turgan joyini ko'rsatib, "faylni o'sha yerdan topasan" deydi. File aytilgan joydan topilmasa, DB aybni bo'yniga olmaydi ))

Siz so'rayotgan narsa esa BLOB deyiladi, ya'ni katta fileni to'g'ridan to'g'ri DBda saqlash(aslini olganda, bunda ham file tableda saqlanmaydi).
BinaryField orqali djangoda ham BLOB sifatida ishlatishingiz mumkin.

BLOBning men biladigan kamchiliklari:
— Nisbatan sekin. File "cherez baza" uzatiladi.
— Katta filelarni backup qilish qiyin.
— Cache qilish qiyin.

Lekin masalan, softwareni boshqa serverga migrate qilayotganda juda qo'l keladi.
👍5
Engineering Notes
Photo
#javob

Connectionni MainDB objectni initialize qilayotganda ochmang.
Hozir siz MainDBdan object olganda connection ochayapsiz.
Bir method orqali query yuborganda with context manager orqali connectiondan foydalanib, keyin uni yopib chiqib ketayapsiz.
Keyingi safar query yubormoqchi bo'lganingizda connection yopilgani sabab error berayapti.

Yoki har bitta query uchun alohida connection ishlating, yoki (agar bitta connectionni doim ishlatmoqchi bo'lsangiz) with ishlatmang, sababi u kod execute bo'lganidan keyin connectionni yopadi.
👍5
Engineering Notes
#savol FastAPI nima? U ham REST APIning bir qismimi? Ikkalasining farqi nima?
#javob

Tushunarliroq qilishga harakat qilaman:

Bilasiz, API (boshlanishiga, faqat web APIlar haqida gaplashamiz) bizga ikki xil dastur/application orasida ma'lumot almashish uchun kerak. Masalan, frontend backend bilan ma'lumot almashishi uchun API ishlatamiz.

API ishlatish uchun esa ikkala taraf ham tushunadigan usulda ma'lumot almashish kerak. Masalan, siz Xitoy tilini bilmaysiz, u esa O'zbek tilini bilmaydi. Lekin ikkalangiz ham ingliz tilini bilsangiz bir-biringiz bilan gaplasha olasizlar.

Qaysi tilda va qanday usulda, qanday qoidalar asosida "gaplashish"ga qarab API ko'plab turlarga bo'linadi.

Web APIlar orasida eng keng tarqalgan turlaridan biri REST turidagi APIlar. RESTda ma'lumot almashish uchun JSON formatidan foydalaniladi. Va ma'lumotlarni qanday ko'rsatish va hokazo kabi bir qancha qoidalarni o'z ichiga oladi.
E'tibor bering, REST aynan bir dastur emas, balki API turi, aniqrog'i, qoidalar to'plami. Shu qoidalar asosida ishlaydigan APIlar esa REST API deyiladi.

Web uchun ishlatiladigan ko'plab dasturlash tillarida REST APIlar qurish va ulardan foydalana olish uchun texnologiyalar qurilgan. Pythonda ham bu bo'yicha yetarlicha librarylar bor.

Django standart holatda server-side renderingdan foydalanadi, REST API ishlatmaydi. Lekin Django bilan REST API qurish uchun Django REST Framework (DRF) nomni library(balki, framework, anig'ini bilmayman) bor. Qisqasi, u djangoda API qurish uchun "adapter" sifatida ishlaydi.

Boshqa python frameworklar esa standart holatda REST APIlar bilan ishlay oladi. Bulardan eng mashhurlari esa Flask va FastAPI. Ya'ni bular REST qoidalaridan foydalangan holda API qura oladigan frameworklar.

REST yagona web API turi emas. Yana eng mashhurlaridan GraphQL nomli API turi bor.
👍18
Forwarded from Engineering Notes
Engineering Notes
#savol FastAPI nima? U ham REST APIning bir qismimi? Ikkalasining farqi nima?
#javob

Tushunarliroq qilishga harakat qilaman:

Bilasiz, API (boshlanishiga, faqat web APIlar haqida gaplashamiz) bizga ikki xil dastur/application orasida ma'lumot almashish uchun kerak. Masalan, frontend backend bilan ma'lumot almashishi uchun API ishlatamiz.

API ishlatish uchun esa ikkala taraf ham tushunadigan usulda ma'lumot almashish kerak. Masalan, siz Xitoy tilini bilmaysiz, u esa O'zbek tilini bilmaydi. Lekin ikkalangiz ham ingliz tilini bilsangiz bir-biringiz bilan gaplasha olasizlar.

Qaysi tilda va qanday usulda, qanday qoidalar asosida "gaplashish"ga qarab API ko'plab turlarga bo'linadi.

Web APIlar orasida eng keng tarqalgan turlaridan biri REST turidagi APIlar. RESTda ma'lumot almashish uchun JSON formatidan foydalaniladi. Va ma'lumotlarni qanday ko'rsatish va hokazo kabi bir qancha qoidalarni o'z ichiga oladi.
E'tibor bering, REST aynan bir dastur emas, balki API turi, aniqrog'i, qoidalar to'plami. Shu qoidalar asosida ishlaydigan APIlar esa REST API deyiladi.

Web uchun ishlatiladigan ko'plab dasturlash tillarida REST APIlar qurish va ulardan foydalana olish uchun texnologiyalar qurilgan. Pythonda ham bu bo'yicha yetarlicha librarylar bor.

Django standart holatda server-side renderingdan foydalanadi, REST API ishlatmaydi. Lekin Django bilan REST API qurish uchun Django REST Framework (DRF) nomni library(balki, framework, anig'ini bilmayman) bor. Qisqasi, u djangoda API qurish uchun "adapter" sifatida ishlaydi.

Boshqa python frameworklar esa standart holatda REST APIlar bilan ishlay oladi. Bulardan eng mashhurlari esa Flask va FastAPI. Ya'ni bular REST qoidalaridan foydalangan holda API qura oladigan frameworklar.

REST yagona web API turi emas. Yana eng mashhurlaridan GraphQL nomli API turi bor.
👍15
#savol
Why HTTP/3 uses UDP instead of TCP?

#javob
I think the main reason why HTTP/3 (which uses QUIC) is built on top of UDP instead of TCP is to solve the problem with lost packets in HTTP/2.

One of the biggest problems with h2 is that streams (a logical communication for a single request) are not fully independent from each other. Since the TCP retransmission works on layer 4 of the OSI model but h2 itself is implemented on layer 7, the TCP connection has no knowledge of h2 streams. So if a single TCP packet is missing in one of the streams, TCP blocks the entire connection (thus, all the streams on it) till the missing packet is retransmitted successfully.
That means, if I try to send 10 request at the same time over h2 and if any of them fails to reach, all 10 requests are blocked. This is called HOL blocking, but on the transport layer.

HTTP/3 solves this problem by using QUIC, which is built on top of UDP. Since UDP does not guarantee delivery of data, it has no retransmission mechanism. QUIC has its own recovery mechanism that guarantees delivery. Unlike TCP, this recovery mechanism works on the same layer as the QUIC streams and knows which packet belongs to which stream. That's why if any packet is lost, the recovery mechanism blocks only the stream that packet belongs to. It does not affect other streams.
👍5
Forwarded from Engineering Notes
#javob

It includes non-index column values to the actual index (b-tree).

Let's say you have a table named "users" with id, name and a bunch of other columns.
If you include name column in the index on id field:
CREATE INDEX
idx_user_id_include_name
ON users(id)
INCLUDE name;

Each time you query that uses this index and only asks for the columns on the index:
SELECT id, name 
FROM users
WHERE id = 1;
PostgreSQL doesn't necessarily go to the actual table after finding the required row, since it can find both id and name field on the index. This is called index-only scan.

If you query some other columns (let's say age), PostgreSQL first finds the required row id from the index and go to that row on the table to get age value, since it's not presented on the index. Searching on the index and fetching from the actual table. This is called index scan.
👍13