GaiaEx AcademyGaiaEx Academy
Go สำหรับระบบกระจายและไมโครเซอร์วิส
นักพัฒนาการเขียนโปรแกรม10 min read

Go สำหรับระบบกระจายและไมโครเซอร์วิส

เรียบง่าย รวดเร็ว และสร้างมาเพื่อการทำงานพร้อมกัน

แชร์โพสต์

ทำไม Go ถึงครองตลาด Cloud Infrastructure

Go ถูกออกแบบมาสำหรับระบบเครือข่ายขนาดใหญ่โดยเฉพาะ: คอมไพล์เร็ว ภาษาเรียบง่าย และ standard library ด้าน I/O ที่แข็งแรง นี่คือเหตุผลที่ Docker, Kubernetes, Terraform, etcd และเครื่องมือ infra อีกมากมายถูกส่งออกมาในรูปแบบไฟล์ไบนารีแบบ static ตัวเดียว

Go ไม่ใช่ภาษาที่เร็วที่สุดต่อรอบ CPU แต่มันมักเป็นตัวเลือกที่ทำให้ทีมพัฒนาส่งงานขึ้น production ได้เร็วที่สุด สำหรับ service ที่ใช้เวลาส่วนใหญ่ไปกับ RPC, การซีเรียลไลซ์ข้อมูล และการ fan-out — ซึ่งตรงกับ backend ของตลาดแลกเปลี่ยนส่วนใหญ่ที่ไม่ใช่ core การจับคู่คำสั่งซื้อขาย

สแต็กในสไตล์ GaiaEx ใช้ Go ในจุดที่ throughput และความเรียบง่ายสำคัญกว่าการรีดเวลาระดับนาโนวินาทีสุดท้ายออกจาก hot loop

Goroutine และ Channel: ทำให้ Concurrency เป็นเรื่องง่าย

Goroutine คือ task แบบ concurrent ในระดับ user-space ที่มีต้นทุนต่ำ ส่วน channel คือช่องทางส่งข้อความระหว่าง goroutine เหล่านั้น หลักคิดแบบ CSP คือ: เลือกใช้การส่งข้อความมากกว่าการแชร์หน่วยความจำ — เรื่องนี้ยังต้องอาศัยความมีวินัยในการเขียนโค้ด ไม่ใช่เวทมนตร์

func processOrders(orders <-chan Order) {
    for order := range orders {
        go handleOrder(order)
    }
}

Channel ส่งค่าที่มีชนิดข้อมูลกำหนดไว้แน่นอน; select ใช้สำหรับ multiplex การรอหลายทางเข้าด้วยกัน ให้ใช้คู่กับ go test -race — โค้ดด้านการเงินที่เกิด data race ไม่ใช่แค่ "eventually consistent" แต่มันผิดตรง ๆ

Concurrency เขียนได้ง่าย แต่ความถูกต้องยังต้องแลกมาด้วยการทดสอบและการรีวิวโค้ด

Goroutines fan out (conceptual) main() go worker go worker go worker channels coordinate without shared locks (idealized)
Task ที่มีต้นทุนต่ำ + การส่งต่องานอย่างชัดเจน — รูปแบบมาตรฐานของ network service ที่เขียนด้วย Go

การสร้าง HTTP Service และ gRPC ด้วย Go

net/http เพียงพอสำหรับ API หลายแบบ; router เสริมเรื่องการจับคู่เส้นทาง (muxing) และ middleware เข้ามา ส่วน gRPC + protobuf จะโดดเด่นภายในดาต้าเซ็นเตอร์: payload เล็กลง มี codegen รองรับ streaming — มีประโยชน์มากเมื่อ traffic ภายในมีขนาดใหญ่กว่า JSON ที่ส่งออกไปนอกระบบมาก

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("GET /api/v1/ticker/{symbol}", handleTicker)
    mux.HandleFunc("POST /api/v1/orders", handleNewOrder)
    server := &http.Server{Addr: ":8443", Handler: mux, ReadTimeout: 5 * time.Second}
    log.Fatal(server.ListenAndServeTLS("cert.pem", "key.pem"))
}

Interface ใน Go เป็นแบบ implicit — สามารถ mock ชั้น storage ในการทดสอบได้โดยไม่ต้องพึ่ง framework ที่หนักอึ้ง

Typical Go service sandwich HTTP / gRPC transport + middleware domain logic (risk checks, authz, orchestration) storage & clients (SQL, cache, message bus)
ให้ transport layer เบาที่สุด และให้ตรรกะที่เกี่ยวกับเงินสามารถทดสอบได้โดยไม่ต้องเปิด listening socket

Go ใน Blockchain Node และ Backend ของตลาดแลกเปลี่ยน

Geth, สแต็กตระกูล Cosmos/Tendermint, Fabric, Cockroach — Go ปรากฏอยู่ทั่วไปในโลกของบล็อกเชนและฐานข้อมูล ส่วนงานเชื่อมต่อของตลาดแลกเปลี่ยน — gateway, การตรวจสอบความเสี่ยงเบื้องต้น, websocket fan-out — ก็เหมาะกับ Go โดยธรรมชาติ

เครื่องจับคู่คำสั่งซื้อขายที่ทำงานในระดับไมโครวินาทีหลักเดียวยังคงเป็นพื้นที่ของ C++/Rust เป็นส่วนใหญ่ ส่วนทุกอย่างที่อยู่รอบ ๆ นั้นเป็นพื้นที่ที่ Go เล่นได้เต็มที่

GaiaEx ใช้ Go สำหรับขอบด้าน API และฟีดข้อมูลแบบเรียลไทม์; การประมวลผลคำสั่งบน Hyperliquid L1 เป็นอีกเลเยอร์หนึ่งที่แยกออกไป — ต้องรู้ให้ชัดว่าคุณรับผิดชอบงบเวลาความหน่วง (latency budget) ส่วนไหน

การจัดการ Error, การทดสอบ, และ Go Modules

การ return error อย่างชัดเจนนั้นดูยืดยาวแต่ตรงไปตรงมา — สำหรับงานที่เกี่ยวกับการเคลื่อนย้ายเงิน การกลืน error ทิ้งไปเงียบ ๆ ถือเป็นเรื่องที่ยอมรับไม่ได้ ให้ wrap error ด้วย %w เพื่อให้ผู้เรียกสามารถจำแนกประเภทความล้มเหลวได้

go test, benchmark และ pprof เป็นเครื่องมือระดับหนึ่งของภาษา Table-driven test ช่วยให้เห็น test case ได้ชัดเจน

Modules ล็อกเวอร์ชันผ่าน go.mod/go.sum — การ build ที่ทำซ้ำได้เหมือนกันทุกครั้งมีความสำคัญมาก เมื่อ production ไม่ใช่แล็ปท็อปของคุณเอง

เมื่อไหร่ควรเลือก Go — และเมื่อไหร่ไม่ควร

เหมาะสม: network service, CLI, operator, งานที่ใช้ CPU ปานกลางแต่มี I/O หนัก

ไม่เหมาะสม: การจับคู่คำสั่งซื้อขายที่ต้องการความหน่วงต่ำที่สุด, งาน real-time ที่ต้องการันตีแบบเข้มงวดโดยไม่มี GC pause, งาน machine learning เชิงตัวเลขหนัก ๆ — ต้องเลือกเครื่องมือที่เหมาะกับงาน

Go จะชนะเมื่อเรื่องการส่งงานและการดูแลระบบสำคัญพอ ๆ กับ QPS สูงสุดตามทฤษฎี — ซึ่งตรงกับ infrastructure ส่วนใหญ่ที่อยู่รอบ ๆ การเทรด