Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB

Саяхан би стандарт жорыг ашиглан яаж хийхийг танд хэлсэн SQL унших асуулгын гүйцэтгэлийг нэмэгдүүлэх PostgreSQL мэдээллийн сангаас. Өнөөдөр бид хэрхэн яаж хийх талаар ярилцах болно бичлэгийг илүү үр дүнтэй хийх боломжтой Мэдээллийн санд тохиргоонд ямар ч "мушгиа" ашиглахгүйгээр - зүгээр л өгөгдлийн урсгалыг зөв зохион байгуулснаар.

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB

#1. Хэсэглэх

Үүнийг хэрхэн, яагаад зохион байгуулах нь зүйтэй вэ гэсэн нийтлэл "онолын хувьд" хэрэглээний хуваалт аль хэдийн байсан, энд бид өөрсдийн хүрээнд зарим арга барилыг ашиглах практикийн талаар ярих болно Олон зуун PostgreSQL серверүүдэд зориулсан хяналтын үйлчилгээ.

"Өнгөрсөн өдрүүд..."

Эхэндээ, ямар ч MVP-ийн нэгэн адил манай төсөл нэлээд хөнгөн ачааллын дор эхэлсэн - хяналт нь зөвхөн хамгийн чухал арван серверт хийгдсэн, бүх хүснэгтүүд харьцангуй авсаархан байсан ... Гэвч цаг хугацаа өнгөрөх тусам хянаж буй хостуудын тоо улам бүр нэмэгдсээр байв. , мөн бид дахин нэг нь ямар нэг зүйл хийхийг оролдсон 1.5TB хэмжээтэй ширээ, Хэдийгээр ингэж амьдрах боломжтой байсан ч энэ нь маш тохиромжгүй гэдгийг бид ойлгосон.

Цаг үе бараг л баатарлаг цаг үе шиг байсан, PostgreSQL 9.x-ийн өөр хувилбарууд хамааралтай байсан тул бүх хуваалтыг "гараар" хийх шаардлагатай байв. хүснэгтийн удамшил ба триггерүүд динамикаар чиглүүлэх EXECUTE.

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB
Үүний үр дүнд гарсан шийдэл нь бүх хүснэгтэд орчуулагдах боломжтой бүх нийтийнх болсон.

  • Хоосон "толгой" эх хүснэгтийг зарласан бөгөөд энэ нь бүгдийг тодорхойлсон шаардлагатай индексүүд болон триггерүүд.
  • Үйлчлүүлэгчийн үзэл бодлоос бичлэгийг "үндэс" хүснэгтэд хийж, дотооддоо ашигласан чиглүүлэлтийн гох BEFORE INSERT бичлэгийг шаардлагатай хэсэгт "бие махбодийн хувьд" оруулсан. Хэрэв тийм зүйл хараахан гараагүй байсан бол бид онцгой тохиолдол барьж, ...
  • … ашиглах замаар CREATE TABLE ... (LIKE ... INCLUDING ...) эх хүснэгтийн загвар дээр үндэслэн үүсгэсэн хүссэн огнооны хязгаарлалттай хэсэгИнгэснээр өгөгдлийг олж авах үед унших нь зөвхөн дотор нь хийгддэг.

PG10: анхны оролдлого

Гэхдээ өв залгамжлалаар хуваах нь идэвхтэй бичих урсгал эсвэл олон тооны хүүхдийн хуваалтуудтай ажиллахад түүхэндээ тохиромжгүй байсан. Жишээлбэл, шаардлагатай хэсгийг сонгох алгоритм нь байсныг санаж болно квадрат нарийн төвөгтэй байдал, энэ нь 100+ хэсэгтэй ажилладаг тул та өөрөө яаж гэдгийг ойлгож байна ...

PG10-д дэмжлэгийг хэрэгжүүлснээр энэ байдлыг ихээхэн оновчтой болгосон үндсэн хуваалт. Тиймээс бид агуулахыг шилжүүлсний дараа шууд хэрэглэхийг оролдсон боловч...

Гарын авлагыг судалсны дараа энэ хувилбар дахь үндсэн хуваалттай хүснэгт нь дараах байдалтай байна.

  • индексийн тайлбарыг дэмждэггүй
  • үүн дээрх триггерүүдийг дэмждэггүй
  • хэн нэгний “удам” байж болохгүй
  • дэмжихгүй байна INSERT ... ON CONFLICT
  • автоматаар хэсэг үүсгэх боломжгүй

