Ruang warna OKLCH (Lightness, Chroma, Hue) menawarkan persepsi warna yang seragam secara visual dibandingkan sRGB atau HSL. Keunggulan perseptual ini menjadikannya standar ideal untuk menghasilkan tema UI adaptif dari gambar media yang diunggah pengguna. Namun, konversi piksel dari sRGB ke Linear sRGB, CIE XYZ, Oklab, hingga OKLCH, dilanjutkan dengan algoritma clustering (seperti k-means) untuk menemukan warna dominan, menghabiskan siklus CPU yang signifikan. Menjalankan proses ini secara sinkron di web server atau thread penanganan HTTP request dapat memicu lonjakan beban CPU, memblokir thread pool, dan mendegradasi throughput API secara masif.
Beban Komputasi dan Desain Arsitektur Antrean
Ekstraksi palet gambar resolusi standar (misalnya 1920x1080) membutuhkan kalkulasi matriks 3x3 dan fungsi eksponensial untuk lebih dari dua juta piksel. Jika diproses langsung pada jalur sinkron API, waktu respons request dapat melonjak dari puluhan milidetik menjadi hitungan detik. Isolasi proses komputasi ke background worker mutlak diperlukan.
Alur kerja yang efisien memisahkan penerimaan data dan pemrosesan:
- Klien mengunggah gambar ke API server.
- API server memvalidasi berkas, menghitung hash (SHA-256) dari buffer berkas, dan menyimpannya ke object storage.
- Hash berkas digunakan sebagai kunci pengecekan cache di Redis. Jika entri palet sudah ada, API langsung mengembalikan hasil.
- Jika terjadi cache miss, API membuat job berbobot ringan ke message broker (misalnya Redis Streams atau BullMQ) dan mengembalikan respons awal ke klien.
- Background worker mengambil job, mengekstraksi palet warna OKLCH, lalu menulis hasilnya ke cache Redis.
Struktur Payload Job Antrean
Payload antrean harus seringkas mungkin untuk menghemat memori broker. Hindari menyertakan binary gambar di dalam antrean; gunakan referensi lokasi file di storage dan metadata validasi.
{
"job_id": "job_oklch_9f83a21b",
"asset_hash": "a8f5f167f44f4964e6c998dee827110c",
"storage_path": "media/uploads/2026/03/user_992_photo.jpg",
"palette_size": 5,
"created_at": 1774358400
}Pencegahan Cache Stampede dengan Distributed Lock
Ketika sebuah gambar populer diakses oleh banyak request secara bersamaan saat cache belum tersedia (misalnya cache baru saja kadaluarsa atau baru pertama kali dipublikasikan), risiko cache stampede meningkat drastis. Ratusan permintaan yang membaca status cache kosong dapat memicu ratusan job komputasi yang identik ke worker.
Untuk memitigasi kondisi ini, implementasikan pola distributed lock berbasis Redis menggunakan perintah SET key lock_value NX EX ttl. Hanya satu proses yang berhak mendaftarkan job ekstraksi untuk satu hash gambar.
async function acquireExtractionLock(redis, assetHash) {
const lockKey = `lock:palette:${assetHash}`;
const lockValue = process.pid.toString();
const ttlSeconds = 30;
// SET NX EX mengembalikan 'OK' hanya jika kunci belum ada
const result = await redis.set(lockKey, lockValue, 'NX', 'EX', ttlSeconds);
return result === 'OK';
}Jika lock berhasil diperoleh, job dijadwalkan. Jika gagal, API menunggu event publikasi via Redis Pub/Sub atau meminta klien melakukan polling status pemrosesan dengan interval exponential backoff.
Implementasi Worker Ekstraksi OKLCH
Tahap krusial dalam mengendalikan penggunaan CPU worker adalah melakukan downsampling gambar sebelum memproses piksel. Menganalisis palet dari gambar 2000x2000 menghasilkan distribusi visual yang hampir identik dengan gambar yang diperkecil menjadi 64x64 piksel, namun memangkas jumlah kalkulasi hingga 99.8%.
import sharp from 'sharp';
// Konversi sRGB [0-255] ke Linear RGB [0-1]
function sRgbToLinear(c) {
const v = c / 255;
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
}
// Konversi Linear RGB ke OKLCH
function rgbToOklch(r, g, b) {
const lr = sRgbToLinear(r);
const lg = sRgbToLinear(g);
const lb = sRgbToLinear(b);
// Matriks Linear sRGB ke Oklab LMS cone space
const l = 0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb;
const m = 0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb;
const s = 0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb;
const l_ = Math.cbrt(l);
const m_ = Math.cbrt(m);
const s_ = Math.cbrt(s);
const L = 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_;
const a = 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_;
const b_ = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_;
const C = Math.sqrt(a * a + b_ * b_);
let H = (Math.atan2(b_, a) * 180) / Math.PI;
if (H < 0) H += 360;
return { L: Number(L.toFixed(4)), C: Number(C.toFixed(4)), H: Number(H.toFixed(2)) };
}
export async function extractOklchPalette(imageBuffer, sampleLimit = 5) {
// Optimasi CPU: Downscale gambar ke resolusi rendah
const { data } = await sharp(imageBuffer)
.resize(64, 64, { fit: 'inside' })
.removeAlpha()
.raw()
.toBuffer({ resolveWithObject: true });
// Sampel piksel dan konversi ke OKLCH
const oklchPixels = [];
for (let i = 0; i < data.length; i += 3) {
oklchPixels.push(rgbToOklch(data[i], data[i + 1], data[i + 2]));
}
// ponytail: Gunakan k-means sederhana. Upgrade ke median-cut jika clustering memakan waktu berlebih.
return runOklchClustering(oklchPixels, sampleLimit);
}Kontrol Beban dan Strategi Fallback
Meskipun gambar telah di-downsample, lonjakan antrean (queue backlog) tetap dapat terjadi saat beban traffic tinggi. Terapkan strategi adaptif untuk mempertahankan stabilitas worker:
- Queue Backpressure Monitoring: Pantau metrik latensi antrean. Jika waktu tunggu job dalam queue melebihi batas toleransi (misalnya 10 detik), alihkan metode ekstraksi ke mode degradasi.
- Algoritma Degradasi Cepat: Alih-alih menjalankan iterasi k-means penuh yang membutuhkan puluhan putaran konvergens, ambil nilai rata-rata kuadran gambar (1x1 atau 2x2 grid) sebagai perkiraan palet darurat.
- Batas Konkurensi Worker: Batasi jumlah worker thread sesuai jumlah physical core CPU untuk menghindari context-switching overhead pada container. Gunakan rumus konservatif:
concurrency = Math.max(1, os.cpus().length - 1)untuk menyisakan core bagi sistem operasi dan I/O.
Hasil ekstraksi disimpan di Redis dalam bentuk JSON terkompresi dengan TTL terukur (misal: 30 hari). Pendekatan hashing aset menjamin bahwa file yang sama tidak akan pernah diekstraksi ulang, mengamankan CPU dari redundansi beban.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!