17 คะแนน โดย GN⁺ 11 일 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ย้าย โครงสร้างพื้นฐาน production มูลค่า $1,432 ต่อเดือน ไปยัง dedicated server ราคา $233 ต่อเดือน พร้อมเปลี่ยนระบบปฏิบัติการโดยยังคงความต่อเนื่องของบริการแบบไม่มี downtime
  • ตั้งค่า ฐานข้อมูล MySQL 30 ตัว และ Nginx virtual host 34 ตัว รวมถึง GitLab EE, Neo4J, Supervisor, Gearman บนเซิร์ฟเวอร์ใหม่ให้เหมือนเดิม แล้วเสร็จสิ้นการย้ายด้วยการทำ replication แบบเรียลไทม์และ incremental sync รอบสุดท้าย
  • หัวใจของการย้ายฐานข้อมูลคือการผสาน การประมวลผลแบบขนานของ mydumper·myloader เข้ากับ MySQL replication และยังแก้ปัญหาเรื่องสคีมา sys กับสิทธิ์ที่เกิดขึ้นระหว่างอัปเกรดจาก MySQL 5.7 ไป 8.0
  • ขั้นตอน cutover ดำเนินตามลำดับ ลด DNS TTL, เปลี่ยน Nginx บนเซิร์ฟเวอร์เดิมให้เป็น reverse proxy, และ เปลี่ยน A record ทั้งหมดพร้อมกัน ทำให้แม้ระหว่าง DNS propagation คำขอที่ยังวิ่งเข้า IP เดิมก็ถูกส่งต่อไปยังเซิร์ฟเวอร์ใหม่
  • ผลลัพธ์คือ ประหยัดได้ $1,199 ต่อเดือน, $14,388 ต่อปี พร้อมได้ CPU·หน่วยความจำ·สตอเรจที่สูงขึ้น และ downtime 0 นาที

เบื้องหลังของการย้ายระบบ

  • ในบริบทของการดำเนินบริษัทซอฟต์แวร์ในตุรกี ภาวะ เงินเฟ้อที่พุ่งสูง และ ค่าเงินลีราตุรกีอ่อนตัว ทำให้ภาระค่าโครงสร้างพื้นฐานที่คิดเป็นดอลลาร์เพิ่มขึ้นอย่างมาก
  • ค่าใช้จ่ายของเซิร์ฟเวอร์ DigitalOcean เดิมอยู่ที่ $1,432 ต่อเดือน โดยมีสเปกเป็น RAM 192GB, 32 vCPU, SSD 600GB, block volume 1TB จำนวน 2 ตัว และรวมแบ็กอัป
  • เป้าหมายใหม่คือ Hetzner AX162-R ซึ่งเป็น dedicated server ที่ใช้ AMD EPYC 9454P 48 คอร์ 96 เธรด, 256GB DDR5 และ 1.92TB NVMe Gen4 RAID1
  • ค่าใช้จ่ายรายเดือนลดลงเหลือ $233 ทำให้ประหยัดได้ $1,199 ต่อเดือน และ $14,388 ต่อปี
  • แม้จะไม่ได้ไม่พอใจกับความน่าเชื่อถือหรือประสบการณ์นักพัฒนาของเซิร์ฟเวอร์เดิม แต่สำหรับ steady-state workload แล้ว ความคุ้มค่าต่อราคาก็ไม่สมเหตุสมผลอีกต่อไป

สภาพแวดล้อมการใช้งานเดิม

  • สแตกที่ใช้งานไม่ใช่แค่สภาพแวดล้อมทดสอบแบบง่าย ๆ แต่เป็น production จริง
    • ฐานข้อมูล MySQL 30 ตัว รวมข้อมูลทั้งหมด 248GB
    • ให้บริการ Nginx virtual host 34 ตัว ครอบคลุมหลายโดเมน
    • มีแบ็กอัป GitLab EE ขนาด 42GB
    • รัน Neo4J Graph DB ขนาด 30GB
    • ใช้ Supervisor จัดการ background worker หลายสิบตัว
    • ใช้คิวงาน Gearman
    • ให้บริการแอปมือถือแบบ live กับผู้ใช้หลายแสนคน
  • ระบบปฏิบัติการของเซิร์ฟเวอร์เดิมคือ CentOS 7 ซึ่งสิ้นสุดการซัพพอร์ตไปแล้ว
  • ระบบปฏิบัติการของเซิร์ฟเวอร์ใหม่คือ AlmaLinux 9.7 ซึ่งเป็นดิสโทรที่เข้ากันได้กับ RHEL 9 และเป็นตัวเลือกสืบทอดจาก CentOS อย่างเป็นธรรมชาติ
  • การย้ายครั้งนี้ไม่ใช่แค่เพื่อลดต้นทุน แต่ยังเป็นโอกาสในการออกจากระบบปฏิบัติการที่ไม่ได้รับ security update มาหลายปี

กลยุทธ์แบบไม่มี downtime

  • ไม่ใช้วิธีเปลี่ยน DNS แล้วรีสตาร์ตบริการแบบง่าย ๆ แต่ดำเนินการย้ายแบบไม่มี downtime ผ่าน กระบวนการ 6 ขั้นตอน
  • ขั้นตอนที่ 1: ติดตั้งสแตกทั้งหมดบนเซิร์ฟเวอร์ใหม่

    • ติดตั้ง Nginx ด้วยการคอมไพล์จากซอร์สโดยใช้แฟล็กเหมือนของเดิม
    • ติดตั้ง PHP ผ่าน Remi repo และใช้ไฟล์ตั้งค่า .ini เดิมจากเซิร์ฟเวอร์เก่า
    • ติดตั้ง MySQL 8.0, Neo4J Graph DB, GitLab EE, Node.js, Supervisor, Gearman และตั้งค่าให้ทำงานเหมือนเดิม
    • ก่อนแตะ DNS ได้ทำให้ทุกบริการทำงานเหมือนเซิร์ฟเวอร์เดิมเรียบร้อยแล้ว
    • ใบรับรอง SSL จัดการโดยคัดลอกไดเรกทอรี /etc/letsencrypt/ ทั้งหมดจากเซิร์ฟเวอร์เดิมด้วย rsync
    • หลังจากทราฟฟิกทั้งหมดถูกย้ายไปยังเซิร์ฟเวอร์ใหม่แล้ว จึงบังคับต่ออายุใบรับรองทั้งหมดด้วย certbot renew --force-renewal
  • ขั้นตอนที่ 2: ทำสำเนาไฟล์เว็บด้วย rsync

    • คัดลอกไดเรกทอรี /var/www/html ทั้งหมด ขนาดประมาณ 65GB และมี ไฟล์ 1.5 ล้านไฟล์ ด้วย rsync ผ่าน SSH
    • ใช้ตัวเลือก --checksum เพื่อตรวจสอบความถูกต้องครบถ้วน
    • ก่อน cutover ทำ incremental sync รอบสุดท้ายเพิ่มเติมเพื่อเก็บไฟล์ที่มีการเปลี่ยนแปลง
  • ขั้นตอนที่ 3: ทำ MySQL master-slave replication

    • แทนที่จะ dump แล้ว restore จนฐานข้อมูลต้องหยุด ใช้วิธีตั้งค่า replication แบบเรียลไทม์
    • ตั้งให้เซิร์ฟเวอร์เดิมเป็น master และเซิร์ฟเวอร์ใหม่เป็น read-only slave
    • โหลดข้อมูลก้อนใหญ่เริ่มต้นด้วย mydumper จากนั้นเริ่ม replication จาก ตำแหน่ง binlog ที่ถูกบันทึกไว้อย่างแม่นยำใน metadata ของ dump
    • ทำให้ฐานข้อมูลทั้งสองฝั่งซิงก์แบบเรียลไทม์จนถึงเวลาที่ cutover
  • ขั้นตอนที่ 4: ลด DNS TTL

    • เรียกใช้ DigitalOcean DNS API ผ่านสคริปต์เพื่อลด TTL ของ A/AAAA record ทั้งหมด จาก 3600 วินาทีเหลือ 300 วินาที
    • MX และ TXT record ไม่ได้ถูกเปลี่ยน
    • เพราะการเปลี่ยน TTL ของ mail record อาจทำให้เกิดปัญหาด้านการส่งอีเมล จึงตั้งใจแยกไว้
    • รอ 1 ชั่วโมงให้ TTL เดิมหมดอายุทั่วโลก แล้วจึงพร้อม cutover ภายใน 5 นาที
  • ขั้นตอนที่ 5: เปลี่ยน Nginx บนเซิร์ฟเวอร์เดิมให้เป็น reverse proxy

    • สคริปต์ Python ทำการ parse server {} block ทั้งหมดของคอนฟิกไซต์ Nginx 34 ตัว
    • สำรองคอนฟิกเดิมไว้ แล้วแทนที่ด้วยคอนฟิก proxy ที่ชี้ไปยังเซิร์ฟเวอร์ใหม่
    • ระหว่าง DNS propagation คำขอที่ยังเข้ามายัง IP เดิมก็จะถูกส่งต่อไปยังเซิร์ฟเวอร์ใหม่อย่างเงียบ ๆ
    • สำหรับผู้ใช้จะมองไม่เห็นการหยุดชะงัก
  • ขั้นตอนที่ 6: DNS cutover และปิดเซิร์ฟเวอร์เดิม

    • ใช้สคริปต์ Python เรียก DigitalOcean API เพื่อเปลี่ยน A record ทั้งหมด ไปยัง IP ของเซิร์ฟเวอร์ใหม่ภายในไม่กี่วินาที
    • คงเซิร์ฟเวอร์เดิมไว้เป็น cold standby เป็นเวลา 1 สัปดาห์ก่อนปิด
    • ตลอดทั้งกระบวนการ บริการยังคงตอบสนองได้เองหรือผ่าน proxy จึงไม่มีช่วงว่างด้านความพร้อมใช้งาน

การย้าย MySQL

  • ในงานทั้งหมด ส่วนที่ ซับซ้อนที่สุด คือกระบวนการย้าย MySQL
  • การ dump ข้อมูล

    • ใช้ mydumper แทน mysqldump มาตรฐาน
    • อาศัย 48 คอร์ CPU ของเซิร์ฟเวอร์ใหม่เพื่อ export/import แบบขนาน ทำให้งานที่ถ้าใช้ mysqldump แบบเธรดเดียวจะกินเวลาหลายวัน ลดเหลือเพียงไม่กี่ชั่วโมง
    • ตัวเลือกสำคัญที่ใช้ ได้แก่ --threads 32, --compress, --trx-consistency-only, --skip-definer, --chunk-filesize 256
    • ไฟล์ metadata ของ dump หลักบันทึกตำแหน่ง binlog ณ เวลาที่ snapshot ไว้
      • File: mysql-bin.000004
      • Position: 21834307
    • ค่านี้ถูกใช้เป็นจุดเริ่มต้นของ replication ในภายหลัง
  • การส่ง dump

    • เมื่อ dump เสร็จแล้ว จึงส่งไปยังเซิร์ฟเวอร์ใหม่ด้วย rsync ผ่าน SSH
    • ส่ง compressed chunk รวมทั้งหมด 248GB
    • ตัวเลือก --compress ของ mydumper ช่วยเพิ่มความเร็วในการส่งผ่านเครือข่าย
  • การโหลดข้อมูล

    • ใช้ myloader
    • ตัวเลือกหลักคือ --threads 32, --overwrite-tables, --ignore-errors 1062, --skip-definer
  • ปัญหาระหว่างเปลี่ยนจาก MySQL 5.7 ไป 8.0

    • เนื่องจากสภาพแวดล้อม CentOS 7 เซิร์ฟเวอร์เดิมจึงยังคงใช้ MySQL 5.7
    • ก่อนย้าย ได้ตรวจสอบความเข้ากันได้ของข้อมูลกับ MySQL 8.0 ด้วย mysqlcheck --check-upgrade และผลออกมาว่าไม่มีปัญหา
    • บนเซิร์ฟเวอร์ใหม่ติดตั้ง MySQL 8.0 Community รุ่นล่าสุด
    • เวลาการรัน query ตลอดทั้งโปรเจกต์ลดลงอย่างมีนัยสำคัญ โดยต้นฉบับระบุเหตุผลว่าเป็นเพราะ optimizer ที่ดีขึ้น และ การปรับปรุง InnoDB ของ MySQL 8.0
    • อย่างไรก็ตาม ก็เกิดปัญหาจากการกระโดดเวอร์ชัน
      • หลัง import โครงสร้างคอลัมน์ของตาราง mysql.user มีเพียง 45 คอลัมน์ แทนที่จะเป็น 51 ตามที่คาดไว้
      • ส่งผลให้ mysql.infoschema หายไปและเกิดปัญหาในการยืนยันตัวตนผู้ใช้
    • การลองแก้ครั้งแรกใช้คำสั่งด้านล่าง
      • systemctl stop mysqld
      • mysqld --upgrade=FORCE --user=mysql &
    • ครั้งแรกไม่สำเร็จเพราะเกิดข้อผิดพลาด ERROR: 'sys.innodb_buffer_stats_by_schema' is not VIEW
    • สาเหตุคือ สคีมา sys ถูก import มาเป็นตารางธรรมดา ไม่ใช่ view
    • วิธีแก้คือรัน DROP DATABASE sys; แล้วจึงรันอัปเกรดซ้ำ
    • หลังจากนั้นจึงทำงานได้ตามปกติ

