Çoğu ekip, “sadece 30 saniyelik video” depolamanın ne kadar maliyetli olabileceğini fark etmez — ta ki bu durum sessiz bir şekilde terabaytlarca depolama alanına ve devasa aylık faturaya dönüşene kadar.
Bizim başımıza gelen tam olarak buydu.
Her biri yalnızca ~30 saniye uzunluğunda milyonlarca kısa doğrulama videosu depoluyorduk — ancak birlikte, her ay yüzlerce GB’ye mal oluyordu.
Depolama için para harcamak yerine, kök problemi çözmeye karar verdik.
Sonuç?
👉 Günlük 20-30 GB tasarruf
👉 Ortalama %60 sıkıştırma
👉 İnceleme kalitesi üzerinde sıfır etki
Şirketimizde video tabanlı bir doğrulama akışı yürütüyoruz — kullanıcılar, ekibimiz tarafından gözden geçirilen kısa klipler (genellikle 30 saniye) kaydediyor. Basit gibi görünüyor. Ancak zamanla bu klipler hızla birikiyor.
2-4 yıl saklama gereksinimi olan depolama alanında milyonlarca kayıtlı video vardı. Depolama faturası tırmanmaya devam etti. Dönüm noktası, gerçekten neyi depoladığımızı ölçtüğümde geldi — ve aslında ihtiyaç olduğundan çok daha fazla veri sakladığımızı fark ettim.
Bunu başarmak için oluşturduğum süreç, günde 2,000’den fazla videoyu sıkıştırıyor ve günlük 20-30 GB depolama tasarrufu sağlıyor — bir canlı dosyayı bile dokunmadan.
Üretimden Gerçek Rakamlar
Nasıl yapıldığına girmeden önce, sıkıştırma kontrol panelimizdeki bir günün görünümü şöyle:
MetricValue
Videos processed: 2,203
Total space saved: 15.66 GB
Average compression ratio: 62.1%
Best compression recorded: 99.92%
Ortalama dosya boyutunda %62’lik bir azalma. Bazı klipler (genellikle sessiz veya neredeyse sabit olanlar) %99.9’a kadar sıkıştırılıyor. Tipik bir günde, tek bir cron çalıştırmasından 15+ GB tasarruf sağlıyoruz.
Sorun: Yanlış Kullanım Durumuna Aşırı Mühendislik
Orijinal kayıt kurulumumuz, tarayıcı varsayılanlarını kullanıyordu — yüksek çözünürlük, yüksek kare hızı, 48 kHz stereo ses. Genel kullanım için makul ayarlardı, ancak 30 saniyelik bir yüz doğrulama klibi için tamamen gereksizdi.
İş yükü milyonlarca dosyayı geçmeye başladığında, maliyet göz ardı edilemez hale geldi. Ancak tek bir sıkıştırma kodu yazmadan önce, dosyaların neden bu kadar büyük olduğunu anlamam ve sıkıştırma öncesinde kaynağı düzeltmem gerekiyordu.
Adım 1: Araştır, Deney, Doğrula
Öylece daha düşük ayarlar seçip gönderemedim. Codec davranışını araştırdım, farklı bit hızı ve kalite kombinasyonlarını test ettim ve — kritik olarak — kullanıcı trafiğine dokunmadan önce gerçek kayıtlarla doğruladım.
Doğrulama yaklaşımım: Doğrulayıcılarımız (doğrulama videolarını gözden geçiren kişiler) kendi video profillerini de kaydediyor. Bu, mükemmel bir test populasyonu — küçük, kontrollü ve içsel. Yeni kayıt kısıtlarını önce doğrulayıcı hesaplarına yaydım ve onlardan tipik bir doğrulama videosundan çok daha uzun olan 10 saniyelik klipler kaydetmelerini istedim.
Neden 10 saniye? Çünkü codec ayarları, cihaz uyumluluğu veya ses kalitesi sorunları, kısa kliplerde gizlenirken daha uzun olanlarda belirginleşir. Beyzbol sorunları, ses senkronizasyon kayması, hareket altındaki kodlama artefaktları — hepsi süreyi zorladığınızda görünür hale gelir.
Doğrulayıcı videoları, çeşitli cihazlarda (Android’de Chrome, masaüstünde Chrome, iOS’ta Safari) kontrol edildikten sonra, ayarların doğru olduğundan emin oldum. Yalnızca o zaman bunları kullanıcıların bulunduğu kayıtlara yaydım.
Adım 2: Kaydı Kaynakta Optimize Et
Tarayıcı Codec Desteğini Anlamak (VP8 vs VP9)
Modern tarayıcılar, MediaRecorder için iki temel video codec’ini destekler:
VP8 — daha eski WebM codec’i. Tüm tarayıcılar ve platformlar, eski Android cihazlar dahil olmak üzere, geniş çapta destekleniyor. VP9’dan daha az verimli sıkıştırma ancak son derece güvenilir.
VP9 — Google’ın daha yeni codec’i. Aynı kalite seviyesinde, özellikle hareket az olan içerikler için oldukça iyi sıkıştırma sağlar. Chrome, Firefox ve çoğu modern tarayıcıda destekleniyor, ancak bazı eski cihazlarda veya belirli Safari bağlamlarında her zaman mevcut olmayabilir.
Neden geri dönüş önemlidir: video/webm;codecs=vp9,opus belirtirseniz ve tarayıcı veya cihaz VP9’u desteklemiyorsa, MediaRecorder ya hata fırlatır ya da sessizce bozuk bir dosya üretir. Test cihazınızda işe yarayan sabit kodlu bir codec seçimi, gerçek kullanıcılarının cihazlarının bir kısmında başarısız olacaktır. Runtime’da desteği sorgulamanız gerekir:
const mimeTypes = [
'video/webm;codecs=vp9,opus', // En iyi: VP9 video + Opus ses
'video/webm;codecs=vp8,opus', // İyi: VP8 video + Opus ses
'video/webm' // Geri dönüş: tarayıcı seçiyor
];const mimeType = mimeTypes.find(type => MediaRecorder.isTypeSupported(type)) || ”;
MediaRecorder.isTypeSupported() mevcut tarayıcı/cihaz kombinasyonunun belirli bir MIME tipini destekleyip desteklemediğini runtime’da kontrol eder. Liste, tercihe göre sıralanmıştır — VP9 birinci, VP8 ikinci, tarayıcı varsayılanı sonuncu. Herhangi bir desteklenen aygıt en iyi mevcut seçeneği alır.
Gerçek kayıt kısıtları
const constraints = {
video: {
width: { ideal: 640 },
height: { ideal: 480 },
frameRate: { ideal: 24 }
},
audio: {
sampleRate: 16000,
channelCount: 1, // mono
echoCancellation: true,
noiseSuppression: true
}
};const mediaRecorder = new MediaRecorder(stream, {
mimeType,
videoBitsPerSecond: 1_000_000, // 1 Mbps cap
audioBitsPerSecond: 64_000 // 64 Kbps cap
});Neden her bir karar:
640×480, 24 fps — bir yüzü net bir şekilde tanımlamak için yeterli. 30fps ve 1080p tekrarlı olarak izlayacağınız içerikler içindir; doğrulama klibi bir kez gözden geçiriliyor.
16kHz mono ses — Sesin anlaşılırlığı 8kHz civarında maksimum düzeye ulaşır. 16 kHz, 44.1 kHz stereo’nun yarısı kadar veri ile net bir şekilde konuşmayı kaydeder. Doğrulayıcı, birinin söylediklerini duymalı, yüksek kaliteli sesi keyfini çıkarmalıdır.
1 Mbps video / 64 Kbps ses — Kaydedici seviyesinde bir kapama. Bunlar olmadan, VP8 özellikle bazı cihazlarda makul bit hızlarının üzerinde spike yapabilir.
echoCancellation + noiseSuppression — Bu, ses varyasyonunu azaltır, bu da aşağıda daha iyi sıkıştırılır. Gürültülü veya yankılı sesler daha verimsiz bir şekilde kodlanır.
Adım 3: Geriye Dönük Sıkıştırma
Kaynağı düzeltmek, sorunun büyümesini önledi. Ancak hala orijinal büyük boyutlarda milyonlarca eski dosya vardı. Bunları işlemek için üç katmanlı bir Laravel boru hattı geliştirdim.
Katman 1 — Artisan Komutu
php artisan media:compress-videos --chunk=200 --dry-run
// veya test etmek için tek bir videoyu hedefle:
php artisan media:compress-videos --id=202423Bu komut, video/% MIME türüne sahip tüm kayıtları sorgular, bunları 200’lük gruplara ayırır ve her video için kuyruklanmış bir iş gönderir. --dry-run bayrağı, bir şey yapmadan işlenecek olanları görmenizi sağlar — bu, üretimde ilk kez çalıştırmadan önce kullanışlıdır.
Katman 2 — Kuyruklu İş
class CompressMediaVideo implements ShouldQueue
{
public int $tries = 3;
public int $timeout = 120;
public function handle(VideoCompressorService $compressor): void
{
$media = Media::findOrFail($this->mediaId);
if (!str_starts_with($media->mime_type, 'video/')) {
return; // güvenli bir şekilde atla
}
$compressor->compress($media);
}Her video için bir iş. Eğer bir iş başarısız olursa, diğerlerini etkilemeden bağımsız olarak yeniden dener. Sıkıştırma çalışması milyonlarca dosya geçmişinde aylar alabilir — bireysel, yeniden denenebilir işler, bir sunucu yeniden başlatması ya da bozuk bir dosya ile sıfıra geri dönmeyi engeller.
Katman 3 — FFmpeg Sıkıştırma Stratejisine Derin Dalma
Asıl sıkıştırmanın gerçekleştiği yer burası. Nasıl çalıştığı hakkında bazı bilgiler:
FFmpeg ne yapıyor: Orijinal WebM dosyasını (genellikle Chrome tarafından kaydedilen H.264 video + Opus ses), video parçasını VP9 kullanarak yeniden kodluyor, sesi daha düşük bir bit hızıyla yeniden kodluyor ve yeni bir WebM kabını yazıyor.
VP9 neden sıkıştırma için? VP9, H.264’e göre çok daha karmaşık algoritmalar kullanır — çerçeveler arasında gereksiz bilgileri tanımlamak ve bunları kaldırmakta daha iyidir. Duvar yanında konuşan bir insan gibi çoğu statik sahnede, VP9, görüntüyü bir insan inceleyicinin gözünde mükemmel tutarken, muazzam miktarda veriyi atabilir.
CRF ne anlama geliyor: CRF (Sabit Oran Faktörü) kalite kontrollü kodlamadır. Belirli bir bit hızını hedeflemek yerine, bir kalite seviyesi belirleyip FFmpeg’e buna ulaşmak için ne kadar alan gerektiğini belirtirsiniz. Daha düşük CRF = daha yüksek kalite = daha büyük dosya. Daha yüksek CRF = daha fazla sıkıştırma = daha küçük dosya.
VP9 için, CRF 33 “iyi kalite” olarak kabul edilir. CRF 35 “biraz agresif”dir. CRF 40+ görünür şekilde bozulmayı başlatır. Ben CRF 35’i seçtim çünkü:
Bu bir yüz doğrulama klibi, bir film değil
İnceleyici, yüzü açıkça görmeli, gözenekleri saymamalıdır
Üretim verilerimiz bunun işe yaradığını doğruluyor — %62.1’lik ortalama sıkıştırma oranı, CRF 35’ten geldi
$command = [
'ffmpeg', '-i', $inputPath,
'-c:v', 'libvpx-vp9',
'-crf', '35',
'-b:v', '0', // CRF modunda gereklidir
'-c:a', 'libopus',
'-b:a', '64k',
'-y', $tempPath
];Not: -b:v 0, VP9 CRF için isteğe bağlı değildir. Birçok insanı bu çelme çıkarır. FFmpeg’de VP9, bit hızına dayalı moda varsayılan olarak geçer; CRF yalnızca -b:v 0 açıkça belirtildiğinde etkinleştirilir.
Güvenli İşlem ile Atomik Dosya Değiştirme:
$exitCode = $process->run();
if ($exitCode !== 0) {
@unlink($tempPath);
// Hata çıktısını kaydet ve hata ayıklama için sakla
$media->update(['compressed_meta' => ['error' => $process->getErrorOutput()]]);
return;
}
// Başarılı sıkıştırmadan sonra yalnızca orijinal ile değiştir
rename($tempPath, $inputPath);FFmpeg önce bir .tmp dosyasına yazar. Kodlama bir sebepten dolayı başarısız olursa — bozuk giriş, disk dolu, işlem öldü — orijinal dosya etkilenmez. Yalnızca onaylanmış bir başarılı çıkış kodundan sonra rename() uygulanır. Milyonlarca dosyayı işleyen bir boru hattında bu önemlidir.
Hizmet ayrıca, büyüyebilecek dosyaları atlar: Eğer sıkıştırılmış çıktı, orijinalden büyükse (bu, zaten optimize edilmiş veya çok kısa dosyalarla olur), saved_bytes 0 olarak kaydedilir ve orijinal saklanır. Gösterge tablosundaki -130.33% düşük değeri, tam olarak bu durumu temsil eder — yeniden kodlama altında daha büyük hale gelen küçük bir dosya.
Adım 4: Depolama Yaşam Döngüsü Yönetimi (Çöp + Temizlik Stratejisi)
Bir doğrulama videosu reddedildiğinde ve kullanıcı yeni bir tane kaydettiğinde, eski klibi hemen silmiyoruz. Çöp/katarına taşınıyor. Haftalık bir cron işi, çöp kutusunda 7 günden daha eski her şeyi kalıcı olarak kaldırıyor.
Bu, operasyon ekibine kurtarma penceresi sağlıyor ve reddedilen videoları süresiz olarak tutmamakta. Ayrıca sıkıştırma boru hattını temiz tutar — çöp videoları zaten silinmekte olduğu için sıkıştırma kuyruğundan hariç tutulur.
Sonuçlar
Bir günün çalışması (11 Mart 2026):
2,203 video sıkıştırıldı
15.66 GB tasarruf edildi
62.1% ortalama sıkıştırma oranı
Ölçekli olarak tahmin edilen:
Günlük ortalama 20 GB: Aylık 600 GB, 7+ TB/yıl
Geçmişte milyonlarca video var — bu boru hattı aylarca çalışacak
Yeni yüklemeler, kayıt kısıtlaması değişiklikleri sayesinde zaten daha küçüktür
Anahtar Çıkarımlar
Öncelikle iç kullanıcılar üzerinde doğrulayın. Kullanıcı hesaplarına kayıt değişikliklerini yaymak, herhangi bir sorunun içsel olarak tespit edilmesi anlamına geliyordu. Özellikle 30 saniyelik kliplerle test yapmak, kısa kliplerin gizlediği sorunları ortaya çıkarır.
Runtime’da codec desteğini sorgulayın. Bir MIME tipi hiçbir zaman sabit kodlanmamalıdır.
MediaRecorder.isTypeSupported()her cihazın en iyi kodlamayı almasını sağlamak için bir satırlık bir çözümdür.CRF, bit hızından daha iyidir. Sabit bir bit hızı, basit sahneler üzerinde bitleri boşa harcar ve karmaşık olanları aç bırakır. CRF içeriğe adapte olur — basit konuşma özne çerçeveleri çok küçük olur, karmaşık çerçeveler gerektiklerini alır.
4. -b:v 0, VP9 CRF için isteğe bağlı değildir. Bu, birçok insanı yanıltır. FFmpeg’de VP9, bit hızına dayalı moda varsayılan olarak geçer; CRF yalnızca açıkça -b:v 0 belirtildiğinde etkinleştirilir.
Atomik yazmalar verilerinizi korur. Özellikle toplu işlemede, işler başarısız oluyor. Geçici dosyaya yazın, başarıyı doğrulayın, ardından yeniden adlandırın. Asla doğrudan canlı yola yazmayın.
Batch başına değil, dosya başına kuyruk. Bireysel kuyruklu işler, boru hattını yeniden başlatılabilir, gözlemlenebilir ve hata toleranslı hale getirir. Kötü bir dosya izole bir şekilde başarısız olur; her şey diğerinin çalışmaya devam eder.
Backend mühendisliği ve fintech sistemleri hakkında yazıyorum. Bu faydalı olduysa, bir sonraki gönderi bu boru hattı arkasındaki Laravel kuyruk mimarisini kapsayacak.
Kaynak: Orijinal Makale


