+1

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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí