2 คะแนน โดย GN⁺ 2024-01-19 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • GOV.UK Notify ย้ายฐานข้อมูล PostgreSQL 11 ขนาด 400GB ไปยัง PostgreSQL 15 RDS ในบัญชี AWS ของตนเองตามการยุติ PaaS โดยลด downtime เหลือประมาณ 11 วินาที
  • สร้างเฉพาะตารางในฐานข้อมูลปลายทางก่อน แล้วคัดลอกข้อมูลด้วย DMS full load จากนั้นจึงค่อยใช้ดัชนีและข้อจำกัดของคีย์ภายหลัง เพื่อลดเวลาการโหลดข้อมูลปริมาณมาก
  • ฐานข้อมูลต้นทางมีประมาณ 1.3 พันล้านแถว, 85 ตาราง, 185 ดัชนี และ 120 foreign key โดยในวันทำงานมีการ insert/แก้ไขประมาณ 1,000 รายการต่อวินาที และมีการอ่านในจำนวนใกล้เคียงกัน
  • เนื่องจากมีข้อจำกัดที่การ redeploy แอปพลิเคชันใช้เวลาประมาณ 5 นาที จึงเตรียม credentials เดียวกันและการสลับ Route53 DNS แบบ weighted ไว้ล่วงหน้า เพื่อลดเวลาสลับจริง
  • DMS ถูกเลือกเพราะได้รับการสนับสนุนจากทั้ง PaaS และ AWS ได้ง่าย แต่สำหรับการย้ายระหว่าง PostgreSQL ด้วยกัน ยังมีความเป็นไปได้ว่าเครื่องมือทางเลือกอย่าง pglogical อาจเรียบง่ายกว่า

การย้ายฐานข้อมูล Notify ตามการยุติ PaaS

  • GOV.UK Notify ถูกโฮสต์อยู่บน GOV.UK Platform as a Service และเมื่อ PaaS จะยุติบริการ จึงต้องย้ายโครงสร้างพื้นฐานทั้งหมดไปยังบัญชี AWS ของตนเอง
  • ฐานข้อมูลของ Notify คือ AWS RDS PostgreSQL ที่อยู่ในบัญชี AWS ของ PaaS โดยเก็บข้อมูลตั้งแต่ข้อมูลการส่งการแจ้งเตือน ไปจนถึงเนื้อหา template หลายแสนรายการที่ทีมบริการต่าง ๆ ใช้
  • ในการย้าย แยกฐานข้อมูลเดิมเป็น source database และฐานข้อมูลใหม่เป็น target database
  • ความท้าทายหลักไม่ใช่การสร้างฐานข้อมูล PostgreSQL ใหม่ แต่คือการ ลด downtime ให้เหลือน้อยที่สุด ระหว่างการย้ายข้อมูลทั้งหมดและเปลี่ยนปลายทางการเชื่อมต่อของแอปพลิเคชัน

ขนาดฐานข้อมูลต้นทางและข้อจำกัดของบริการ

  • ฐานข้อมูลต้นทางคือ PostgreSQL 11 ขนาดประมาณ 400GB
    • ประมาณ 1.3 พันล้านแถว
    • 85 ตาราง
    • 185 ดัชนี
    • 120 foreign key
  • ในวันทำงานทั่วไป มีการ insert หรือแก้ไขประมาณ 1,000 รายการต่อวินาที และมีการอ่านในจำนวนใกล้เคียงกัน
  • GOV.UK Notify ส่งการแจ้งเตือนสำคัญและต้องทันเวลา เช่น คำเตือนน้ำท่วมและสถานะการดำเนินการสมัครหนังสือเดินทาง วันละหลายล้านรายการ
  • เนื่องจากการส่งการแจ้งเตือนทั้งหมดต้องเข้าถึงฐานข้อมูล จึงจำเป็นต้องรักษาเวลาหยุดให้สั้น

โครงสร้างการโหลดเริ่มต้นและ replication ต่อเนื่องด้วย DMS

  • ทีม PaaS มีแนวทางการย้ายฐานข้อมูลโดยใช้ AWS Database Migration Service
  • DMS ทำหน้าที่ย้ายข้อมูลจากฐานข้อมูลต้นทางไปยังฐานข้อมูลปลายทาง และสามารถรันได้ทั้งในบัญชี AWS ต้นทางหรือปลายทาง
  • งานของ DMS แบ่งเป็นสองขั้นตอน
    • full load: คัดลอกข้อมูลทั้งหมดที่มีอยู่ถึงจุดเวลาหนึ่งเป็นรายตาราง
    • replication ต่อเนื่อง: replay transaction ใหม่จากฐานข้อมูลต้นทางลงในฐานข้อมูลปลายทาง เพื่อซิงก์ฐานข้อมูลทั้งสอง
  • งานสลับให้แอปพลิเคชันใช้ฐานข้อมูลปลายทางแทนฐานข้อมูลต้นทางเป็นหน้าที่ของทีม Notify เอง

การเตรียมฐานข้อมูลปลายทางและ full load

  • สร้าง DMS instance ในบัญชี AWS ต้นทาง
    • ทีม PaaS ตั้งค่า DMS instance ไว้ในบัญชีแล้ว จึงเตรียมได้รวดเร็ว
    • DMS instance ต้องมี credentials ที่เชื่อมต่อได้ทั้งฐานข้อมูล PostgreSQL ต้นทางและปลายทาง
  • เนื่องจาก DMS instance และฐานข้อมูลปลายทางอยู่คนละ VPC จึงตั้งค่า VPC peering เพื่อให้ทราฟฟิก DMS จาก VPC ของ PaaS ถูก route มายัง VPC ของตนเองโดยไม่ผ่านอินเทอร์เน็ตสาธารณะ
  • สร้าง target RDS instance ในบัญชี AWS ของตนเอง และเนื่องจากใกล้ถึงเวลาสิ้นสุดการสนับสนุน PostgreSQL 11 จึงตั้งค่าฐานข้อมูลใหม่เป็น PostgreSQL 15
  • ใช้ pg_dump dump schema ของฐานข้อมูลต้นทางเพื่อสร้างไฟล์ SQL สำหรับสร้าง schema ใหม่ และในตอนแรกใช้เฉพาะ declaration ของตารางกับฐานข้อมูลปลายทาง
  • ไม่ใช้ foreign key ในช่วง full load
    • เพราะ DMS full load ไม่ได้คัดลอกข้อมูลตามลำดับที่สอดคล้องกับข้อจำกัด foreign key
  • ไม่สร้าง primary key และดัชนีก่อน full load เช่นกัน
    • เพราะทุกการ insert จะต้องอัปเดตดัชนี ทำให้เวลารวมเพิ่มขึ้นมากเมื่อใส่ข้อมูลหลายพันล้านแถว
    • วิธีที่เร็วกว่า คือคัดลอกข้อมูลทั้งหมดก่อน แล้วค่อยเพิ่มดัชนี
  • งาน full load คัดลอกข้อมูลที่มีอยู่ ณ ตอนกดปุ่มเริ่ม
    • ข้อมูลใหม่หรือการอัปเดตที่เกิดหลังจากนั้นจะไม่รวมอยู่ใน full load
    • full load ใช้เวลาประมาณ 6 ชั่วโมง จึงเสร็จ
  • หลัง full load จึงใช้ไฟล์ schema ส่วนที่เหลือเพื่อเพิ่มดัชนีและข้อจำกัดของคีย์ โดยงานนี้ใช้เวลาประมาณ 3 ชั่วโมง

รักษา replication ไว้ 10 วันก่อนสลับทราฟฟิก

  • หลัง full load เสร็จ ฐานข้อมูลปลายทางตรงกับข้อมูลในฐานข้อมูลต้นทาง ณ เวลาเริ่ม full load แต่หลังจากนั้นยังมีการ insert, แก้ไข และลบเกิดขึ้นต่อเนื่องในต้นทาง
  • เริ่มงาน replication ต่อเนื่องของ DMS หรือ change data capture เพื่อส่ง transaction จาก transaction log ของฐานข้อมูลต้นทางที่เกิดหลังเวลาเริ่ม full load ไปยังฐานข้อมูลปลายทาง
  • กระบวนการ replication ใช้เวลาหลายชั่วโมงในการตามให้ทัน หลังจากนั้นจึงตรวจสอบสถานะซิงก์ด้วยการมอนิเตอร์ค่า replication lag ของ DMS
  • DMS replication รันอยู่เบื้องหลังประมาณ 10 วัน และซิงก์ฐานข้อมูลทั้งสองจนถึงเวลาย้ายทราฟฟิกที่แจ้งผู้ใช้ไว้ล่วงหน้า
  • ขั้นตอนสลับทราฟฟิกถูกเขียนเป็น Python script ไว้ล่วงหน้า
    • หยุดทราฟฟิกของแอปพลิเคชันที่ไปยังฐานข้อมูลต้นทาง
    • ตรวจสอบว่า replication ตามทันทั้งหมดแล้ว
    • อนุญาตให้แอปพลิเคชันเชื่อมต่อฐานข้อมูลปลายทาง
  • ต้องหลีกเลี่ยงสภาวะที่แอปพลิเคชันบางส่วนใช้ DB ต้นทาง และส่วนที่เหลือใช้ DB ปลายทาง
    • เพราะการเปลี่ยนแปลงที่เกิดใน DB ปลายทางจะไม่ถูกสะท้อนกลับไปยัง DB ต้นทาง ซึ่งอาจทำให้ผู้ใช้เห็นข้อมูลไม่สอดคล้องกัน
  • script ถูกออกแบบให้ชัดเจน ทำซ้ำได้ และทำงานเร็วกว่า manual operation และถูกใช้ในการทดสอบและซ้อมล่วงหน้าอย่างน้อย 40 ครั้ง
  • downtime เป้าหมายคือ ต่ำกว่า 5 นาที และกำหนดเวลามigration เป็นช่วงเย็นวันเสาร์ที่ค่อนข้างเงียบ โดยหลีกเลี่ยงช่วงกลางดึก