Тармуураар духандаа хүнд цохилт өгсний дараа бид өргөдлийг өөрчлөхгүйгээр хийх боломжгүй гэдгийг ойлгож, цаашдын судалгааг зургаан сараар хойшлуулав.

PG10: хоёр дахь боломж

Тиймээс бид үүссэн асуудлуудыг нэг нэгээр нь шийдэж эхлэв.

  1. Учир нь өдөөгч ба ON CONFLICT Бидэнд эдгээр нь энд тэнд хэрэгтэй хэвээр байгааг олж мэдсэн тул тэдгээрийг боловсруулахын тулд завсрын үе шат хийсэн прокси хүснэгт.
  2. "чиглүүлэлт"-ээс салсан триггерүүдэд - өөрөөр хэлбэл, эхлэн EXECUTE.
  3. Тэд тусад нь гаргаж авсан бүх индекс бүхий загвар хүснэгтИнгэснээр тэд прокси хүснэгтэд ч байхгүй болно.

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB
Эцэст нь, энэ бүхний дараа бид үндсэн хүснэгтийг үндсэн байдлаар хуваав. Шинэ хэсэг үүсгэх нь програмын ухамсарт үлдсэн хэвээр байна.

"Хөрөөдөх" толь бичгүүд

Аливаа аналитик системийн нэгэн адил бидэнд ч бас байсан "баримт" ба "тайрах" (толь бичиг). Манай тохиолдолд тэд ийм үүрэг гүйцэтгэсэн, жишээлбэл, загвар бие ижил төстэй удаан асуулга эсвэл асуулгын текст өөрөө.

"Баримтуудыг" аль хэдийн өдөр болгон хуваасан тул бид хуучирсан хэсгүүдийг тайвнаар устгасан бөгөөд тэд бидэнд төвөг учруулаагүй (логууд!). Гэхдээ толь бичигт асуудал гарсан ...

Тэд маш олон байсан гэж хэлэхгүй, гэхдээ ойролцоогоор 100TB "баримт"-аас 2.5TB толь бичиг бий болсон. Ийм хүснэгтээс та ямар ч зүйлийг хялбархан устгаж чадахгүй, та үүнийг хангалттай хугацаанд шахаж чадахгүй, бичих нь аажмаар удааширч байна.

Толь бичиг шиг... түүн дотор оруулга бүрийг яг нэг удаа толилуулах ёстой... энэ нь зөв, гэхдээ!.. Бидэнд хэн ч саад болохгүй. өдөр бүр тусдаа толь бичиг! Тийм ээ, энэ нь тодорхой хэмжээний илүүдэл авчирдаг, гэхдээ энэ нь дараахь боломжийг олгодог.

  • хурдан бичих/унших жижиг хэсгийн хэмжээтэй холбоотой
  • санах ой бага зарцуулдаг илүү нягт индекстэй ажиллах замаар
  • бага өгөгдөл хадгалах хуучирсан зүйлийг хурдан арилгах чадвартайн улмаас

Бүхэл бүтэн цогцолбор арга хэмжээний үр дүнд CPU-ийн ачаалал ~30%-иар, дискний ачаалал ~50%-иар буурсан:

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB
Үүний зэрэгцээ бид өгөгдлийн санд яг ижил зүйлийг бичиж, ачаалал багатай үргэлжлүүлэв.

#2. Өгөгдлийн сангийн хувьсал ба рефакторинг

Тиймээс бид байгаа зүйлээ шийдсэн өдөр бүр өөрийн гэсэн хэсэгтэй өгөгдөлтэй. Үнэндээ, CHECK (dt = '2018-10-12'::date) — мөн хуваах түлхүүр болон бичлэгийг тодорхой хэсэгт оруулах нөхцөл байдаг.

Манай үйлчилгээний бүх тайлангууд нь тодорхой огнооны хүрээнд хийгдсэн байдаг тул "хуваагдаагүй цаг"-аас хойшхи индексүүд нь бүх төрлийн байна. (Сервер, Огноо, Төлөвлөгөөний загвар), (Сервер, Огноо, Төлөвлөгөөний зангилаа), (Огноо, Алдааны ангилал, Сервер), ...

Харин одоо тэд хэсэг бүр дээр амьдардаг таны хуулбарууд ийм индекс бүр ... Мөн хэсэг болгон дотор огноо нь тогтмол юм... Одоо бид ийм индекс бүрт байгаа нь харагдаж байна зүгээр л тогтмолыг оруулна уу талбаруудын нэг болох нь түүний эзлэхүүн болон хайлтын хугацааг хоёуланг нь нэмэгдүүлдэг боловч ямар ч үр дүнд хүргэдэггүй. Тэд тармуурыг өөрсөддөө үлдээсэн, өө...

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB
Оновчлолын чиглэл нь ойлгомжтой - энгийн бүх индексээс огнооны талбарыг устгах хуваалттай хүснэгтүүд дээр. Бидний эзлэхүүнийг авч үзвэл ашиг нь ойролцоогоор байна 1ТБ/долоо хоног!

Энэ терабайтыг ямар нэгэн байдлаар бүртгэх шаардлагатай байсныг одоо тэмдэглэе. Энэ нь бид ч гэсэн диск одоо бага ачаалалтай байх ёстой! Энэ зураг нь бидний долоо хоног зарцуулсан цэвэрлэгээний үр нөлөөг тодорхой харуулж байна.

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB

#3. Оргил ачааллыг "тархаж" байна

Ачаалал ихтэй системүүдийн нэг том бэрхшээл бол илүүдэл синхрончлол үүнийг шаарддаггүй зарим үйлдлүүд. Заримдаа "тэд анзаараагүй учраас", заримдаа "энэ нь илүү хялбар байсан" ч эрт орой хэзээ нэгэн цагт та үүнийг арилгах хэрэгтэй.

Өмнөх зургийг томруулж үзээд диск байгаа эсэхийг харцгаая Давхар далайцтай ачааллын дор "шахдаг" Зэргэлдээх дээжүүдийн хооронд ийм олон тооны үйлдлүүд "статистикийн хувьд" тохиолдох ёсгүй:

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB

Үүнд хүрэхэд нэлээд хялбар байдаг. Бид аль хэдийн хяналт тавьж эхэлсэн бараг 1000 сервер, тус бүр нь тусдаа логик хэлхээгээр боловсруулагддаг бөгөөд урсгал бүр нь тодорхой давтамжтайгаар мэдээллийн сан руу илгээгдэх хуримтлагдсан мэдээллийг дахин тохируулдаг.

setInterval(sendToDB, interval)

Энд байгаа асуудал нь яг үүнд л оршдог бүх хэлхээ ойролцоогоор ижил цагт эхэлдэг, тиймээс тэдний илгээх цаг бараг үргэлж "цэг рүү" давхцдаг. Өө №2...

Аз болоход үүнийг засахад маш хялбар, "санамсаргүй" гүйлтийг нэмж байна цаг хугацааны хувьд:

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

#4. Бид хэрэгцээтэй зүйлээ хадгалдаг

Гурав дахь уламжлалт ачаалал ихтэй асуудал юм кэш байхгүй тэр хаана байна чадна байх.

Жишээлбэл, бид төлөвлөгөөний зангилааны хувьд дүн шинжилгээ хийх боломжтой болгосон (эдгээр бүх Seq Scan on users), гэхдээ тэр даруйдаа тэд ихэнх тохиолдолд адилхан гэж бодоод мартжээ.

Үгүй ээ, мэдээжийн хэрэг, мэдээллийн санд дахин юу ч бичихгүй, энэ нь гохыг таслана INSERT ... ON CONFLICT DO NOTHING. Гэхдээ энэ өгөгдөл нь мэдээллийн санд хүрсэн хэвээр байгаа бөгөөд энэ нь шаардлагагүй юм зөрчил байгаа эсэхийг шалгахын тулд уншина уу хийх ёстой. Өө №3...

Кэшийг идэвхжүүлэхээс өмнө/дараа нь мэдээллийн санд илгээсэн бичлэгийн тооны ялгаа нь тодорхой байна.

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB

Энэ нь хадгалах ачааллын дагалддаг бууралт юм:

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB

Нийт

"Өдөрт терабайт" гэдэг нь аймшигтай сонсогдож байна. Хэрэв та бүх зүйлийг зөв хийвэл энэ нь зүгээр л юм 2^40 байт / 86400 секунд = ~12.5MB/sТэр ч байтугай ширээний IDE эрэг хүртэл барьсан. 🙂

Гэхдээ нухацтай хэлэхэд, өдрийн цагаар ачааллыг арав дахин "тазайлгасан" ч гэсэн та орчин үеийн SSD-ийн чадварыг хялбархан хангаж чадна.

Бид PostgreSQL дээр дэд зүйл дээр бичдэг: 1 хост, 1 өдөр, 1 TB

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх