AizuDemy

Tutorial Build Reverse Proxy High Performance dengan Pingora Rust di VPS

Tutorial Build Reverse Proxy High Performance dengan Pingora Rust di VPS
๐ŸŽง
Dengarkan Artikel Ini
Suara AI Otomatis โ€ข 7 mnt baca baca
โšก TL;DR

Poin Kunci Artikel Ini:

  • [x] Install Rust toolchain versi terbaru dan libssl-dev.
  • [x] Konfigurasi routing handler dan injeksi HTTP header.
  • [x] Terapkan strategi Load Balancing (Round-Robin).
๐Ÿ“‹ Daftar Isi Materi Tutup โ–ด

Mengapa Pingora Menggeser Nginx pada Workload Ekstrem

Nginx menjadi standar industri reverse proxy selama dua dekade. Namun, model arsitektur process-per-worker milik Nginx menyimpan keterbatasan struktural saat menangani beban infrastruktur modern skala besar. Keterbatasan utama meliputi overhead context switching antar-proses, pemakaian memori terisolasi per worker yang boros, serta batasan kustomisasi logika routing kompleks yang bergantung pada modul C atau integrasi Lua.

Cloudflare merancang Pingora menggunakan bahasa pemograman Rust untuk menggantikan arsitektur legasi tersebut. Pingora mengadopsi model multi-threaded async execution yang ditenagai oleh runtime Tokio. Pendekatan ini memungkinkan ribuan koneksi berjalan di atas utas thread bersama tanpa isolasi memori antar-worker. Hasil benchmark internal Cloudflare mencatat penurunan penggunaan RAM hingga 70% dan peningkatan efisiensi CPU sebesar 30% dibandingkan Nginx pada skala trafik jutaan request per detik (RPS).

Komparasi Arsitektur Engine: Nginx vs Pingora

Parameter TeknikalNginxPingora Rust
Model EksekusiMulti-process (Worker isolation)Multi-threaded Async (Tokio Runtime)
Keamanan MemoriManual Memory Management (C)Compile-time Memory Safety (Rust)
Kustomisasi LogikaModul C / Lua ScriptingNative Rust Traits & Hooks
Alokasi MemoriDuplikasi status per workerShared Memory via Arc & Atomic operations
Konfigurasi ReloadSIGHUP (Spawn worker baru)Programmatic Zero-Downtime Reload
Handling Connection PoolPer-worker connection reuse limitGlobal async connection pooling

Persiapan Environment VPS Linux

Penerapan Pingora membutuhkan spesifikasi sistem minimal 1 vCPU dan 1 GB RAM pada distro Ubuntu 22.04 LTS atau Ubuntu 24.04 LTS. Pastikan akses root atau privilese sudo tersedia.

1. Install Dependency System

Pasang toolchain kompilasi dasar, OpenSSL, dan utility build yang dibutuhkan Crate Pingora:

sudo apt update && sudo apt install -y build-essential libssl-dev pkg-config curl git cmake

2. Install Rust Toolchain

Pasang Rust compiler versi stabil menggunakan rustup installer:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source $HOME/.cargo/env
rustc --version

Membangun Project Reverse Proxy Pingora

Struktur aplikasi Pingora dibangun sebagai executable binary Rust yang mengimpor library pingora-core dan pingora-proxy.

Langkah 1: Inisialisasi Project dan Dependency

Eksekusi perintah berikut untuk membuat workspace Cargo baru:

cargo new pingora-proxy --bin
cd pingora-proxy

Ubah isi file Cargo.toml untuk mengonfigurasi pustaka Pingora beserta async ecosystem:

[package]
name = "pingora-proxy"
version = "0.1.0"
edition = "2021"

[dependencies]
pingora = "0.3"
pingora-core = "0.3"
pingora-proxy = "0.3"
pingora-load-balancing = "0.3"
async-trait = "0.1"
tokio = { version = "1", features = ["full"] }
env_logger = "0.10"
log = "0.4"

Langkah 2: Arsitektur Lifecycle dan Basic Proxy Handler

Pingora mengendalikan request melalui trait ProxyHttp. Eksekusi alur request terbagi dalam beberapa hook method: request_filter, upstream_peer, dan logging.

Ganti seluruh isi file src/main.rs dengan kode proxy dasar berikut:

use async_trait::async_trait;
use pingora_core::server::Server;
use pingora_core::upstreams::peer::HttpPeer;
use pingora_proxy::{ProxyHttp, Session};

pub struct BasicProxy;

#[async_trait]
impl ProxyHttp for BasicProxy {
    type ServerSessionCtx = ();

    fn new_ctx(&self) -> Self::ServerSessionCtx {}

    async fn upstream_peer(
        &self,
        _session: &mut Session,
        _ctx: &mut Self::ServerSessionCtx,
    ) -> pingora_core::Result<Box<HttpPeer>> {
        // Definisikan alamat IP backend upstream (aplikasi internal)
        let peer = Box::new(HttpPeer::new(
            "127.0.0.1:8080",
            false, // Nonaktifkan TLS ke backend internal
            "".to_string(),
        ));
        Ok(peer)
    }

    async fn upstream_request_filter(
        &self,
        _session: &mut Session,
        upstream_request: &mut pingora_http::RequestHeader,
        _ctx: &mut Self::ServerSessionCtx,
    ) -> pingora_core::Result<()> {
        // Injeksi header kustom sebelum request dikirim ke backend
        upstream_request.insert_header("X-Proxy-Engine", "Pingora-Rust").unwrap();
        Ok(())
    }
}

fn main() {
    env_logger::init();
    let mut server = Server::new(None).unwrap();
    server.bootstrap();

    let mut proxy_service = pingora_proxy::http_proxy_service(
        &server.configuration,
        BasicProxy,
    );
    proxy_service.add_tcp("0.0.0.0:80");

    server.add_service(proxy_service);
    server.run_forever();
}

Implementasi Load Balancer dan TLS Termination

Reverse proxy tingkat produksi mewajibkan distribusi beban ke beberapa backend service serta enkripsi TLS untuk HTTPS.

1. Load Balancer Round-Robin dengan Health Check

Gunakan module pingora_load_balancing untuk mendistribusikan request secara merata ke klaster backend server.

Perbarui file src/main.rs:

use async_trait::async_trait;
use pingora_core::server::Server;
use pingora_core::upstreams::peer::HttpPeer;
use pingora_load_balancing::selection::RoundRobin;
use pingora_load_balancing::LoadBalancer;
use pingora_proxy::{ProxyHttp, Session};
use std::sync::Arc;

pub struct LBProxy {
    lb: Arc<LoadBalancer<RoundRobin>>,
}

#[async_trait]
impl ProxyHttp for LBProxy {
    type ServerSessionCtx = ();

    fn new_ctx(&self) -> Self::ServerSessionCtx {}

    async fn upstream_peer(
        &self,
        _session: &mut Session,
        _ctx: &mut Self::ServerSessionCtx,
    ) -> pingora_core::Result<Box<HttpPeer>> {
        // Pilih node upstream menggunakan algoritma Round Robin
        let upstream = self.lb.select(b"", 256).expect("No upstream available");
        
        let peer = Box::new(HttpPeer::new(
            upstream,
            false,
            "".to_string(),
        ));
        Ok(peer)
    }
}

fn main() {
    env_logger::init();
    let mut server = Server::new(None).unwrap();
    server.bootstrap();

    // Daftar IP backend node
    let upstreams = vec!["127.0.0.1:8081", "127.0.0.1:8082", "127.0.0.1:8083"];
    let lb = LoadBalancer::try_from_iter(upstreams).expect("Failed to build load balancer");

    let mut proxy_service = pingora_proxy::http_proxy_service(
        &server.configuration,
        LBProxy { lb: Arc::new(lb) },
    );
    
    proxy_service.add_tcp("0.0.0.0:80");
    server.add_service(proxy_service);
    server.run_forever();
}

2. TLS Termination (HTTPS Enablement)

