
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 เขียนได้ง่าย แต่ความถูกต้องยังต้องแลกมาด้วยการทดสอบและการรีวิวโค้ด
การสร้าง 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 ที่หนักอึ้ง
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 ส่วนใหญ่ที่อยู่รอบ ๆ การเทรด