Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB

Yaqinda men sizga standart retseptlar yordamida qanday qilib aytdim SQL o'qish so'rovlarining ishlashini oshirish PostgreSQL ma'lumotlar bazasidan. Bugun biz qanday qilib haqida gaplashamiz yozib olish yanada samarali amalga oshirilishi mumkin ma'lumotlar bazasida konfiguratsiyada hech qanday "burilish" dan foydalanmasdan - shunchaki ma'lumotlar oqimini to'g'ri tashkil qilish orqali.

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB

#1. Bo'limlarni ajratish

Qanday va nima uchun uni tashkil qilish kerakligi haqida maqola amaliy bo'linish "nazariy" allaqachon bo'lgan, bu erda biz o'z doirasidagi ba'zi yondashuvlarni qo'llash amaliyoti haqida gapiramiz yuzlab PostgreSQL serverlari uchun monitoring xizmati.

"O'tgan kunlar ..."

Dastlab, har qanday MVP singari, bizning loyihamiz ham juda engil yuk ostida boshlandi - monitoring faqat o'nta eng muhim serverlar uchun amalga oshirildi, barcha jadvallar nisbatan ixcham edi... Ammo vaqt o'tishi bilan nazorat qilinadigan xostlar soni tobora ko'payib bordi. , va yana bir bor biz ulardan biri bilan nimadir qilishga harakat qildik 1.5 TB hajmdagi stollar, biz shunday yashashni davom ettirish mumkin bo'lsa-da, bu juda noqulay ekanligini angladik.

Vaqtlar deyarli epik davrlarga o'xshardi, PostgreSQL 9.x ning turli versiyalari tegishli edi, shuning uchun barcha qismlarga bo'linish "qo'lda" amalga oshirilishi kerak edi. jadval merosi va triggerlar dinamik bilan marshrutlash EXECUTE.

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB
Olingan yechim universal bo'lib chiqdi va uni barcha jadvallarga tarjima qilish mumkin edi:

  • Bo'sh "sarlavha" ota-jadval e'lon qilindi, unda hammasi tasvirlangan kerakli indekslar va triggerlar.
  • Mijoz nuqtai nazaridan yozuv "ildiz" jadvalida va ichki foydalanishda qilingan marshrutlash triggeri BEFORE INSERT yozuv zarur bo'limga "jismoniy" kiritildi. Agar hali bunday narsa bo'lmasa, biz istisnoga duch keldik va ...
  • … yordamida CREATE TABLE ... (LIKE ... INCLUDING ...) ota-jadvalning shabloni asosida yaratilgan kerakli sanada cheklov bilan bo'limshunday qilib, ma'lumotlar olinganda, o'qish faqat unda amalga oshiriladi.

PG10: birinchi urinish

Ammo meros orqali bo'linish tarixan faol yozish oqimi yoki ko'p sonli bolalar bo'limlari bilan ishlash uchun mos kelmagan. Masalan, kerakli bo'limni tanlash algoritmi borligini eslashingiz mumkin kvadratik murakkablik, u 100 dan ortiq bo'limlar bilan ishlashini o'zingiz tushunasiz ...

PG10-da bu holat qo'llab-quvvatlashni amalga oshirish orqali sezilarli darajada optimallashtirildi mahalliy bo'linish. Shuning uchun, biz uni saqlash joyini ko'chirgandan so'ng darhol qo'llashga harakat qildik, lekin...

Qo'llanmani o'rganib chiqqandan so'ng ma'lum bo'lishicha, ushbu versiyada tabiiy ravishda bo'lingan jadval:

  • indeks tavsiflarini qo'llab-quvvatlamaydi
  • undagi triggerlarni qo'llab-quvvatlamaydi
  • hech kimning "avlodi" bo'la olmaydi
  • qo'llab-quvvatlamang INSERT ... ON CONFLICT
  • bo'limni avtomatik ravishda yarata olmaydi

Rak bilan peshonaga og'riqli zarba berib, biz arizani o'zgartirmasdan qilish mumkin emasligini tushundik va keyingi tadqiqotlarni olti oyga qoldirdik.

PG10: ikkinchi imkoniyat

Shunday qilib, biz paydo bo'lgan muammolarni birma-bir hal qila boshladik:

  1. Chunki tetiklar va ON CONFLICT Biz ularga hali ham bu erda va u erda kerakligini aniqladik, shuning uchun biz ularni ishlab chiqish uchun oraliq bosqich qildik proksi-jadval.
  2. "Marshrutlash" dan xalos bo'ldim triggerlarda - ya'ni dan EXECUTE.
  3. Ular uni alohida olib ketishdi barcha indekslar bilan shablon jadvalishuning uchun ular hatto proksi-server jadvalida ham mavjud emas.

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB
Nihoyat, bularning barchasidan so'ng, biz asosiy jadvalni mahalliy ravishda ajratdik. Yangi bo'limni yaratish hali ham dasturning vijdoniga qoldiriladi.

"Arralash" lug'atlari

Har qanday tahliliy tizimda bo'lgani kabi, bizda ham bor edi "faktlar" va "kesishlar" (lug'atlar). Bizning holatlarimizda, ular bu lavozimda harakat qilishdi, masalan, shablon tanasi shunga o'xshash sekin so'rovlar yoki so'rovning o'zi.

"Faktlar" allaqachon kun bo'yi bo'lingan edi, shuning uchun biz eskirgan bo'limlarni xotirjamlik bilan o'chirib tashladik va ular bizni bezovta qilmadi (jurnallar!). Ammo lug'atlarda muammo bor edi...

Ularning ko'pi borligini aytmaslik kerak, lekin taxminan 100 TB "faktlar" natijasida 2.5 TB lug'at paydo bo'ldi. Bunday jadvaldan hech narsani qulay tarzda o'chira olmaysiz, uni etarli vaqt ichida siqib chiqolmaysiz va unga yozish asta-sekin sekinlashdi.

Lug'at kabi... unda har bir yozuv aynan bir marta taqdim etilishi kerak... va bu to'g'ri, lekin!.. Bizga hech kim to'sqinlik qilmayapti. har bir kun uchun alohida lug'at! Ha, bu ma'lum bir ortiqchalikni keltirib chiqaradi, lekin u quyidagilarga imkon beradi:

  • tezroq yozish/o'qish kichikroq bo'lim hajmi tufayli
  • kamroq xotira sarflaydi yanada ixcham indekslar bilan ishlash orqali
  • kamroq ma'lumotlarni saqlash eskirgan narsalarni tezda olib tashlash qobiliyati tufayli

Butun kompleks chora-tadbirlar natijasida CPU yuki ~30% ga, disk yuki ~50% ga kamaydi:

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB
Shu bilan birga, biz ma'lumotlar bazasiga xuddi shu narsani yozishni davom ettirdik, faqat kamroq yuk.

#2. Ma'lumotlar bazasi evolyutsiyasi va refaktoring

Shunday qilib, biz bor narsaga qaror qildik har bir kunning o'z bo'limi bor ma'lumotlar bilan. Aslida, CHECK (dt = '2018-10-12'::date) β€” va boΚ»lish kaliti va yozuvning maΚΌlum boΚ»limga tushishi sharti mavjud.

Bizning xizmatimizdagi barcha hisobotlar ma'lum bir sana kontekstida tuzilganligi sababli, "bo'linmagan vaqtlar" dan beri ular uchun indekslar barcha turdagi bo'lgan. (Server, sana, Reja shabloni), (Server, sana, Reja tugun), (sana, Xato sinfi, Server)...