Tambahkan sertifikat SSL/TLS (Let's Encrypt atau X.509 certificate) untuk menangani enkripsi HTTPS di port 443:

let mut proxy_service = pingora_proxy::http_proxy_service(
    &server.configuration,
    LBProxy { lb: Arc::new(lb) },
);

// Binding Listener HTTPS Port 443
proxy_service
    .add_tls(
        "0.0.0.0:443",
        "/etc/letsencrypt/live/domainanda.com/fullchain.pem",
        "/etc/letsencrypt/live/domainanda.com/privkey.pem",
    )
    .expect("Failed to bind TLS certificate");

Optimasi Kernel OS dan Systemd Integration

Aplikasi performa tinggi memerlukan penyesuaian batas resource sistem operasi agar tidak membentur limitasi file descriptor default.

1. Optimasi Paramater Sysctl & Open File Limits

Edit file /etc/sysctl.conf untuk mengoptimalkan queue koneksi TCP socket:

net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
fs.file-max = 2097152

Terapkan perubahan kernel secara langsung:

sudo sysctl -p

Ubah limitasi open file descriptor pada /etc/security/limits.conf:

root soft nofile 65536
root hard nofile 65536
www-data soft nofile 65536
www-data hard nofile 65536

2. Build Binary Release dengan Link-Time Optimization (LTO)

Kompilasi binary dengan tingkat optimasi tertinggi menggunakan flag release:

cargo build --release

File executable hasil kompilasi berlokasi di target/release/pingora-proxy.

3. Setup Unit Service Systemd

Salin binary ke direktori sistem:

sudo cp target/release/pingora-proxy /usr/local/bin/

Buat file unit service baru di /etc/systemd/system/pingora.service:

[Unit]
Description=Pingora High-Performance Reverse Proxy
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/pingora-proxy
Restart=always
RestartSec=3s
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Jalankan service dan aktifkan auto-start saat booting:

sudo systemctl daemon-reload
sudo systemctl enable pingora
sudo systemctl start pingora
sudo systemctl status pingora

Checklist Deployment Production

  • [x] Install Rust toolchain versi terbaru dan libssl-dev.
  • [x] Inisialisasi Crate pingora-proxy dan pingora-load-balancing.
  • [x] Konfigurasi routing handler dan injeksi HTTP header.
  • [x] Terapkan strategi Load Balancing (Round-Robin).
  • [x] Bind TLS certificate untuk port 443 HTTPS.
  • [x] Parameterisasi Kernel OS (somaxconn dan file descriptor limits).
  • [x] Kompilasi binary mode release (cargo build --release).
  • [x] Daftarkan dan verifikasi unit service di Systemd.

Troubleshooting Error Umum

1. Error: Permission denied (os error 13)

Penyebab: Binary diakses oleh non-root user saat mencoba melakukan binding port privileged (< 1024) seperti port 80 atau 443.

Solusi: Jalankan service sebagai root atau berikan kapabilitas CAP_NET_BIND_SERVICE pada file binary:

sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/pingora-proxy

2. Error: Too many open files

Penyebab: Lonjakan koneksi berconcurrent tinggi melampaui limit file descriptor bawaan OS.

Solusi: Pastikan nilai LimitNOFILE=65536 telah aktif pada file unit systemd dan parameter sysctl fs.file-max diset lebih besar dari total alokasi koneksi simulasi.

Kesimpulan dan Strategi Migrasi Canary

Pingora Rust menawarkan solusi alternatif modern pengganti Nginx untuk infrastruktur skala besar. Efisiensi memori, performa multi-threading Tokio runtime, serta keamanan memori tingkat compiler menjadikannya kokoh menangani beban tinggi.

Gunakan alur migrasi bertahap (Canary Deployment) untuk meminimalkan risiko downtime:

  1. Rutekan 5%โ€“10% trafik dari edge DNS menuju server Pingora.
  2. Pantau performa latensi p99 dan penggunaan RAM menggunakan tool load test seperti k6 atau wrk.
  3. Tingkatkan rasio bobot trafik secara bertahap setelah penanganan TLS handshake dan koneksi upstream dipastikan stabil.

๐Ÿ“– Artikel Terkait