การสลับ DNS ที่ทำให้ downtime เหลือ 11 วินาที

  • การหยุดทราฟฟิกไปยังฐานข้อมูลต้นทางทำโดยเรียก pg_terminate_backend กับ connection ของแอปพลิเคชัน และใช้เวลาน้อยกว่า 1 วินาที
  • เปลี่ยนรหัสผ่านผู้ใช้ PostgreSQL ด้วย เพื่อไม่ให้แอปพลิเคชันเชื่อมต่อกลับไปยัง DB ต้นทางได้ โดยให้เกิด authentication error เมื่อ reconnect
  • DMS สร้างตารางสถานะ replication ในฐานข้อมูลปลายทางและอัปเดตทุกนาที โดย migration script ใช้ตารางนี้ตรวจสอบ lag ระหว่างต้นทางและปลายทาง
  • เป็นมาตรการความปลอดภัยเพิ่มเติม หลังจากแอปพลิเคชันหยุดเข้าถึง DB ต้นทางแล้ว script จะเขียน record เดี่ยวลงใน DB ต้นทางและรอจนกว่าจะมาถึง DB ปลายทาง
  • ข้อมูลการเชื่อมต่อฐานข้อมูลของแอปพลิเคชันถูกส่งผ่าน environment variable SQLALCHEMY_DATABASE_URI
    • รูปแบบเดิมคือ postgresql://...@random-identifier.eu-west-1.rds.amazonaws.com:5432 ซึ่งมี username, password และตำแหน่ง RDS
    • หากต้องเปลี่ยนตำแหน่งฐานข้อมูลหรือ credentials จะต้อง redeploy แอปพลิเคชัน และการ redeploy ใช้เวลาประมาณ 5 นาที
  • เพื่อหลีกเลี่ยง downtime เพิ่มจากการ redeploy จึงเตรียมสองอย่างก่อน migration
    • สร้างผู้ใช้ที่มี username และ password เหมือนกันในฐานข้อมูลต้นทางและปลายทาง
    • สร้าง DNS record database.notifications.service.gov.uk ใน AWS Route53 และตั้ง TTL เป็น 1 วินาที
  • DNS record เริ่มต้นด้วย weight ไปต้นทาง 100% และปลายทาง 0%
  • เปลี่ยน URI ของแอปพลิเคชันไว้ล่วงหน้าให้ใช้ username/password ร่วมกันและชื่อโดเมนใหม่
  • ตอนสลับจริง script จะเปลี่ยน DNS weight ของ AWS ไปยังปลายทาง 100% และรอให้ TTL 1 วินาทีหมดอายุ
  • ณ เวลาสลับในช่วงเย็นวันเสาร์ที่ 4 พฤศจิกายน 2023 lag ระหว่างฐานข้อมูลปลายทางและต้นทางอยู่ในระดับไม่กี่วินาที
  • ผลจากการรัน migration script คือแอปพลิเคชันหยุดเข้าถึง DB ต้นทางและเริ่มใช้ DB ปลายทางใหม่ โดย downtime อยู่ที่ประมาณ 11 วินาที

การประเมินการเลือก DMS และงานต่อไป

  • DMS ถูกเลือกเพราะ GOV.UK PaaS รองรับได้ดีและสามารถขอการสนับสนุนจาก AWS ได้ด้วย
  • หากต้องย้ายฐานข้อมูลระหว่าง PostgreSQL กันอีกในอนาคต มีแผนจะพิจารณาเครื่องมือทางเลือกอย่าง pglogical ให้มากขึ้น
  • DMS อาจเพิ่มความซับซ้อนและกระบวนการ replication ที่ไม่คุ้นเคยมากกว่าเครื่องมืออื่น
  • หลังการย้ายฐานข้อมูล ขั้นตอนถัดไปคือการย้ายแอปพลิเคชัน
  • แอปพลิเคชัน GOV.UK Notify มีแผนจะย้ายไปยัง AWS Elastic Container Service และจะมีการแชร์ความคืบหน้าในภายหลัง