Ammo endi ular har bir bo'limda yashaydilar sizning nusxalaringiz har bir bunday indeks ... Va har bir bo'lim ichida sana doimiy hisoblanadi...Ma'lum bo'lishicha, hozir biz har bir shunday indeksdamiz oddiygina doimiyni kiriting maydonlardan biri sifatida, bu uning hajmini ham, uni qidirish vaqtini ham oshiradi, lekin hech qanday natija bermaydi. Rakni o'zlariga qoldirdilar, ey...

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB
Optimallashtirish yo'nalishi aniq - oddiy barcha indekslardan sana maydonini olib tashlang bo'lingan jadvallarda. Bizning hajmlarimizni hisobga olsak, daromad taxminan 1TB/hafta!

Endi shuni ta'kidlaymizki, bu terabayt hali qandaydir tarzda yozilishi kerak edi. Ya'ni, biz ham disk endi kamroq yuklanishi kerak! Ushbu rasmda biz bir hafta bag'ishlagan tozalashdan olingan effekt aniq ko'rsatilgan:

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB

#3. Eng yuqori yukni "tarqatish"

Yuklangan tizimlarning katta muammolaridan biri bu ortiqcha sinxronizatsiya buni talab qilmaydigan ba'zi operatsiyalar. Ba'zan "ular sezmaganlari uchun", ba'zida "bu yo'l osonroq edi", lekin ertami-kechmi undan qutulish kerak.

Keling, oldingi rasmni kattalashtiramiz va bizda disk borligini ko'ramiz Ikki amplitudali yuk ostida "nasoslar" Qo'shni namunalar o'rtasida, bu kabi bir qator operatsiyalar bilan "statistik" bo'lmasligi kerak:

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB

Bunga erishish juda oson. Biz allaqachon monitoringni boshladik 1000 ga yaqin serverlar, har biri alohida mantiqiy ip tomonidan qayta ishlanadi va har bir ip ma'lum bir chastotada ma'lumotlar bazasiga yuboriladigan to'plangan ma'lumotni qayta tiklaydi, shunga o'xshash:

setInterval(sendToDB, interval)

Bu erda muammo aynan shu narsadadir barcha mavzular taxminan bir vaqtning o'zida boshlanadi, shuning uchun ularni yuborish vaqtlari deyarli har doim "nuqtaga" to'g'ri keladi. Voy β„–2...

Yaxshiyamki, buni tuzatish juda oson, "tasodifiy" yugurishni qo'shish vaqt bo'yicha:

setInterval(sendToDB, interval * (1 + 0.1 * (Math.random() - 0.5)))

#4. Biz kerakli narsani keshlaymiz

Uchinchi an'anaviy yuklama muammosi kesh yo'q u qayerda mumkin bo'lmoq.

Masalan, biz reja tugunlari bo'yicha tahlil qilish imkonini berdik (bularning barchasi Seq Scan on users), lekin darhol o'ylab ko'ring, ular ko'pincha bir xil - ular unutishdi.

Yo'q, albatta, ma'lumotlar bazasiga yana hech narsa yozilmaydi, bu bilan tetikni kesadi INSERT ... ON CONFLICT DO NOTHING. Ammo bu ma'lumotlar hali ham ma'lumotlar bazasiga etib boradi va bu kerak emas ziddiyatni tekshirish uchun o'qish qilish kerak. Voy β„–3...

Keshni yoqishdan oldin/keshlashdan keyin ma'lumotlar bazasiga yuborilgan yozuvlar sonidagi farq aniq:

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB

Va bu saqlash yukining tushishi:

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB

jami

"Kuniga terabayt" shunchaki qo'rqinchli ko'rinadi. Agar siz hamma narsani to'g'ri qilsangiz, bu shunchaki 2^40 bayt / 86400 soniya = ~12.5MB/sBu hatto ish stoli IDE vintlarini ham ushlab turadi. πŸ™‚

Ammo jiddiy ravishda, hatto kun davomida yukning o'n baravar "egilishi" bilan ham siz zamonaviy SSD-larning imkoniyatlarini osongina qondirishingiz mumkin.

Biz PostgreSQL-da sublight-da yozamiz: 1 xost, 1 kun, 1TB

Manba: www.habr.com

a Izoh qo'shish