การตั้งค่า MySQL replication

  • หลังจากทั้งสองเซิร์ฟเวอร์โหลด dump เสร็จแล้ว ก็ตั้งค่าเซิร์ฟเวอร์ใหม่ให้เป็น replica ของเซิร์ฟเวอร์เดิม
  • ในคำสั่ง CHANGE MASTER TO ได้กำหนด IP ของเซิร์ฟเวอร์เดิม, ผู้ใช้สำหรับ replication, พอร์ต 3306, MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=21834307
  • จากนั้นรัน START SLAVE;
  • เกือบทันที replication ก็หยุดด้วย error 1062 Duplicate Key
  • สาเหตุคือ dump ถูกทำเป็นสองช่วง และในช่วงเวลานั้นมีการเขียนลงบางตาราง ทำให้เมื่อ replay binlog จึงพยายาม insert แถวเดิมซ้ำกับที่มีอยู่ใน dump แล้ว
  • เพื่อแก้ปัญหา จึงใช้การตั้งค่าด้านล่าง
    • SET GLOBAL slave_exec_mode = 'IDEMPOTENT';
    • START SLAVE;
  • โหมด IDEMPOTENT จะข้าม duplicate key และ missing row error อย่างเงียบ ๆ
  • ฐานข้อมูลสำคัญทั้งหมดซิงก์ได้โดยไม่มีข้อผิดพลาด และภายในไม่กี่นาทีค่า Seconds_Behind_Master ก็ลดลงเป็น 0

การตรวจสอบก่อน cutover

  • ก่อนแตะ DNS จำเป็นต้องยืนยันว่าทุกบริการบนเซิร์ฟเวอร์ใหม่ทำงานได้ถูกต้อง
  • วิธีตรวจสอบคือแก้ไฟล์ /etc/hosts บนเครื่องโลคัลชั่วคราว เพื่อแมปโดเมนไปยัง IP ของเซิร์ฟเวอร์ใหม่
  • ทำให้เบราว์เซอร์และ Postman ส่งคำขอไปยังเซิร์ฟเวอร์ใหม่ ขณะที่ผู้ใช้ภายนอกยังคงเข้าเซิร์ฟเวอร์เดิม
  • ตรวจสอบ API endpoint, แอดมินพาเนล และสถานะการตอบสนองของแต่ละบริการ
  • เมื่อยืนยันครบทุกอย่างแล้วจึงเริ่ม cutover จริง

ปัญหาสิทธิ์ SUPER

  • หลังจาก master-slave replication ซิงก์กันสมบูรณ์แล้ว พบว่าบนเซิร์ฟเวอร์ใหม่แม้จะตั้ง read_only = 1 แต่ คำสั่ง INSERT ยังสำเร็จ
  • สาเหตุคือผู้ใช้ PHP application ทุกคนมี สิทธิ์ SUPER
  • ใน MySQL สิทธิ์ SUPER สามารถข้าม read_only ได้
  • ตรวจพบว่ามีสิทธิ์ SUPER อยู่ในผลลัพธ์ของ SHOW GRANTS FOR 'some_db_user'@'localhost';
  • จึงรัน REVOKE SUPER ON *.* FROM 'some_db_user'@'localhost'; ซ้ำสำหรับ ผู้ใช้แอปพลิเคชัน 24 ราย
  • จากนั้นรัน FLUSH PRIVILEGES;
  • หลังจากนั้น read_only = 1 จึงบล็อกการเขียนจากผู้ใช้แอปพลิเคชันได้ถูกต้อง ขณะที่ยังคงให้ replication ทำงานต่อได้

การเตรียม DNS

  • ทุกโดเมนถูกจัดการด้วย DigitalOcean DNS และเนมเซิร์ฟเวอร์เชื่อมผ่าน GoDaddy
  • งานลด TTL ถูกทำเป็นสคริปต์ที่ยิงไปยัง DigitalOcean API
  • จำกัดขอบเขตการเปลี่ยนแปลงไว้เฉพาะ A และ AAAA record
  • MX และ TXT record ไม่ได้ถูกแตะต้อง
    • เพราะความเป็นไปได้ที่จะเกิดปัญหาเรื่องการส่งผ่านของ Google Workspace จึงไม่นำ TTL ของ record ที่เกี่ยวกับอีเมลไปเปลี่ยน
  • หลังรอ 1 ชั่วโมงให้ TTL เดิมหมดอายุ ก็พร้อมสำหรับ cutover

เปลี่ยน Nginx บนเซิร์ฟเวอร์เดิมเป็น reverse proxy

  • แทนที่จะแก้ไฟล์คอนฟิก 34 ไฟล์ด้วยมือ ได้ใช้สคริปต์ Python แปลงอัตโนมัติ
  • สคริปต์จะ parse server {} block ของทุกไฟล์คอนฟิก ระบุ content block หลัก แล้วแทนที่ด้วยคอนฟิก proxy
  • คอนฟิกต้นฉบับถูกสำรองเป็นไฟล์ .backup
  • ในตัวอย่างคอนฟิกใช้ proxy_pass https://NEW_SERVER_IP;, proxy_set_header Host $host;, proxy_set_header X-Real-IP $remote_addr;, proxy_read_timeout 150;
  • ตัวเลือกสำคัญคือ proxy_ssl_verify off
    • เพราะใบรับรอง SSL บนเซิร์ฟเวอร์ใหม่ใช้ได้กับโดเมน แต่ใช้ไม่ได้กับ IP address
    • ในสภาพแวดล้อมที่ควบคุมปลายทางทั้งสองฝั่งได้ จึงยอมปิดการตรวจสอบในจุดนี้

