Rust vs Go: Chọn ngôn ngữ nào cho dự án của bạn?
Là một developer, bạn có thể đã nghe đến cả Rust và Go - hai ngôn ngữ hiện đại đang được nhiều công ty lớn như Google, Amazon, Discord, Cloudflare áp dụng. Nhưng khi nào nên chọn Rust? Khi nào nên chọn Go? Bài viết này sẽ giúp bạn trả lời câu hỏi đó với những ví dụ code cụ thể.
Chọn nhanh trong 30 giây
Chọn Go nếu: Bạn cần ship nhanh, team có junior developers, business logic phức tạp hơn technical complexity, hoặc đang làm microservices/API/DevOps tools.
Chọn Rust nếu: Performance và memory efficiency là critical, cần safety tuyệt đối, làm systems programming, hoặc có requirements về latency < 10ms.
Chọn cả hai: API layer dùng Go, hot paths/compute-intensive modules dùng Rust.
Phần 1: Rust - "Fast & Furious" của Programming Languages
1.1 Memory Safety không cần Garbage Collector
Đây là điểm mạnh đặc trưng nhất của Rust. Hãy xem ví dụ này:
fn process_request(data: Vec<u8>) {
let buffer = data; // ownership chuyển sang buffer
send_to_worker(buffer); // ownership chuyển vào hàm
// println!("{:?}", buffer); // ❌ COMPILE ERROR!
// Compiler báo: "value borrowed here after move"
}
fn send_to_worker(buf: Vec<u8>) {
// worker takes ownership và tự động free memory
}
Tại sao điều này quan trọng?
Trong Go, code tương tự sẽ compile nhưng có thể dẫn đến:
- GC pause (10-50ms) khi heap memory lớn
- Memory leak nếu goroutine vô tình giữ reference
- Use-after-free bugs trong C/C++
Discord đã migrate một service từ Go sang Rust và giảm latency spikes từ 50ms xuống < 5ms chỉ nhờ loại bỏ GC pauses.
1.2 Performance tối đa với Zero-cost Abstractions
// Rust: Code này compile thành tight loop như viết tay bằng C
let numbers: Vec<i32> = vec![1, 2, 3, 4, 5];
let sum: i32 = numbers
.iter()
.filter(|&&x| x % 2 == 0)
.map(|&x| x * x)
.sum();
Benchmark thực tế - JSON parsing:
- Rust (serde_json): 450 MB/s
- Go (encoding/json): 120 MB/s
Amazon Prime Video đã chuyển từ microservices sang Rust monolith và giảm chi phí infrastructure 90% nhờ performance cải thiện.
1.3 Concurrency an toàn - Compiler là bodyguard của bạn
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
// ❌ Không thể access counter mà không lock
// Compiler FORCE bạn handle concurrency correctly
}
Trong Go, code tương tự có thể compile nhưng tạo data race:
// Go: Compiles nhưng có data race!
counter := 0
for i := 0; i < 10; i++ {
go func() {
counter++ // ⚠️ DATA RACE
}()
}
// Cần chạy go run -race để detect
1.4 Type System mạnh mẽ
enum PaymentStatus {
Pending { initiated_at: DateTime },
Processing { transaction_id: String },
Completed { settled_at: DateTime, amount: f64 },
Failed { reason: String },
}
fn handle_payment(status: PaymentStatus) {
match status {
PaymentStatus::Completed { amount, .. } => {
// Compiler đảm bảo amount tồn tại
record_revenue(amount);
}
PaymentStatus::Failed { reason } => {
alert_ops_team(reason);
}
_ => {} // Compiler yêu cầu handle ALL cases
}
}
Pattern matching này không thể tạo ra "impossible states". Go không có tính năng tương đương - bạn phải dùng string constants và hy vọng không ai typo.
Phần 2: Go - "Keep It Simple, Stupid"
2.1 Simplicity - Junior-friendly từ ngày đầu
Đây là HTTP server production-ready trong 20 dòng code:
package main
import (
"encoding/json"
"net/http"
"log"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func getUsers(w http.ResponseWriter, r *http.Request) {
users := []User{
{Name: "Alice", Email: "alice@example.com"},
{Name: "Bob", Email: "bob@example.com"},
}
json.NewEncoder(w).Encode(users)
}
func main() {
http.HandleFunc("/users", getUsers)
log.Fatal(http.ListenAndServe(":8080", nil))
}
Junior developer có thể viết code này sau 1 tuần học Go. Với Rust? Cần 2-3 tháng để hiểu ownership, lifetimes, async/await.
2.2 Fast Compilation - Developer happiness matters
# Go project - 50,000 lines of code
$ time go build
real 0m2.341s # < 3 giây!
# Rust project - 50,000 lines of code
$ time cargo build --release
real 4m23.123s # > 4 phút!
Impact thực tế: Với Go, bạn có tight feedback loop - viết test, chạy (2s), fix bug, chạy lại (2s). Với Rust, mỗi iteration mất 30s-2 phút.
Google's Kubernetes có thể build toàn bộ codebase trong < 5 phút nhờ Go.
2.3 Goroutines - Concurrency for the masses
// Spawn 10,000 concurrent tasks - trivial!
func handleRequests() {
for i := 0; i < 10000; i++ {
go func(id int) {
result := processTask(id)
saveToDB(result)
}(i)
}
}
// Fan-out/fan-in pattern - 5 dòng code
func fetchMultipleAPIs() []Response {
urls := []string{"api1.com", "api2.com", "api3.com"}
results := make(chan Response, len(urls))
for _, url := range urls {
go func(u string) {
results <- fetchAPI(u)
}(url)
}
var responses []Response
for i := 0; i < len(urls); i++ {
responses = append(responses, <-results)
}
return responses
}
Real metrics:
- 1 million goroutines = ~2GB RAM
- 1 million OS threads = system crash
2.4 Tooling tuyệt vời - Batteries included
go fmt ./... # Format code (không cần config!)
go test -race ./... # Detect race conditions
go test -cpuprofile # Profile CPU
go mod graph # Analyze dependencies
go vet ./... # Lint
go doc -http=:6060 # Documentation server
Tất cả built-in, không cần cài thêm gì. Rust cần external tools: rustfmt, clippy, cargo-flamegraph...
2.5 Deploy đơn giản - One binary to rule them all
# Cross-compile cho mọi platform
$ GOOS=linux GOARCH=amd64 go build -o myapp
$ ls -lh myapp
-rwxr-xr-x 1 user user 8.2M Oct 28 10:00 myapp
# Copy lên server - XONG! Không cần dependency
$ scp myapp server:/usr/local/bin/
# Docker image cực nhỏ
FROM scratch
COPY myapp /
CMD ["/myapp"]
# Image size: 8MB!
Dropbox migrate từ Python sang Go và giảm deploy time từ 30 phút xuống 5 phút.
Phần 3: So sánh trực tiếp
| Tiêu chí | Rust | Go |
|---|---|---|
| Learning curve | 3-6 tháng | 1-2 tuần |
| Compile time | Chậm (phút) | Nhanh (giây) |
| Runtime performance | 9.5/10 | 8/10 |
| Memory footprint | Rất thấp | Trung bình (có GC) |
| Developer velocity | Chậm ban đầu | Nhanh |
| Team onboarding | Khó | Dễ |
| Concurrency | Safe nhưng phức tạp | Đơn giản |
| Error handling | Verbose | Pragmatic |
Phần 4: Decision Framework - Khi nào chọn cái gì?
Chọn Rust khi:
✅ Systems Programming
- Operating systems, drivers, embedded systems
- Web browsers (Firefox), game engines
- Cần control tuyệt đối về memory
✅ High-Performance Services
- Trading platforms (latency < 1ms)
- Real-time bidding, game servers
- Data processing với throughput cực cao
✅ Security-Critical Applications
- Cryptography libraries
- Blockchain infrastructure
- Authentication systems
✅ Resource-Constrained Environments
- IoT devices, edge computing
- WebAssembly applications
Example: Cloudflare Workers (Rust) xử lý 1M+ req/s với p99 latency < 5ms
Chọn Go khi:
✅ Microservices & APIs
- REST/gRPC services
- API gateways
- Backend services với business logic phức tạp
✅ Cloud Infrastructure
- Container orchestration (Kubernetes)
- Service mesh, monitoring tools
- CLI tools (Docker, Terraform)
✅ DevOps Tools
- CI/CD pipelines
- Automation scripts
- Infrastructure management
✅ Rapid Development
- MVPs, startups cần ship nhanh
- Internal tools
- Projects với team size lớn
Example: Uber's backend services (Go) - easy to maintain với hàng trăm engineers
Hybrid Approach - Best of both worlds
Nhiều công ty dùng chiến lược này:
┌─────────────────────┐
│ API Gateway (Go) │ ← Easy to change, fast iteration
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Business Logic (Go) │ ← Maintainable, junior-friendly
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Hot Paths (Rust) │ ← Performance-critical modules
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ ML Inference (Rust) │ ← Latency-sensitive workloads
└─────────────────────┘
Real case: Discord dùng Go cho API servers nhưng rewrite message routing service sang Rust để giải quyết latency issues.
Phần 5: Lời khuyên thực tế
1. Đừng chỉ nhìn technical specs
Xem xét các yếu tố này:
Team Capability
- Có bao nhiêu người biết Rust/Go?
- Junior vs Senior ratio?
Hiring Market
- Tuyển Go dev ở Việt Nam dễ hơn Rust rất nhiều
- Go salary competitive, Rust salary cao hơn 20-30%
Ecosystem
- Go: Mature ecosystem cho web/cloud/DevOps
- Rust: Growing ecosystem, excellent cho systems/performance
Maintenance
- 3-5 năm sau ai maintain code này?
- Go code dễ đọc hơn cho người mới
2. Start with Go, optimize with Rust
Chiến lược pragmatic:
Phase 1: Build MVP bằng Go
- Ship nhanh, validate idea
- Easy to iterate và refactor
Phase 2: Identify bottlenecks
- Profile với
pprof - Tìm hot paths (< 5% code thường chiếm 95% CPU)
Phase 3: Optimize hot paths với Rust
- Rewrite chỉ những phần cần thiết
- Call Rust code từ Go qua FFI hoặc microservice
3. Consider your constraints
Chọn Rust nếu:
- [ ] Performance/latency là deal-breaker
- [ ] Memory budget rất chặt (< 100MB)
- [ ] Team có experience với systems programming
- [ ] Project dài hạn (> 2 năm)
- [ ] Ready to invest 3-6 tháng learning curve
Chọn Go nếu:
- [ ] Time-to-market quan trọng
- [ ] Team có nhiều junior developers
- [ ] Business logic > technical complexity
- [ ] Need to iterate quickly
- [ ] "Good enough" performance là đủ
Kết luận
Rust là Ferrari - fast, powerful, nhưng không phải ai cũng lái được.
Go là Toyota Camry - reliable, practical, phù hợp với đa số use cases.
Với majority of web services, Go là lựa chọn pragmatic hơn. Chỉ chọn Rust khi có lý do rõ ràng về performance hoặc safety requirements.
Nhưng đừng quên - bạn không phải chọn chỉ một. Nhiều công ty thành công nhất đang dùng cả hai:
- Go cho phần lớn services (80-90%)
- Rust cho critical paths (10-20%)
Tài liệu tham khảo
All rights reserved