1 ความคิดเห็น

 
GN⁺ 2024-01-19
ความคิดเห็นจาก Hacker News
  • เราก็ทำการย้ายระบบคล้ายกันด้วย AWS RDS Blue-Green Deployments และแม้ฐานข้อมูลจะใหญ่กว่านิดหน่อย แต่ downtime อยู่ที่ราว 20 วินาที และงานที่ต้องทำก็น้อยกว่ามาก น่าแปลกที่ยังไม่มีใครพูดถึงในเธรดนี้
    โดยพื้นฐานแล้วก็สร้าง deployment แบบ Blue/Green ใหม่พร้อมการเปลี่ยนแปลงที่ต้องการ แล้ว AWS จะซิงก์ green deployment ด้วย logical replication ขณะที่ฝั่ง blue เดิมยังคงรับทราฟฟิกต่อไป
    บน green สามารถแก้ไข ทดสอบ หรือทำ load test ได้ ตราบใดที่ไม่เขียนข้อมูล โดยการเขียนจะยังเข้า blue ที่เป็น live อยู่ แล้วค่อยถูก replicate ไปยัง green
    เมื่อพร้อมแล้วก็รันคำสั่ง switch แล้ว AWS จะจัดการตรวจสอบการซิงก์ ตัดการเขียนและการเชื่อมต่อ รอให้ replication ตามทัน เปลี่ยนชื่อฐานข้อมูล แล้วเปิดการเชื่อมต่อและการเขียนกลับมา
    สำหรับเรา downtime น้อยกว่า 20 วินาที และทั้งชุดระบบรวมถึง primary กับ read replica หลายตัวก็สลับได้โดยไม่มีปัญหา AWS ยังเปลี่ยน database URL ให้ด้วย จึงไม่ต้องแก้ config อะไร และ green จะกลายเป็น blue ส่วน blue เดิมจะกลายเป็น old blue แล้วค่อยลบทีหลังได้
    แนะนำมาก แต่ก็มีข้อจำกัด เช่น อาจใช้ไม่ได้ในกรณีย้ายข้ามบัญชี: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/blue-...

    • +1 ให้ Blue/Green แต่กรณีนี้น่าจะใช้ไม่ได้เพราะเป็นการ ย้ายข้ามบัญชี เราเคยใช้กับทั้ง MySQL และ Postgres โดยฝั่ง MySQL มีจำนวน query ต่อวินาทีสูงกว่ากรณีในบทความอีกสองหลัก แต่ทั้งคู่ราบรื่นดี
      ต้องอ่านเอกสาร โดยเฉพาะข้อจำกัด ซ้ำแล้วซ้ำอีก ควรทดสอบในสภาพแวดล้อม dev โดยใส่โหลดเข้าไป และลองอีกครั้งใน staging ด้วย
      หรือจะ YOLO ใส่ production ไปเลยก็น่าจะยังพอไหวเหมือนกัน
    • เราใช้ RDS Blue/Green deployment ตอน อัปเกรดเวอร์ชันเอนจินหลัก จาก MySQL 5.7 ไป 8.0 และในมุมมองเรื่อง downtime ถือว่ายอดเยี่ยม จากที่สังเกตผ่าน API downtime น่าจะประมาณ 13 วินาที
      แต่ก็ได้เรียนรู้แบบเจ็บ ๆ ว่า RDS Blue/Green ไม่ได้ใช้กับการเปลี่ยนแปลงอะไรก็ได้ ในกรณีของเรา มันใช้ได้เฉพาะตอนอัปเกรดเวอร์ชันเอนจิน แต่ใช้ตอนดาวน์เกรดไม่ได้
      มี stored procedure ตัวหนึ่งบน MySQL 8.0 ที่ล้มเหลวเป็นครั้งคราวมาก ๆ เราเลยพิจารณาทางเลือกที่จะย้อนกลับไป 5.7 แต่ทำไม่ได้
    • สงสัยว่ามีใครเคยใช้ Blue/Green เพื่อเข้ารหัส RDS storage ที่เดิมไม่ได้เข้ารหัสไหม
    • อยากรู้ว่าหยุดและเริ่มแอปพลิเคชันที่เข้าถึงฐานข้อมูลใหม่อย่างไร เรามีหลายงานที่รันบน ECS ซึ่งอาจใช้เวลา 1 นาทีในการปิด และอีกหลายกว่านาทีในการกลับขึ้นมาใหม่
    • +1 ให้ Route53 Groups และการตั้งค่าแบบ Blue/Green เราก็ทำคล้ายกันกับการอัปเกรด PostgreSQL และจัดการได้แบบไม่มี downtime โดยใช้ AWS R53 groups และแพตช์ Rails ActiveRecord transaction ภายในของเราเองเพื่อ retry query ที่กำลังรันอยู่
      trade-off คือมีบาง request ช้าลงอยู่ไม่กี่วินาที
      การจับคู่ระหว่าง DNS Groups กับการ retry เป็นกลไกที่ใช้ได้ดีทีเดียวสำหรับงานแบบนี้
      เครื่องมือที่ใช้: https://github.com/shayonj/pg_easy_replicate
  • มีหลายวิธีในการ “pause” query ขาเข้าของ Postgres เช่น ใช้ pgbouncer เพื่อหน่วงไว้แทนที่จะปล่อยให้ล้มเหลว จนกว่า replication จะตามทัน แล้วค่อยให้ทำงานต่อบนฐานข้อมูลใหม่
    ถ้าเกิดอะไรผิดพลาดและ replication ตามไม่ทัน ก็แค่ยกเลิกการ pause แล้วปล่อยให้ query เหล่านั้นไปรันบนฐานข้อมูลเดิม
    แบบนี้ downtime 11 วินาทีจะกลายเป็นเวลาโหลดหน้าเพิ่มขึ้น 0~11 วินาทีแทน ที่สำคัญกว่านั้นคือจะลด ความเสียหายข้างเคียง ได้มาก ในกรณีที่มีเส้นทางจัดการข้อผิดพลาดที่มีบั๊ก หรือมี batch job ที่พังยกชุดจาก query ล้มเหลวเพียงครั้งเดียว ในบรรดาผู้ใช้ฐานข้อมูลนับพันคนที่ไม่เคยเห็น query ล้มเหลวมาก่อน

    • การหยุด query คงพอทำได้ แต่สงสัยว่าสามารถหยุด transaction ที่กำลังดำเนินอยู่แล้วได้ด้วยไหม มันทำงานอย่างไร?
  • เมื่อเทียบกับ https://knock.app/blog/zero-downtime-postgres-upgrades แล้วก็น่าสนใจ มีการถกเถียงที่เกี่ยวข้องอยู่ที่ https://news.ycombinator.com/item?id=38616181
    ข้อสรุปของการถกเถียงส่วนใหญ่ในตอนนั้นคือ “แค่จะเลี่ยง downtime ไม่กี่นาที ถึงกับต้องทำให้ซับซ้อนขนาดนี้เลยหรือ” กรณีนี้ดูเหมือนจะเป็นหลักฐานยืนยัน และดูเหมือนแนวคิดจะเป็นว่าใช้ AWS Data Migration Service แล้วสลับไปใช้งานจริงด้วยการเปลี่ยนรายการ DNS จากนั้นยอมรับ downtime 11 วินาที ก็พอ

    • ตรงนี้ไม่มีคำว่า “ก็แค่” บทเรียนสำคัญอยู่ในส่วน “สิ่งที่ได้เรียนรู้”

      เหตุผลที่เลือก DMS คือมันได้รับการรองรับอย่างดีบน GOV.UK PaaS และเรายังสามารถขอการสนับสนุนจาก AWS ได้ด้วย ในอนาคต หากต้องย้ายฐานข้อมูลจาก PostgreSQL ไปยัง PostgreSQL อีกครั้ง เราจะใช้เวลาให้มากขึ้นในการพิจารณาเครื่องมือทางเลือกอย่าง pglogical DMS อาจเพิ่มความซับซ้อนและกระบวนการทำ replication ที่ไม่คุ้นเคยมากกว่าที่เราอาจเจอกับเครื่องมืออื่น ซึ่งก็สอดคล้องกับสิ่งที่ AWS เองพูดไว้โดยตรงเกี่ยวกับการย้ายข้อมูลระหว่าง PostgreSQL
      ข้อความที่ควรได้จากตรงนี้ไม่ใช่ “ก็ใช้ DMS ไปสิ”

    • อยากรู้ว่ามีใครเคยทำงานลักษณะคล้ายกันด้วย https://cloud.google.com/database-migration/docs/postgres/qu... บ้างไหม มันทำงานคล้าย AWS DMS หรือเปล่า?
    • DMS ดูเหมือนภายในจะใช้ pglogical แต่มีจุดหลุมพรางเยอะ มันไม่ใช่ hardware-level replication ดังนั้นอาจมีปัญหากับแถวขนาดใหญ่ คอลัมน์ขนาดใหญ่ และตารางขนาดใหญ่ และยังจัดการ foreign key ได้ไม่ดีนัก
      บาง data type แบบพิเศษอาจจัดการไม่ได้เลยด้วยซ้ำ หลังการ migration ยังต้องอัปเดต sequence ไม่เช่นนั้นอาจเจอข้อผิดพลาด primary key ซ้ำได้
      ถ้าไม่มี primary key ที่เหมาะสมก็อาจเกิดปัญหาได้ เพราะมันไม่ได้คัดลอกทั้งแถวในคราวเดียวเสมอไป
      ถ้าฐานข้อมูลอยู่ในบัญชี AWS เดียวกัน และคุณยอมรับ downtime ได้ 4–5 นาที การใช้ hardware-level replication ผ่าน global database หรือ snapshot น่าจะง่ายกว่า
  • ไม่นานมานี้เราเพิ่งย้ายฐานข้อมูล PostgreSQL 3TB ที่โฮสต์เองจาก 12 ไป 16 และย้ายจาก Ubuntu 18 ไป Ubuntu 22 พร้อมกันไปด้วย ในเวลาเดียวกันก็ต้องอัปเกรด extension หลายตัว โดยเฉพาะ Timescale ซึ่งไม่มีเวอร์ชันที่รองรับทุกชุดการผสมกันได้พอดี
    เราใช้วิธีอัปเกรด read-only replica: จุดเริ่มต้นคือ PG12, Ubuntu 18, TS2.9 แล้วสร้าง read-only replica ที่ยังคงเป็น PG12 และ TS2.9 แต่รันบน Ubuntu 22 ก่อน
    จากนั้นเข้า maintenance mode หยุดทุก service แยก read-only replica ออก แล้วอัปเกรด PG12 เป็น PG15 บน Ubuntu 22 โดยคง TS2.9 ไว้
    ต่อมาจึงอัปเกรดจาก PG15 + TS2.9 เป็น TS2.13 และสุดท้ายอัปเกรด PG15 เป็น PG16 บน Ubuntu 22 โดยคง TS2.13 ไว้
    ปิดท้ายด้วยการชี้ทุก service กลับไปยังเซิร์ฟเวอร์ฐานข้อมูลใหม่ เริ่มทุก service ใหม่ แล้วออกจาก maintenance mode
    เราทดสอบและทำให้ทุกขั้นตอนการอัปเกรดฐานข้อมูลเป็นอัตโนมัติด้วย Ansible อย่างเพียงพอแล้ว แต่ก็ยังมีปัญหาหนึ่งที่ไม่โผล่ขึ้นมาในช่วงทดสอบ ทำให้ downtime ยืดไปประมาณ 30 นาที ซึ่งสำหรับงานของเราก็ยังยอมรับได้
    ถ้าใช้ logical replication ก็น่าจะลดปัญหาไม่คาดคิดในช่วงท้ายสุดได้ และเราตั้งใจจะพิจารณาแนวทางนี้ในรอบอัปเกรดครั้งถัดไป

    • เราเองก็เพิ่งเดินตามเส้นทางอัปเกรดแทบจะเหมือนกัน ต่างกันแค่ว่าตอนนั้น Timescale ยังไม่รองรับ PG16 เลยหยุดที่ PG15 + TS 2.12
      เราดูเรื่อง logical replication เพื่อจะลด downtime ระหว่างอัปเกรดเหมือนกัน แต่เพราะ schema ของฐานข้อมูลและคำสั่ง DDL ไม่ถูก replicate จึงดูเหมือนเป็นแนวทางที่ไม่แนะนำเมื่อมี Timescale เข้ามาเกี่ยวข้อง
      การเปลี่ยนแปลง schema พื้นฐานที่ Timescale ต้องทำภายในน่าจะขึ้นอยู่กับขนาด chunk ของ hypertable และรูปแบบ write ที่เข้ามาเป็นหลัก ดังนั้นอาจพอวางแผนหรือจับจังหวะได้ แต่เรามองว่าความซับซ้อนและความเสี่ยงที่อาจเกิดขึ้นสูงเกินไป เมื่อเทียบกับการแค่กัน maintenance window สั้น ๆ ระหว่างที่ pg_upgrade ทำงานเสร็จ
  • ศัตรูของ migration แบบ downtime ต่ำหรือไร้ downtime คือ query ที่รันนาน
    ตัวอย่างเช่น ถ้ามี query update เดี่ยวที่ใช้เวลา 30 นาที คุณก็ต้องเลือกว่าจะ kill มันแล้ว rollback หรือยอมเสียความพร้อมใช้งานไป 30 นาที
    เท่าที่รู้ ตอนนี้ยังไม่มีวิธีย้าย query ที่กำลังรันอยู่ระหว่างการ migration

    • ถ้าเป็นโครงการวิศวกรรมซอฟต์แวร์ โดยทั่วไปควรจำกัดเวลา transaction ให้สั้นกว่านั้นมาก การตั้งค่า statement_timeout คือเพื่อนของคุณ
      ถ้ามี transaction ที่ยาวมากผิดปกติ ก็น่าจะมีโอกาสสลับระบบโดยหลีกเลี่ยงช่วงที่มันรันอยู่ได้ หวังว่ามันจะไม่เกิดแบบสุ่ม แต่เป็นผลจากงานตามตารางเวลาอะไรทำนองนั้น
      ถ้าผสมการจำกัดเวลา transaction เข้ากับการตั้งค่า failover เช่น การบังคับให้ primary เดิมล้มเหลว และใช้สิ่งอย่าง pgbouncer คุณจะควบคุมช่วงเวลา ที่ระบบช้าลง แทน downtime ได้ค่อนข้างละเอียด
      พูดตรง ๆ สิ่งที่น่ากังวลกว่าคือทั้ง stack รวมถึงเซิร์ฟเวอร์ DNS cache ภายนอกที่พึ่งพาอยู่นั้นเคารพ DNS TTL อย่างถูกต้องหรือไม่
      แต่โดยทั่วไป การเลี่ยง downtime ระดับสิบกว่าวินาทีในแอปก็มักไม่ใช่เรื่องถึงตาย ดังนั้นการเลือกวิธีที่ง่ายกว่าสำหรับตัวเองก็น่าจะเหมาะกว่า
    • ส่วนตัวแล้วนึกภาพไม่ค่อยออกว่างาน query update ที่ใช้เวลา 30 นาทีจะเป็นกรณีอะไรได้บ้าง นอกเสียจากว่ามันถูกเขียนมาอย่างไม่มีประสิทธิภาพอย่างมาก หรือเป็นการ migration ข้อมูลก้อนใหญ่แบบครั้งเดียว
      แน่นอนว่าแบบแรกมีอยู่จริงเยอะมาก ผมเคยสนุกกับการเปลี่ยนงานที่ใช้เวลาเป็นนาทีหรือเป็นชั่วโมงให้เหลือระดับมิลลิวินาทีมาพอสมควร
    • เพิ่งรู้นี่เอง อยากรู้ว่างานเขียนข้อมูลที่ใช้เวลาเกิน 30 นาทีมีลักษณะเป็นแบบไหน
      เป็นข้อมูลแบบใด และคนแบบไหนที่ต้องรับมือกับการเขียนฐานข้อมูลเช่นนั้น จนต้องพึ่งให้ DB engine ทำงานนานขนาดนั้นแทนที่จะซอยออกเป็นงานย่อยผ่านคิวในชั้นบนกว่านี้
  • การสร้าง DNS record ของ AWS Route53 สำหรับ database.notifications.service.gov.uk ที่มี TTL 1 วินาที แล้วให้สคริปต์ย้ายข้อมูลปรับน้ำหนัก DNS ของ AWS ให้ส่งไปยังตำแหน่งฐานข้อมูลปลายทาง 100% จากนั้นรอ 1 วินาทีให้ TTL หมดอายุดูแปลก ๆ
    จากนั้นบอกว่าเมื่อแอปพยายาม query ฐานข้อมูลครั้งถัดไป มันก็จะไป query ฐานข้อมูลปลายทางแทน แบบนี้หมายความว่า ORM ของพวกเขาหรือพฤติกรรมพื้นฐานของ Python จะทำ DNS lookup ทุกครั้งที่มี query แล้วค้างรออย่างนั้นหรือ?
    ไม่มีการ cache address ที่ resolve ได้ไว้ช่วงหนึ่งเลย และไม่มี connection pooling หรือการ reuse การเชื่อมต่อด้วยหรือ?

    • น่าจะเป็นพฤติกรรมของ getaddrinfo หรือ gethostname ของ OS มากกว่า Python เองแทบไม่ได้เขียน system-level call พวกนี้ขึ้นใหม่ จึงขึ้นอยู่กับการตั้งค่าของระบบ
      ถ้า TTL 1 วินาทีถูกเคารพจริง ก็อาจถูก cache ไว้ 1 วินาที แต่ก็ไม่ใช่เรื่องแปลกที่ไลบรารีสำหรับ DNS lookup และโดยเฉพาะ caching DNS server จะไม่ทำตาม TTL แบบเป๊ะ ๆ พูดตรง ๆ ว่านี่อาจอธิบาย downtime บางส่วนที่สังเกตได้ด้วย
  • ดีเลย เราเพิ่งย้าย Postgres cluster 3 ชุดจาก Postgres 14 ไป 16 บน RDS ซึ่งรวมข้อมูลราว 2TB และมีฐานข้อมูล 8 ตัว ระบบล่มตั้งแต่ 00:00 ถึง 04:00
    ก่อนอื่นเราเปิด “maintenance mode” ซึ่งเป็นไซต์สำรองที่เบามากและรันอยู่บน Cloudflare Workers แล้วใช้ Terraform scale down ทุกแอปที่ใช้ DB ลงเป็น 0
    จากนั้นกดปุ่มอัปเกรดใน AWS web UI เพื่อรัน pg_upgrade จาก 14→15 แล้วรอให้เสร็จ ก่อนจะกดอีกครั้งเพื่อทำ 15→16
    เรารอจนฐานข้อมูลเริ่มรับการเชื่อมต่อได้ ซึ่งดูเหมือนว่ามันรับ connection ได้ตั้งแต่ก่อนจะแสดงว่า ready และดูเหมือน AWS จะทำอย่างอื่นเพิ่มเติมนอกเหนือจาก pg_upgrade
    หลังจากนั้นเราเริ่ม VACUUM ANALYZE; REINDEX DATABASE CONCURRENTLY โดยตั้งใจจะหลีกเลี่ยงปัญหาด้านประสิทธิภาพระหว่างเวอร์ชัน และใช้ประโยชน์จากการปรับปรุงประสิทธิภาพของเวอร์ชันใหม่
    จากนั้นก็เริ่มปลุกแอปกลับขึ้นมา รอจนทุกแอปมีคอนเทนเนอร์ขึ้นมาสักสองสามตัว แล้วค่อยเริ่มรับทราฟฟิก ปิด maintenance site และเข้านอน
    REINDEX CONCURRENTLY รันต่ออีก 18 ชั่วโมงบน DB ที่ใหญ่ที่สุด แต่ไม่ได้บล็อกอะไร
    ครั้งหน้าจะใช้ AWS Blue/Green deployments เพื่อหลีกเลี่ยง downtime แต่ครั้งนี้ใช้ไม่ได้เพราะไม่ได้อยู่บน 14.9 ซึ่งเป็น minor version ต่ำสุดของ 14 ที่ Blue/Green รองรับ
    ถ้าเป็นฉันทำเอง ฉันจะไม่จ่ายเงินเพิ่มให้ AWS แต่จะทำ Blue/Green เองด้วย logical replication และ load balancer

    • ถ้าเป็นฉันจะใช้ pg_upgrade --hardlinks สำหรับ in-place upgrade
      ฉันเคยทำกับ DB ขนาด 2TB บน Postgres instance แบบ on-premises ของตัวเอง และใช้เวลาไม่ถึง 1 นาที
  • GOV.UK Notify เป็นส่วนหนึ่งของชุดบริการที่ GDS มอบให้หน่วยงานภาครัฐของสหราชอาณาจักร นอกจากนี้ยังมี GOV.UK Pay และ GOV.UK PaaS ด้วย เดิมทีชุดนี้รู้จักกันในชื่อ Government As A Platform

  • DMS เป็นเครื่องมือย้ายข้อมูลที่แย่มาก ฉันสู้กับปัญหาการย้ายข้อมูลหลายอย่างอยู่เกือบเดือนก่อนจะยอมแพ้
    มันย้ายชนิดข้อมูล text และ json ไม่ได้ และ AWS support ก็เสนอทางแก้ไม่ได้
    ฉันเคยใช้ AWS Blue/Green ในช่วงทดสอบแรก ๆ และมันทำให้การอัปเกรดแบบแทบไม่ต้องหยุดระบบเป็นจริงได้

    • ถ้าคุณคิดว่า DMS เป็นเครื่องมือย้ายข้อมูลที่แย่ ลองเอาไปใช้สำหรับ continuous replication ไปยังปลายทางภายนอกดูได้
      พังยับเยินเลย
  • น่าสนใจดี แต่ไม่เข้าใจว่าทำไมรัฐบาลถึงใช้ AWS ตั้งแต่แรก นี่ไม่ใช่สตาร์ทอัพที่กำลังแฮ็กเพื่อหา product-market fit และก็ไม่ใช่สถานการณ์ที่คาดการณ์ทราฟฟิกพุ่งจากการตลาดไม่ทันจนต้องรับมือ
    เรารู้อยู่แล้วว่าบริการแบบนี้จำเป็นในระยะยาว และก็คาดการณ์รูปแบบการใช้งานได้ค่อนข้างดี
    สามารถสร้าง public-sector cloud หรือเลือกแนวทาง on-premises ที่สมเหตุสมผลได้ ต้องใช้เงิน การประสานงาน และภาวะผู้นำทางเทคนิค แต่ระยะยาวจะช่วยประหยัดค่าใช้จ่ายให้ผู้เสียภาษีได้มหาศาล
    IT ภาครัฐโดยรวมมักจะยุ่งเหยิง แต่ก็รู้ว่าข้างในนั้นมีวิศวกรเก่ง ๆ อยู่เหมือนกัน

    • เหตุผลที่ในฐานะสตาร์ทอัพใช้ “คลาวด์” หรือก็คือ PaaS ไม่ใช่เพื่อรับมือทราฟฟิกพุ่ง แต่เป็นเรื่องของ การโฟกัส
      เวลาหนึ่งชั่วโมงที่ต้องวิ่งวุ่นกับฮาร์ดดิสก์และไดรเวอร์ หรือเวอร์ชันบนคลาวด์ของสิ่งเหล่านั้นอย่าง storage กับ Ansible คือหนึ่งชั่วโมงที่ไม่ได้เอาไปสร้างสิ่งที่ลูกค้าต้องการ
      แล้วทำไมรัฐบาลถึงต้องต่างออกไป?
      เราไม่ได้คาดหวังให้รัฐบาลผลิตรถยนต์เอง แต่คาดหวังให้ไปซื้อจาก Volkswagen หรือ Renault แม้ว่ารัฐบาลจะมีความต้องการด้านการขนส่งอย่างชัดเจนก็ตาม แล้วทำไมถึงยืนกรานว่าต้องสร้างโครงสร้างพื้นฐาน IT เองก็ไม่เข้าใจ
    • ถ้าคิดว่าความต้องการและดีมานด์ของรัฐบาลคาดการณ์ได้ แปลว่าคุณไม่ได้ติดตามการเมือง โดยเฉพาะการเมืองอังกฤษในช่วง 10 ปีที่ผ่านมา
      และยังมีเรื่องที่โผล่มาแบบเหนือความคาดหมายทั้งหมดอย่างโรคระบาดด้วย ความสามารถในการขยายระบบให้สอดคล้องกับความต้องการในช่วงโรคระบาดเป็นหนึ่งในตัวอย่างสาธิตสำคัญว่าทำไมภาครัฐจึงควรใช้ commercial public cloud
    • ภาครัฐของสหราชอาณาจักรโดยรวมใช้งานทั้ง public cloud รายใหญ่และ on-premises/colocation บางส่วนร่วมกัน
      แนะนำให้ดูงานนำเสนอเดือนกันยายนเกี่ยวกับหลายยุคของ Gov.UK และการย้ายข้ามคลาวด์ https://youtube.com/watch?v=mpY1lxkikqM&pp=ygUOUmljaGFyZCB0b...
      อย่างน้อยในรัฐบาลสหราชอาณาจักร เนื่องจากข้อกำหนดด้านการจัดซื้อจัดจ้าง จึงต้องนำใบเสนอราคาตามปริมาณการใช้งานกลับออกสู่ตลาดใหม่ทุก ๆ สองสามปี
      ตัวอย่างเช่น ถ้า Oracle Cloud ถูกกว่าถึง 10 เท่า ก็มีโอกาสสูงที่จะได้สัญญา และนั่นหมายความว่าต้องย้ายไป Oracle ตลอดช่วงสัญญา จากนั้นถ้ามีคลาวด์อื่นที่ถูกกว่าออกมา ก็อาจต้องย้ายอีกครั้ง
    • หลายประเทศใน EU น่าจะสร้าง public cloud ของภาครัฐขึ้นมาเอง ผมเจอมากับตัวที่โครเอเชีย และเป็นหนึ่งในนักพัฒนาที่ต้อง deploy ลงไปที่นั่น
      มันแย่ที่สุดเท่าที่เคยเห็นมาในชีวิต แม้ว่าจะเคยรับมือทั้ง VB.NET, Web Forms, SharePoint รุ่นเก่า, Basic และแม้แต่ระบบ legacy ที่ทั้งแอปเป็นก้อน stored procedure ขนาดยักษ์มาก่อนแล้วก็ตาม
      อย่างน้อย AWS, Azure, Google Cloud ก็ถูกสร้างขึ้นโดยคำนึงถึงผู้ใช้ปลายทาง ซึ่งก็คือนักพัฒนา ในทางกลับกัน government cloud ถูกออกแบบและสร้างโดย ผู้ชนะการประมูลราคาต่ำสุด ที่มีเป้าหมายแรกคือการตัดต้นทุนทุกจุดที่เป็นไปได้
    • ไม่แน่ใจว่าสหราชอาณาจักรเป็นอย่างไร แต่ในสหรัฐฯ AWS มี GovCloud มานานมากแล้ว และพูดตามตรง เมื่อเทียบกับอินฟราหลายแห่งที่เคยเห็น มันแทบจะเป็นพรเลย
      ในทางกลับกัน ผมก็เคยเจอทีมโครงสร้างพื้นฐานและปฏิบัติการที่ยอดเยี่ยมจริง ๆ ซึ่งดูแลดาต้าเซ็นเตอร์ภายในของหน่วยงานสาธารณสุขรัฐบาลเยอรมนี ปัญหาที่นั่นไม่ใช่เทคโนโลยีหรือคน แต่เป็นผู้บริหารและกระบวนการที่พยายามทำตัวเป็นคอขวดในทุกปฏิสัมพันธ์ระหว่างทีมอินฟรากับทีมวิศวกรรม ซึ่งคิดเป็น 100% ของปัญหา