ขั้นตอน cutover

  • เงื่อนไขก่อน cutover คือ replication lag ต้องเป็น Seconds_Behind_Master: 0 และ reverse proxy ต้องพร้อมแล้ว
  • ลำดับการทำงานมีดังนี้
    • บนเซิร์ฟเวอร์ใหม่รัน STOP SLAVE;
    • บนเซิร์ฟเวอร์ใหม่รัน SET GLOBAL read_only = 0;
    • บนเซิร์ฟเวอร์ใหม่รัน RESET SLAVE ALL;
    • รัน supervisorctl start all บนเซิร์ฟเวอร์ใหม่
    • บนเซิร์ฟเวอร์เดิมรัน nginx -t && systemctl reload nginx เพื่อเปิดใช้งาน proxy
    • บนเซิร์ฟเวอร์เดิมรัน supervisorctl stop all
    • บน Mac โลคัลรัน python3 do_cutover.py เพื่อเปลี่ยน A record ทั้งหมดของ DNS ไปยัง IP ของเซิร์ฟเวอร์ใหม่
    • รอ propagation ประมาณ 5 นาที
    • คอมเมนต์ทุกรายการใน crontab บนเซิร์ฟเวอร์เดิม
  • สคริปต์ DNS cutover เรียก DigitalOcean API เพื่อเปลี่ยน A record ทั้งหมดภายในประมาณ 10 วินาที

งานเพิ่มเติมหลัง cutover

  • หลังการย้ายเสร็จ พบว่า GitLab project webhook จำนวนมากยังคงชี้ไปยัง IP ของเซิร์ฟเวอร์เดิม
  • จึงเขียนและใช้สคริปต์ที่สแกนทุกโปรเจกต์ผ่าน GitLab API แล้วอัปเดต webhook ทั้งหมดแบบรวดเดียว

ผลลัพธ์สุดท้าย

  • ค่าใช้จ่ายรายเดือนลดจาก $1,432 เหลือ $233
  • ประหยัดรายปีได้ $14,388
  • ในด้านประสิทธิภาพก็ได้เซิร์ฟเวอร์ที่แรงขึ้นด้วย
    • CPU เพิ่มจาก 32 vCPU เป็น 96 logical CPU
    • RAM เพิ่มจาก 192GB เป็น 256GB DDR5
    • สตอเรจเปลี่ยนจากโครงสร้างผสมประมาณ 2.6TB เป็น 2TB NVMe RAID1
    • downtime เท่ากับ 0 นาที
  • การย้ายทั้งหมดใช้เวลาประมาณ 24 ชั่วโมง
  • ไม่มีผลกระทบต่อผู้ใช้

บทเรียนสำคัญ

  • MySQL replication คือเครื่องมือหลักของการย้ายแบบไม่มี downtime
    • ตั้งค่าให้เร็ว ปล่อยให้ไล่ตามจนทัน แล้วค่อยทำ cutover
  • ต้องตรวจสอบสิทธิ์ของผู้ใช้ MySQL ก่อนย้ายเสมอ
    • ถ้ามี สิทธิ์ SUPER ก็จะข้าม read_only ทำให้สภาพแวดล้อม slave ไม่ได้เป็น read-only จริง
  • งานอย่างอัปเดต DNS, แก้คอนฟิก Nginx และแก้ webhook ควร ทำเป็นสคริปต์
    • ถ้าต้องจัดการไซต์ 34 แห่งขึ้นไปด้วยมือ จะใช้เวลานานและเพิ่มโอกาสผิดพลาด
  • ชุด mydumper + myloader เร็วกว่า mysqldump มากเมื่อใช้กับชุดข้อมูลขนาดใหญ่
    • การ dump และ restore แบบขนาน 32 เธรด ลดงานที่กินเวลาหลายวันให้เหลือไม่กี่ชั่วโมง
  • สำหรับ steady-state workload ผู้ให้บริการคลาวด์อาจมีราคาสูงเกินไป และ dedicated server อาจให้ประสิทธิภาพสูงกว่าในต้นทุนที่ต่ำกว่า

สคริปต์บน GitHub

  • สคริปต์ Python ทั้งหมดที่ใช้ในการย้ายถูกเผยแพร่บน GitHub
  • รายการสคริปต์ที่รวมอยู่
    • do_list_domains_ttl.py
      • ใช้ดู A record, IP และ TTL ของทุกโดเมนใน DigitalOcean
    • do_ttl_update.py
      • ลด TTL ของทุก A/AAAA record ลงเหลือ 300 วินาทีแบบรวดเดียว
    • do_to_hetzner_bulk_dns_records_import.py
      • ย้ายทุก DNS zone จาก DigitalOcean ไปยัง Hetzner DNS
    • do_cutover_to_new_ip.py
      • สลับ A record ทั้งหมดจาก IP ของเซิร์ฟเวอร์เดิมไปยัง IP ของเซิร์ฟเวอร์ใหม่
    • nginx_reverse_proxy_update.py
      • แปลงคอนฟิก nginx site ทั้งหมดให้เป็น reverse proxy
    • mysql_compare.py
      • เปรียบเทียบจำนวน row ของทุกตารางระหว่าง MySQL สองเซิร์ฟเวอร์
    • final_gitlab_webhook_update.py
      • อัปเดต GitLab project webhook ทั้งหมดให้ชี้ไปยัง IP ของเซิร์ฟเวอร์ใหม่
    • mydumper
      • ไลบรารี mydumper
  • ทุกสคริปต์รองรับโหมด DRY_RUN = True เพื่อให้พรีวิวอย่างปลอดภัยก่อนใช้งานจริง

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

 
GN⁺ 11 일 전
ความคิดเห็นจาก Hacker News
  • เมื่อหลายเดือนก่อนฉันย้ายเซิร์ฟเวอร์สองเครื่องจาก Linode และ DO ไป Hetzner แล้วลดค่าใช้จ่ายได้ มหาศาลในระดับใกล้เคียงกัน สิ่งที่น่าประทับใจกว่าคือมันเป็น สแตกสุดยุ่งเหยิง ที่มีหลายสิบเว็บไซต์ ใช้หลายภาษา มีไลบรารีเก่า ๆ ปนกันไปหมด รวมถึง MySQL และ Redis ด้วย แต่ Claude Code ย้ายทั้งหมดให้ แถมยังเขียนโค้ดบางส่วนใหม่เพื่อจัดการกับไลบรารีที่ไม่มีให้อีกด้วย ตอนนี้การย้ายระบบซับซ้อนแบบนี้ง่ายขึ้นมาก เลยคิดว่าอนาคตการย้ายข้ามผู้ให้บริการน่าจะยิ่งทำได้คล่องขึ้น

    • ฉันคิดว่าที่คนยอมจ่ายเงินกัน ไม่ใช่เพราะ คอมพิวต์วิเศษเหมือนเวทมนตร์ แต่เพราะไม่อยากไปแตะ glue code ที่แปะ ๆ ทับถมกันมา 10 ปีมากกว่า แต่ถ้าเอเจนต์เริ่มกลืน glue พวกนั้นได้ moat ของผู้ให้บริการเดิมก็คงบางลงเร็วมาก
    • พูดตามตรง มันให้ความรู้สึกเหมือนเป็น โฆษณา Claude ที่มีโฆษณา Hetzner ซ้อนอยู่อีกที สงสัยเลยว่าจะซ้อนไปได้อีกกี่ชั้น
    • รู้สึกว่าไม่จำเป็นต้องลากทุกเรื่องไปเป็น เรื่อง AI เสมอไป
    • ฉันเองก็กำลังจะย้ายออกจาก Linode ในอีกไม่กี่เดือนนี้ ใช้มามากกว่า 10 ปีแล้ว แถมยังแนะนำลูกค้าไปเยอะด้วย แต่เขาขึ้นราคาต่อเนื่องจนตอนนี้ที่อย่าง Hetzner ได้ แรมมากกว่า 8 เท่า, NVMe แบบ dedicated และ CPU แบบ dedicated ถูกกว่าอยู่ดี ข้อดีเรื่องย้าย VM ได้ง่ายอาจหายไปนิดหน่อย แต่ถึงจะมีปัญหา Hetzner support ก็เร็วและมีความสามารถเสมอ
    • ฉันเองก็ใช้ Claude กับงาน DevOps มากขึ้นเรื่อย ๆ ฉันรัน VM บน Proxmox บนเครื่องเบียร์เมทัลของตัวเอง แล้ว Claude ก็ช่วยปรับแต่งและตั้งค่าเครือข่ายใหม่ที่พาดหลายเครื่องได้เร็วมาก จนรู้สึกเหมือนเพื่อนร่วมงานหรือ sysadmin ที่ค่าตัวแพงคนหนึ่ง
  • ฉันกำลังวางแผนย้ายจาก AWS ไป Hetzner Amazon บางครั้งตั้งราคา แพงกว่าคู่แข่งถึง 20 เท่า แล้วถ้าอยากได้ราคาที่พอรับได้ก็ต้องผูกมัดระยะยาว แถมยังทำให้การย้ายข้อมูลออกมีค่าใช้จ่ายสูงมากจนรู้สึกว่า เป็นปฏิปักษ์กับลูกค้า สุด ๆ พวกเขาอาจคิดว่าค่าธรรมเนียม egress จะช่วยกักคนไว้ แต่จริง ๆ แล้วมันกลายเป็นแรงกดดันให้คนย้ายทั้งระบบ เมื่อแค่ย้ายบางส่วนไปหาคู่แข่งก็เริ่มคุ้มแล้ว อย่างไรก็ตาม ของฉันย้ายง่ายขึ้นหน่อยเพราะไม่ได้สร้างแพลตฟอร์มทับบนบริการเฉพาะของ Amazon

    • ประเด็นนี้เคยจริงในอดีต แต่บรรยากาศเปลี่ยนไปตั้งแต่เดือนมกราคม 2024 ที่ GCP ออก นโยบายยกเว้นค่า egress แล้ว AWS ก็ออก นโยบายคล้ายกัน ตามมาไม่กี่เดือนหลังจากนั้น ไม่ได้จะชวนให้อยู่ต่อ แค่อยากบอกว่าในทางเทคนิคสามารถขอ waiver ได้ ส่วนจะครอบคลุมแค่ไหนฉันก็ไม่แน่ใจ และจากข้อความของ AWS ก็ดูเหมือนจะเกี่ยวกับ EU Data Act ด้วย
  • ทุกครั้งที่เห็นบทความแบบนี้ ฉันมักแปลกใจที่คนไม่ค่อยพูดถึง redundancy หรือพวก load balancer เลย ถ้าเซิร์ฟเวอร์เครื่องเดียวตาย หลายบริการก็อาจล่มพร้อมกัน เลยสงสัยว่าทุกคนมองว่ามันโอเคจริง ๆ เหรอ อาจประหยัดเงินได้ก็จริง แต่สุดท้ายอาจต้องเสียเวลา maintenance และเจอปัญหาในอนาคตมากขึ้น

    • ผมว่ามันขึ้นอยู่กับลักษณะบริการและความสำคัญของมัน ถ้าเซิร์ฟเวอร์เครื่องหนึ่งรันอยู่ 10 ปี แล้วในช่วงนั้นล่มรวมกันแค่ประมาณ 1 สัปดาห์ถึง 1 เดือน สำหรับหลายกรณีก็ถือว่ายอมรับได้ ธุรกิจขนาดเล็ก เว็บไซต์งานอดิเรก ฟอรัม หรือบล็อก ที่เว็บไม่ใช่งานหลักขององค์กร อาจไม่ได้เดือดร้อนมากกับ downtime สั้น ๆ จริง ๆ แล้วเว็บทราฟฟิกต่ำจำนวนมหาศาลเหล่านี้อาจเป็นเว็บส่วนใหญ่ของโลกด้วยซ้ำ ไม่ใช่ทุกอย่างต้องมี high availability และถ้าต้องการ ผู้ให้บริการแบบนี้ก็มีฟีเจอร์อย่าง load balancer ให้เหมือนกัน
    • เหตุผลที่โพสต์แบบนี้มักได้รับความนิยม ผมว่ามันมักเผยให้เห็น ความไม่ตรงกันระหว่างข้อกำหนดกับวิธีแก้ปัญหา ถ้าเป็นโปรเจกต์งานอดิเรกหรือธุรกิจเล็ก ๆ ที่ไปแบกสถาปัตยกรรมระดับองค์กรจน overengineered ทั้งที่ล่มสักวันหนึ่งก็ยังรับได้ ก็อาจไม่จำเป็นต้องมีชุดคลาวด์เต็มรูปแบบแบบนั้น อย่างไรก็ดี บทความนี้ค่อนข้างแปลกตรงที่เน้น การย้ายแบบไร้ downtime แต่โครงสร้างปลายทางกลับดูไม่ได้ทนทานต่อความล้มเหลวมากนัก ทั้งที่ถ้าเติมโครงสร้างเพิ่มบน Hetzner อีกนิดก็น่าจะดีขึ้นได้มาก
    • สำหรับ workload จำนวนมาก ผมว่าไม่จำเป็นต้องป้องกันระดับนั้น และอย่าประเมิน ความน่าเชื่อถือของความเรียบง่าย ต่ำเกินไป ผมทำงานเป็น Linux sysadmin มานาน เห็น downtime ในระบบซับซ้อนมากกว่าระบบเรียบง่ายเยอะมาก ที่ไหนสักแห่งระหว่างทฤษฎีกับความจริง ผมเลยได้ความรู้สึกว่าสุดท้ายแล้วของที่เรียบง่ายมักอยู่รอดได้ดีกว่า
    • ถ้าจะพูดให้แฟร์ เดิมทีก็ใช้ VM เดี่ยว บน DigitalOcean อยู่แล้ว เลยไม่ได้ใช้ประโยชน์จากข้อดีของผู้ให้บริการคลาวด์มากนัก ปกติบทความแนวนี้มักแบ่งเป็นกรณีที่ขึ้นคลาวด์ด้วยเหตุผลผิดตั้งแต่แรกแล้วควรกลับไปฝั่ง physical กับกรณีที่ย้ายแบบนั้นแล้วจะกลายเป็นหายนะ ซึ่งเคสนี้ดูใกล้เคียงแบบแรกมากกว่า ถ้าคอนฟิกเดิมรันบน DO ได้ดี บน Hetzner ก็น่าจะโอเคเช่นกันถ้าใส่นโยบาย DR ที่เหมาะสม
    • เป็นไปได้ว่าการตัดสินใจนี้มาจากประสบการณ์ที่จริง ๆ แล้วยังไม่ค่อยเคยเจอ maintenance hell หรือปัญหาปวดหัวในอนาคตเท่าไรนัก
  • พวกเราที่ lithus.eu เคยย้ายลูกค้าจากหลายคลาวด์มา Hetzner บ่อย ๆ โดยทั่วไปจะจัดแบบ หลายเซิร์ฟเวอร์ บางครั้งก็หลาย AZ แล้วใช้ Kubernetes กระจาย workload เพื่อให้ได้ HA ถ้ามีแค่โหนดเดียว Kubernetes อาจจะเกินจำเป็น แต่ถ้ามีหลายโหนดมันสมเหตุสมผลขึ้นมาก เรื่องแบ็กอัปเราใช้ทั้ง Velero และแบ็กอัประดับแอป เช่น Postgres ก็ใช้ WAL backup เพื่อให้ทำ PITR ได้ด้วย ข้อมูลสถานะจะเก็บไว้บนอย่างน้อยสองโหนดเพื่อรับประกัน HA ในแง่ประสิทธิภาพ เบียร์เมทัลก็มักจะดีกว่าด้วย และหลายครั้ง latency ลดลงครึ่งหนึ่งเมื่อเทียบกับ AWS ผมคิดว่าเหตุผลไม่ใช่แค่ตัว virtualization เอง แต่เป็นปัจจัยแวดล้อมอย่าง NVMe, network latency ที่ต่ำกว่า และ cache contention ที่น้อยกว่า รายละเอียดเพิ่มเติมเคยเขียนไว้ใน โพสต์ HN ก่อนหน้านี้

    • ผมก็เคยวัดเองเมื่อหลายปีก่อน แล้วหลังจากนั้นก็แทบไม่หันกลับไปมอง virtual server อีกเลย เวลา CPU ไม่ได้ถูกจองแบบ RAM ดังนั้นเมื่อเทียบกับฮาร์ดแวร์จริงแล้วประสิทธิภาพมันแย่มาก ลองดู บทความการวัดผล นี้ได้
    • รู้สึกว่า ดีพลอย k8s เหมาะกับการย้ายไปมาอย่างมาก vendor lock-in น้อยกว่าพวก managed service ของหลายคลาวด์ สแตกของฉันก็มีประมาณ k8s, hosted Postgres และ storage แบบ s3 เท่านั้น ดังนั้น Postgres จะย้ายมาดูแลเองเมื่อไรก็ได้ สุดท้ายแกนหลักจริง ๆ ก็เหลือแค่ k8s กับ s3 ประมาณนั้น เห็นว่า Hetzner ก็มีอะไรคล้าย s3 เหมือนกัน แต่ยังไม่ได้ลองดู และการย้ายข้อมูล 100TB ก็ดูเป็นงานใหญ่พอสมควร
    • เผื่อใครไม่ทราบ HA ย่อมาจาก high availability
    • ตัวบทความดูมีเหตุผลดี แต่ท้ายโพสต์ที่ใส่อีเมลไว้ทำให้รู้สึกเหมือนเป็น ข้อความโปรโมต ไปหน่อย เสียดายตรงนั้น
  • อ่านบทความนี้ค่อนข้างลำบาก รู้สึกเหมือน Claude เป็นคนทำ migration แล้วหลังจากนั้นเราก็ต้องมาอ่าน รายงาน ที่ Claude เขียนต่ออีกที ถ้า LLM ช่วยให้ประหยัดได้ขนาดนี้ก็น่าชื่นชม แต่ถ้าจะเผยแพร่เป็นบทความ อย่างน้อยก็น่าจะช่วยขัดเกลา ตัดความซ้ำ และเก็บ สำนวนแบบ LLM ออกบ้าง

    • รู้ว่ามีหลายคนไม่อ่านต้นฉบับ แต่โพสต์นี้อ่านยากแบบ ทรมานจริง ๆ
  • รู้สึกว่าต้องระวัง Hetzner เหมือนกัน เมื่อก่อนฉันชอบมาก แต่ช่วงหลังย้ายออกแล้ว พวกเขาปิด VM ทั้งหมดประมาณ 30 เครื่องที่ใช้ใน CI/CD pipeline ของเรา เพราะมี ข้อพิพาทบิล 36 ดอลลาร์ แค่รายการเดียว ทั้งที่เราส่งหลักฐานการจ่ายครบถ้วนรวมถึงรายการจากธนาคารไปให้แล้ว แต่พวกเขาไม่ยอมดู แม้เราจะพยายามติดต่อด่วน สุดท้ายก็โดนตัดการเข้าถึงทั้งหมด ตอนนี้ย้ายไป Scaleway แล้ว

    • รู้สึกว่าฝ่ายบริการลูกค้า ค่อนข้างเป็นปฏิปักษ์ อย่างน่าประหลาดใจ ถึงอย่างนั้นฉันก็ยังใช้กับงานที่ไม่สำคัญอยู่
    • ระบบจัดการบิลของ Hetzner ค่อนข้าง อัตโนมัติ แต่ปกติถ้าตัดบัตรไม่ผ่าน พวกเขาก็มักให้เวลาผ่อนผันประมาณหนึ่งเดือน
  • เมื่อไม่กี่เดือนก่อนฉันมองหาทางเลือกแทน AWS สำหรับโปรเจกต์ SaaS เล็ก ๆ ที่ทำเป็น side project ตอนแรกก็พิจารณา Hetzner อย่างจริงจังทั้งเพราะต้องการลดต้นทุนและอยากสนับสนุนคลาวด์ใน EU ถึงจะต้องทำอะไรเองมากหน่อยก็พร้อมรับได้ แต่สุดท้ายสิ่งที่เป็นตัวฉุดจริง ๆ คือ ชื่อเสียงของ IP กฎไฟร์วอลล์แบบ managed ของ AWS ที่บริษัทฉันใช้มีอันหนึ่งที่บล็อก IP ของ Hetzner จำนวนมาก หรืออาจทั้งหมดเลยด้วยซ้ำ และแม้แต่บนโน้ตบุ๊กทำงานของฉัน เว็บไซต์ที่โฮสต์บน IP ของ Hetzner ก็เปิดไม่ได้เพราะนโยบาย IT จะใช้ Cloudflare ก็น่าจะช่วยได้บ้าง แต่ก็เคยเห็นคนพูดว่า DDoS protection ยังอ่อนอยู่ สุดท้ายฉันเลือก DO App Platform ในรีเจียน EU และตัวเลือก managed DB ก็เป็นข้อได้เปรียบใหญ่เช่นกัน

    • ถ้า Amazon บล็อกคู่แข่งแบบนี้ได้ มันก็เป็นวิธีที่ สะดวกดีมาก สำหรับ Amazon เลยนะ
    • ไม่แน่ใจว่าหมายถึงกฎไฟร์วอลล์ตัวไหน แต่ที่ว่า DO น่าเชื่อถือกว่า Hetzner นี่ค่อนข้างน่าแปลกใจ เพราะเวลาเจอ scraper หรือแฮ็กเกอร์ ฉันก็เห็น DO ASN บ่อยเหมือนกัน เลยรู้สึกว่าสักวันหนึ่งฝั่งนั้นก็น่าจะโดนบล็อกได้เหมือนกัน
    • จากประสบการณ์ของฉัน IP ของ DO แย่กว่าอีก ฉันก็ย้ายออกจาก DO เพราะเหตุผลนี้เหมือนกัน
    • ก่อนหน้านี้ฉันเคยเขียนถึงประเด็นนี้ไว้ใน กระทู้เกี่ยวกับ Tor เคยเดาว่าเพราะ Hetzner เป็นมิตรกับ Tor เลยอาจกระทบชื่อเสียงของ IP แต่ตอนนั้นก็มีคนตอบว่าปัญหาเรื่อง reputation ไม่มีเหมือนกัน อย่างไรก็ตาม พอไปดู ข้อมูลจาก Tor Project ก็ดูเหมือน Hetzner จะคิดเป็นราว 7% ของเครือข่าย Tor ทำให้เรื่องนี้ดูไม่ง่ายขนาดนั้น
    • น่าขันดีที่สำหรับฉัน แค่ บล็อก AWS กับ Azure ก็แก้ปัญหาบอตได้ 99% แล้ว และไม่กระทบผู้ใช้จริงเลยสักนิด ถึงขั้นคิดอยู่เลยว่าจะทำฟีเจอร์บล็อกแบบนี้เป็นบริการขายไปเลยดีไหม
  • การแชร์ประสบการณ์ migration แบบนี้มีประโยชน์มากและน่าขอบคุณ ฉันมองการเทียบ DO กับ Hetzner คล้าย trade-off ระหว่างเปิด DoorDash หรือ UberEats กับการลงมือทำมื้อเย็นเอง สัดส่วนเรื่องต้นทุนก็ให้ความรู้สึกคล้ายกัน ฉันดูแลทั้ง 3 big cloud และ on-prem แต่สำหรับงานจุกจิกหรือการทดสอบ PoC ฉันก็ยังกลับไปใช้คอนโซลของ DigitalOcean อยู่ดี ความ สะดวก แบบกดไม่กี่ปุ่มก็ได้เซิร์ฟเวอร์หรือบักเก็ต มี sane default และเปิดแบ็กอัปได้ด้วยเช็กบ็อกซ์เดียว มันมีคุณค่าแน่นอนเมื่อคิดรวมกับมูลค่าของเวลา

    • ไม่แน่ใจเต็มที่ว่าอีกฝ่ายหมายถึงอะไร แต่ฉันรู้สึกว่า Console ของ Hetzner ก็ทำงานคล้ายกัน
    • สิ่งที่น่าสนใจในบทความนี้มีสองอย่าง อย่างแรกคือขั้นตอน ย้ายแบบไร้ downtime ซึ่งอันนี้ใช้เป็นแนวทางทั่วไปได้ อีกอย่างคือการตัดสินใจเปลี่ยนจาก cloud instance ไปเป็นเบียร์เมทัล ซึ่งต้องนับรวมต้นทุนด้านการสลับไปเครื่องสำรองอย่างรวดเร็วและความเสี่ยงเรื่องแบ็กอัปสูญหายเข้าไปในราคาเช่นกัน ถ้าเป็นฉันคงยอมจ่ายเพิ่มราว 200 ดอลลาร์เพื่อมี hot spare สักตัว แล้วสลับเครื่องหลัก/สำรองทุกไม่กี่วันเพื่อยืนยันว่าทั้งคู่ยังใช้งานได้ วิธีนี้ลดความเสี่ยงจากความล้มเหลวร้ายแรงได้มากเมื่อเทียบกับค่าใช้จ่ายที่เพิ่มขึ้นไม่มาก
    • ที่เพิ่งอธิบายไปจริง ๆ แล้วแทบเหมือนประสบการณ์ที่ Hetzner Cloud มีให้มาหลายปีแล้ว แถมยังมี Hetzner Cloud API ด้วย จนสามารถจัดทุกอย่างด้วย IaC ได้โดยไม่ต้องกดปุ่มเลย
    • ในกรณีของฉัน ฉันติดตั้ง Coolify บนเซิร์ฟเวอร์ Hetzner แล้วได้ประสบการณ์ที่แทบจะเหมือนบริการแบบคลิกเดียว
    • อ่านสถานการณ์นี้แล้วทำให้นึกถึง xkcd นี้ ขึ้นมาเลย
  • ฉันสงสัยว่าเขาทำแบ็กอัป DB กันอย่างไร มี replica หรือ standby ไหม หรือแค่แบ็กอัประดับรายชั่วโมงเฉย ๆ ใน สถาปัตยกรรมเซิร์ฟเวอร์เดี่ยว แบบนี้ ถ้าเจอฮาร์ดแวร์เสียอย่าง SSD พัง แอปก็อาจหยุดทันที และโดยเฉพาะถ้า SSD ตาย อาจต้องล่มเป็นชั่วโมงหรือเป็นวันระหว่างตั้งใหม่ทั้งหมด

    • ปกติ Hetzner จะขายฮาร์ดแวร์เซิร์ฟเวอร์พร้อม 2x 1TB SSD และแนะนำอย่างหนักให้ตั้งค่าเป็น SW RAID1 เพื่อให้ได้ความจุใช้งานสุทธิ 1TB ตัวติดตั้งอิมเมจเองก็ตั้งต้นมาในแนวทางนี้ หากอีกหลายปีให้หลัง SSD ลูกแรกพัง ถ้ามี monitoring จับได้ ก็ยังย้ายไปเครื่องใหม่ ใช้ทางออกชั่วคราว/replica หรืออยู่ต่อบนดิสก์อีกลูกพร้อมรอ hot-swap ได้ แน่นอนว่าเมื่อไปฝั่ง physical คุณจะเสีย redundancy บางส่วนของคลาวด์ไป ดังนั้นต้องคิดความเสี่ยงนี้รวมกับเงินที่ประหยัดได้ด้วย และอย่างน้อยถ้าไม่มีแม้แต่ แบ็กอัปประจำวัน ไปยังที่เก็บระยะไกลเลย ก็ถือว่าบ้าบิ่นเกินไป ซึ่งเรื่องนี้บนคลาวด์ก็เหมือนกัน เพียงแค่ตั้งค่าได้ง่ายกว่า
    • ต่อให้ล่มนานขนาดนั้น อาจไม่มีใครใส่ใจมากก็ได้ เช่น ถ้าแอป HOA บนมือถือของฉันล่มไปหนึ่งสัปดาห์ ฉันก็ไม่ได้สนใจอะไร ไม่ใช่ทุกอย่างต้อง พร้อมใช้งานตลอดเวลา
    • ฉันก็มีความกังวลแบบเดียวกัน บทความนี้ให้ความรู้สึกว่าผู้เขียนมองแต่ การลดต้นทุนแบบดุดัน โดยไม่ได้คิดให้รอบด้านพอ VM บน DigitalOcean น่าจะมี live migration และ snapshot ให้ แต่บน Hetzner นั่นใช้ได้กับสินค้า cloud เท่านั้น สำหรับ Hetzner เบียร์เมทัล ถ้าดิสก์หรือชิ้นส่วนตายก็คือตายเลย ถึงจะเปลี่ยนดิสก์ให้ แต่การกู้คืนผู้ใช้ต้องทำใหม่เองทั้งหมด ซึ่ง Hetzner ก็ชี้แจงเรื่องนี้ไว้อย่างชัดเจนหลายแห่ง
    • สิ่งที่ฉันเคยทำแล้วง่ายที่สุดคือฝั่ง MongoDB ซึ่ง replication, sharding และ failover ทำได้ง่ายมาก ส่วนช่วงหลังกับ PostgreSQL ฉันใช้ pg_auto_failover โดยมี monitor 1 เครื่อง, primary 1 เครื่อง และ replica 1 เครื่อง พอเรียนรู้การตั้งค่าและหลุมพรางต่าง ๆ แล้ว มันก็ไม่ได้ยากมากนัก จากประสบการณ์ของฉัน การย้ายแบบไร้ downtime ก็ทำได้ด้วย
    • ถ้าพวกเขาประเมินแล้วว่ายอมรับ trade-off แบบนั้นได้ ก็ไม่ควรสรุปว่าเป็นการตัดสินใจผิด ทุกแอปไม่ได้ต้องการการใช้งานได้ตลอด 24/7 และเว็บไซต์ส่วนใหญ่ก็ไม่ได้เสียหายหนักถ้าล่มสักไม่กี่ชั่วโมง หากเงินที่ประหยัดได้มีค่ามากกว่าความเสี่ยง มันก็อาจเป็น การตัดสินใจทางธุรกิจ ที่สมเหตุสมผล สิ่งที่ฉันอยากรู้มากกว่าคือพวกเขามียุทธศาสตร์เรื่องแบ็กอัปและการกู้คืนอย่างไร และมีอะไรเปลี่ยนไปบ้างหลังย้ายมา Hetzner
  • ภาพมีม ในส่วนหัวเป็นภาพที่ฉันทำเอง เดิมเอาไปใช้ใน บทความนี้ พอเห็นมันถูกใช้ถึง สองครั้ง ก็รู้สึกดีใจ