Service Go untuk upload file ke S3 dan download multiple files sebagai ZIP secara streaming.
- Streaming ZIP Download – File di-zip on-the-fly dan langsung di-stream ke client tanpa perlu menunggu seluruh ZIP selesai dibuat
- No Content-Length – Client tidak perlu tahu ukuran ZIP, download langsung mulai
- Memory Efficient – Server tidak menyimpan ZIP di memory/disk, langsung stream ke client
- Network Throttle Simulation – Testing kondisi jaringan lambat (3G/4G) menggunakan
tc
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Client │────▶│ Go Server │────▶│ LocalStack │
│ (Upload) │ │ (Fiber) │ │ (S3 API) │
└─────────────┘ └─────────────────┘ └─────────────────┘
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Client │◀────│ Go Server │◀────│ S3 File URLs │
│ (Browser) │ │ (Stream ZIP) │ │ (HTTP GET) │
└─────────────┘ └─────────────────┘ └─────────────────┘
│ │
│ Chunked Transfer │
│◀────────────────────│
│ (No Content-Length)
Bagaimana cara kerjanya:
- Client mengirim list URL file yang ingin di-download
- Server fetch file satu per satu dari URL (S3)
- Setiap file langsung di-compress dan di-stream ke client
- Client menerima ZIP secara streaming (download langsung mulai)
- Go – Backend server
- Fiber – HTTP framework
- Swagger – API documentation & testing UI
- AWS SDK Go v2 – S3 client
- LocalStack (Docker) – AWS emulator
- tc (Traffic Control) – Network throttling (bandwidth & latency)
- Go 1.21+
- Docker & Docker Compose
- LocalStack (via Docker image)
- AWS CLI / awslocal
stream-download/
├── main.go # Entry point
├── go.mod # Go modules
├── go.sum # Dependencies checksum
├── .env # Environment variables
├── docker-compose.yml # LocalStack setup
├── config/
│ └── config.go # Configuration loader
├── handler/
│ ├── upload.go # Upload handler
│ └── download.go # Streaming ZIP download handler
├── service/
│ └── s3.go # S3 service layer
└── README.md # Dokumentasi
Buat file .env:
AWS_REGION=ap-southeast-1
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
S3_ENDPOINT=http://localhost:4566
S3_BUCKET=my-bucket
SERVER_PORT=8080docker compose up -dContoh docker-compose.yml:
services:
localstack:
image: localstack/localstack:latest
container_name: localstack-main
ports:
- "4566:4566"
environment:
- SERVICES=s3
- LOCALSTACK_PERSISTENCE=1
volumes:
- localstack_data:/var/lib/localstack
- /var/run/docker.sock:/var/run/docker.sock
cap_add:
- NET_ADMIN
volumes:
localstack_data:
NET_ADMINdiperlukan untuk simulasi network throttle menggunakantc.
awslocal s3 mb s3://my-bucketUntuk mensimulasikan kondisi jaringan lambat (misalnya 3G / 4G / Wi-Fi buruk), gunakan tc (Traffic Control) di dalam container LocalStack.
docker exec -it localstack-main bashInstall tc (sekali saja):
apt-get update
apt-get install -y iproute2tc qdisc add dev eth0 root tbf rate 10mbit burst 256kbit latency 50ms- ~ 1.25 MB/s
- Latency ringan
tc qdisc add dev eth0 root tbf rate 2mbit burst 128kbit latency 200mstc qdisc add dev eth0 root tbf rate 500kbit burst 64kbit latency 600mstc qdisc add dev eth0 root tbf rate 300kbit burst 32kbit latency 800mstc qdisc del dev eth0 rootThrottle akan otomatis hilang jika container direstart.
POST /api/upload
Request:
- Content-Type:
multipart/form-data - Body:
file– File yang akan diuploadfilePath(optional) – Custom path di S3fileName(optional) – Custom filename
Response:
{
"success": true,
"message": "File uploaded successfully",
"data": {
"filename": "example.pdf",
"filePath": "documents/2024",
"url": "http://localhost:4566/my-bucket/documents/2024/example.pdf",
"size": 12345
}
}cURL Example:
curl -X POST http://localhost:8080/api/upload \
-F "file=@/path/to/your/file.pdf" \
-F "filePath=documents/2024" \
-F "fileName=report.pdf"POST /api/download
Request:
- Content-Type:
application/json - Body:
{
"urls": [
"http://localhost:4566/my-bucket/file1.pdf",
"http://localhost:4566/my-bucket/file2.pdf",
"http://localhost:4566/my-bucket/file3.pdf"
]
}Response:
- Content-Type:
application/zip - Transfer-Encoding:
chunked(streaming) - File:
download.zip
cURL Example:
curl -X POST http://localhost:8080/api/download \
-H "Content-Type: application/json" \
-d '{"urls": ["http://localhost:4566/my-bucket/file1.pdf", "http://localhost:4566/my-bucket/file2.pdf"]}' \
--output download.zipKeuntungan Streaming:
| Aspek | Traditional | Streaming |
|---|---|---|
| Memory usage | Tinggi (buffer semua file) | Rendah (stream per chunk) |
| Response time | Lambat (tunggu ZIP selesai) | Cepat (langsung mulai) |
| Content-Length | Diketahui | Tidak perlu |
| File besar | Bisa timeout | Aman |
- Client mengirim file via
multipart/form-data - Handler memvalidasi file
- Service upload ke S3 (LocalStack)
- Return URL file yang diupload
- Client mengirim array of URLs (JSON)
- Server fetch file pertama dari URL via HTTP GET
- File langsung di-compress ke ZIP stream
- Chunk dikirim ke client (Transfer-Encoding: chunked)
- Ulangi untuk file berikutnya
- Client menerima ZIP lengkap setelah semua file selesai
Note: Client tidak perlu tahu ukuran ZIP karena menggunakan chunked transfer encoding. Download langsung mulai tanpa menunggu.
- Jalankan server:
go run main.go - Buka:
http://localhost:8080/swagger/ - Upload file
- Download file dari S3 URL untuk melihat efek throttle
awslocal s3 ls s3://my-bucket/Install k6:
# macOS
brew install k6
# Linux
sudo apt install k6
# atau download dari https://k6.io/docs/getting-started/installation/Aplikasi menyediakan endpoint untuk monitoring memory secara real-time:
-
Memory Stats API:
GET /debug/memorycurl http://localhost:8080/debug/memory
-
Memory Monitor UI:
http://localhost:8080/monitor.html- Grafik real-time untuk Alloc, Heap, Sys Memory
- Goroutines & GC Cycles tracking
- Configurable time window (1m, 5m, 10m, 30m)
-
pprof Profiling:
http://localhost:8080/debug/pprof/go tool pprof http://localhost:8080/debug/pprof/heap
-
Jalankan server
go run main.go
-
Buka Memory Monitor (opsional)
http://localhost:8080/monitor.htmlKlik "Start Monitoring" untuk melihat grafik memory real-time.
-
Jalankan k6 load test
k6 run k6/load-test.js
Script k6/load-test.js menggunakan skenario berikut:
| Stage | Durasi | Virtual Users | Tujuan |
|---|---|---|---|
| Ramp up | 30s | 0 → 10 | Pemanasan |
| Steady | 1m | 10 | Stabilitas beban normal |
| Ramp up | 30s | 10 → 20 | Naikkan beban |
| Steady | 1m | 20 | Stabilitas beban tinggi |
| Ramp down | 30s | 20 → 0 | Turun bertahap |
Total durasi: ~3.5 menit
k6 run -e BASE_URL=http://192.168.1.100:8080 k6/load-test.jsHasil test otomatis disimpan di folder k6/results/:
| File | Format | Isi |
|---|---|---|
summary-{timestamp}.json |
JSON | Data mentah untuk analisis |
summary-{timestamp}.txt |
Text | Summary readable |
| Metric | Penjelasan |
|---|---|
| Alloc | Memory yang sedang dialokasikan (aktif) |
| Heap Alloc | Heap memory yang digunakan |
| Sys Memory | Total memory dari OS |
| Total Alloc | Total memory yang pernah dialokasikan (kumulatif) |
| GC Cycles | Jumlah Garbage Collection yang sudah berjalan |
| Goroutines | Jumlah goroutine aktif |
Tanda tidak ada memory leak:
- Alloc/Heap kembali rendah setelah test selesai
- Goroutines kembali ke jumlah baseline
- GC Cycles bertambah (menunjukkan GC aktif membersihkan memory)
-
Network throttle tidak efektif jika hanya menggunakan
localhosttanpa Docker -
tcbekerja di level kernel Linux (container) -
Cocok untuk testing:
- retry & timeout
- streaming download
- UX progress bar
Screen.Recording.2025-12-24.at.20.44.47.mov
Screen.Recording.2025-12-24.at.20.45.56.mov