Storage Node gRPC adalah microservice penyimpanan khusus (dedicated storage worker) berbasis Java Spring Boot dan gRPC. Proyek ini berfungsi sebagai pasangan/pendamping dari repositori backend utama Anda:
π vps-personal-BE
Dengan memisahkan tugas I/O file berat (seperti upload chunk, perakitan file, dan streaming download) dari backend utama, arsitektur microservice ini memastikan penggunaan CPU, RAM, dan I/O disk pada VPS personal Anda tetap stabil, responsif, dan terisolasi dengan aman.
Berikut adalah alur integrasi antara Client, Backend Utama, dan gRPC Storage Node:
graph TD
Client["Client / Frontend"] -->|1. REST API Upload/Download| BE["vps-personal-BE"]
BE -->|2. gRPC Stream Port 9090| SN["Storage Node gRPC"]
SN -->|3. Simpan Fisik| FS["Physical Disk Storage"]
- π¦ Chunked Uploads (
UploadBatch): Menerima chunk file berukuran besar secara asinkron ke dalam direktori staging (storage/staging/{userId}/{fileId}) dan merakitnya secara otomatis setelah selesai. - π₯ Streaming Downloads (
DownloadFile): Menyajikan file kembali dalam bentuk stream data berukuran 1MB secara buffered agar hemat memori RAM. - π gRPC Interceptor Security: Seluruh request gRPC divalidasi secara real-time menggunakan
GrpcAuthServerInterceptordengan skemaBearertoken. - π¦ Flow Control & Backpressure: Menggunakan Semaphore controller (limit: 20 antrean thread) untuk menjamin node tidak mengalami overload.
- π Isolasi Folder User: Penyimpanan file staging maupun final sepenuhnya dikelompokkan secara terisolasi berdasarkan parameter
userId.
Layanan ini sudah dipaketkan ke dalam image Docker Hub resmi di faizul20/storage-node.
Secara default, SSL/TLS diaktifkan menggunakan JKS keystore (keystore.p12) bawaan proyek:
docker run -d \
--name storage-node-grpc \
-p 9090:9090 \
-e SERVICE_TOKEN="isi-token-rahasia-anda" \
-v /path/di/vps/data:/app/Data \
faizul20/storage-node:latestJika Anda ingin mematikan SSL/TLS agar backend utama (vps-personal-BE) dapat terhubung secara plaintext biasa (tanpa sertifikat SSL):
docker run -d \
--name storage-node-grpc \
-p 9090:9090 \
-e SERVICE_TOKEN="isi-token-rahasia-anda" \
-e SPRING_GRPC_SERVER_SSL_BUNDLE="" \
-v /path/di/vps/data:/app/Data \
faizul20/storage-node:latestImportant
Pastikan nilai SERVICE_TOKEN di atas sama dengan konfigurasi token gRPC client yang dipasang pada repositori vps-personal-BE agar komunikasi berjalan sukses.
Anda dapat mengonfigurasi aplikasi baik via file application.yaml maupun langsung melalui Environment Variable Docker:
| Environment Variable | Properti Spring | Default | Deskripsi |
|---|---|---|---|
SERVICE_TOKEN |
spring.grpc.security.service-token |
Wajib Diisi | Token rahasia penjamin keamanan autentikasi gRPC channel. |
SPRING_GRPC_SERVER_PORT |
spring.grpc.server.port |
9090 |
Port gRPC Server yang diekspos untuk komunikasi. |
SPRING_GRPC_SERVER_ADDRESS |
spring.grpc.server.address |
0.0.0.0 |
IP Address binding untuk gRPC Server listener. |
SPRING_GRPC_SERVER_SSL_BUNDLE |
spring.grpc.server.ssl.bundle |
storage-ssl-bundle |
Menghubungkan SSL Bundle. Isi kosong "" untuk mematikan SSL. |
Karena layanan ini berkomunikasi menggunakan gRPC, klien (vps-personal-BE) harus menggunakan file .proto yang sama untuk men-generate gRPC Client.
syntax = "proto3";
package upload;
service UploadService {
// Mengunggah file dalam bentuk pecahan stream chunk
rpc UploadBatch(stream UploadChunkRequest) returns (UploadBatchResponse);
// Menginstruksikan perakitan akhir semua chunk menjadi satu file utuh
rpc FinalizeUpload(FinalizeRequest) returns (FinalizeResponse);
// Menghapus file fisik di storage node
rpc DeleteFile(DeleteFileRequest) returns (DeleteFileResponse);
}
message UploadChunkRequest {
string file_id = 1;
int32 chunk_index = 2;
int32 total_chunks = 3;
bytes data = 4;
string user_id = 5;
}
message UploadBatchResponse {
string file_id = 1;
bool success = 2;
string message = 3;
}
message FinalizeRequest {
string file_id = 1;
int32 total_chunks = 2;
string user_id = 3;
}
message FinalizeResponse {
string file_id = 1;
bool success = 2;
string message = 3;
}
message DeleteFileRequest {
string file_id = 1;
string user_id = 2;
}
message DeleteFileResponse {
string file_id = 1;
bool success = 2;
string message = 3;
}syntax = "proto3";
package download;
service DownloadService {
// Mengunduh file secara streaming (chunk-by-chunk)
rpc DownloadFile(DownloadRequest) returns (stream DownloadResponse);
}
message DownloadRequest {
string file_id = 1;
string user_id = 2;
}
message DownloadResponse {
string file_id = 1;
int32 chunk_index = 2;
int32 total_chunks = 3;
bytes data = 4;
}Agar vps-personal-BE dapat terhubung ke storage-node-grpc, klien wajib menyertakan token autentikasi di dalam metadata request gRPC.
Berikut adalah cuplikan kode integrasi client gRPC sederhana di Node.js:
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
// 1. Muat protobuf file
const packageDefinition = protoLoader.loadSync('upload.proto', {});
const uploadProto = grpc.loadPackageDefinition(packageDefinition).upload;
// 2. Hubungkan ke Storage Node (Plaintext/SSL)
const targetAddress = 'localhost:9090'; // IP VPS / Container
const client = new uploadProto.UploadService(
targetAddress,
grpc.credentials.createInsecure() // Gunakan secure credentials jika SSL aktif
);
// 3. Wajib: Buat metadata dengan Authorization Header
const metadata = new grpc.Metadata();
metadata.add('Authorization', 'Bearer token-rahasia-anda-yang-sesuai-env');
// 4. Lakukan pemanggilan gRPC (Contoh: DeleteFile)
client.DeleteFile({
fileId: 'file-12345',
userId: 'user-789'
}, metadata, (error, response) => {
if (error) {
console.error('Gagal memanggil storage-node:', error.message);
return;
}
console.log('Respons dari storage-node:', response.message); // "File deleted successfully"
});- Java Development Kit (JDK) 21 atau lebih tinggi
- Maven 3+ (atau menggunakan
./mvnwwrapper bawaan)
./mvnw clean compile./mvnw test- Linux / macOS:
SERVICE_TOKEN="rahasia-anda" ./mvnw spring-boot:run - Windows (Command Prompt):
set SERVICE_TOKEN=rahasia-anda mvnw spring-boot:run
- Windows (PowerShell):
$env:SERVICE_TOKEN="rahasia-anda" ./mvnw spring-boot:run
- Faizul Mushofa - faizulmushofa