Tek Tıkla Birden Fazla Programı Planlamak — AWS Lambda'nın 15 Dakikalık Sınırını Aşmak
Bir FAST kanal operatörü bir aylık programlamayı planlar ve bir kez Deploy'a tıklar. Bu tek tıklamanın arkasında, yüzlerce program, Lambda'nın on beş dakikalık yürütme tavanı içinde, AWS'ye sırayla ulaşması gereken binlerce MediaLive zamanlama eylemine dönüşür - ve ortadaki herhangi bir hata, canlı kanalda boşluklar bırakır. İşte büyük oynatma listelerinin tek tıklamayla dağıtımını nasıl güvenilir hale getirdiğimiz ve bir sonraki adımın neden daha büyük bir Lambda değil de farklı bir runtime olduğu.
Hızlı genel bakış
| Yön | Detay |
|---|---|
| Runtime | AWS Lambda (tek çağrı), 615s arka uç zaman aşımı |
| Çıkış hedefi | MediaLive BatchUpdateScheduleCommand |
| Gruplandırma | İstek başına 200'e kadar MediaLive eylemi — pratikte ~25 program |
| Program başına eylemler | ~7–8 (giriş anahtarı + rendisyon başına 4 filigran + 2 SCTE-35), reklam aralarıyla daha fazla |
| Geri Dönüş Mekanizması | Herhangi bir grup reddedildiğinde program başına yeniden deneme |
| Gözlemlenen | ~44 saniyede dağıtılan 195 program (yerel ölçüm) |
| Hedeflenen | ≤90 saniyede 360 program |
| Ölçeklendirme yolu | >1 aylık oynatma listeleri için Step Functions parçalama — planlandı, henüz yayınlanmadı |
Zorluk
Bir oynatma listesini dağıtmak bir yazma işlemi değil, bir orkestrasyondur. Operatörün planladığı her program için MediaLive, girişleri ne zaman değiştireceğini, her rendisyon için filigranı ne zaman açacağını, SCTE-35 işaret noktalarını ne zaman ekleyeceğini ve reklamları ne zaman ekleyeceğini tam olarak bilmelidir. Yapısal baskılar şunlardır:
- Eylem sayısı toplamsal değil, çarpımsaldır. Her program reklam aralarından önce ~7–8 eylem yayar — bir giriş anahtarı, dört filigran etkinleştirme (StaticImageOutputActivate çıkış-piksel koordinatları kullandığı için her rendisyon için bir tane) ve iki SCTE-35 işaretleyicisi. Reklam araları her biri üç eylem daha ekler. 360 programlık bir ay, kabaca 2.800 eylem anlamına gelir.
- MediaLive kanal başına sıralamayı zorunlu kılar. Zamanlama eylemleri zamana bağlıdır ve birbirlerine referans verir; API'nin çakışan olarak reddetmesi olmadan aynı kanala yazmaları paralelleştiremezsiniz.
- AWS Lambda'nın katı bir 15 dakikalık tavanı vardır. Yumuşak bir limit veya bir yapılandırma değildir. Orkestratör bu duvarın içinde bitirmeli, aksi takdirde kanal yarıda dağıtılmış olur.
- Kısmi hata operasyonel olarak kabul edilemez. 360 programdan 174'ü başarısız olursa ve çalıştırmayı durdurursa, operatör neyin dağıtıldığını ve neyin dağıtılmadığını gösteren bir fark görünümüne sahip olmaz. Kanal boşluklarla yayına girer; izleyiciler içerik bekledikleri yerde boş ekran görürler.
- İlk sürüm, programlar arasında 200ms bekleme süresiyle program başına bir BatchUpdateSchedule gönderiyordu. Bu, program başına ~2.5 saniye gerçek çalışma süresi demek. 360 programda, MediaLive herhangi bir gerçek iş yapmadan Lambda tavanını zaten geçmiş olursunuz.
İş, öyleyse, daha hızlı yazmak değil. Daha az yazmak, kısmi hatalardan kurtulmak ve MediaLive'ın talep ettiği sıralama garantilerini kaybetmeden tek bir çağrı içinde kalmaktır.
Mevcut Yaklaşımlar Neden Başarısız Oluyor?
Aşikar kaçış yollarının hepsi, ayar sorunları değil, yapısal nedenlerle başarısız oluyor.
- "Lambda zaman aşımını artırın." Artıramazsınız. On beş dakika, AWS tarafından Lambda yürütmesi için belirlenmiş katı bir tavandır; konsolda bir ayar düğmesi değildir. Olsa bile, katalog büyüdükçe program başına maliyet artar — daha fazla çalışma süresi satın almak sadece bir sonraki engeli geciktirir.
- "ECS Fargate veya EC2'ye geçin." Bunu düşündük ve reddettik. Uzun süreli çalışan konteynerler, runtime'ın bize ait olduğu anlamına gelir: sistem sağlığı kontrolleri, otomatik ölçeklendirme, soğuk başlatma ve sıcak havuz takasları, IAM kapsam belirleme ve ani yüklerde çalışan bir hizmet için nöbet rotasyonu. Lambda bize çağrı başına izolasyon ve doğası gereği ani yüklenen bir iş yükü için sıfır boşta kalma maliyeti sağlar. Tek bir darboğazı düzeltmek için bundan vazgeçmeye hazır değildik.
- "MediaLive yazmalarını paralelleştirin." MediaLive, kanal başına zamanlama güncellemelerini seri hale getirir. Aynı kanala yapılan eş zamanlı BatchUpdateSchedule çağrıları eylem zaman çizelgesinde çakışır ve reddedilir. Tek meşru paralellik, gruplar arasında değil, bir grubun içindedir.
- "Bırakın çöksün ve operatör tekrar denesin." Bu en kötü seçenektir. Bir dağıtım, N programında durdurulduğunda, kanal hiç kimsenin UI'dan açıklayamayacağı bir durumdadır. Operatörler bir fark görmezler; bir kara kutu ve içinde boşluklar olan canlı bir kanal görürler. Sistem ya her şeyi dağıtmalı ya da operatörün işlem yapabileceği program başına durumla kısmi sonuçlar dağıtmalıdır.
Elimizde kalan kaldıraç, işin kendi şekliydi: daha az, daha büyük yazmalar, seri olarak yürütülen, ve yalnızca bir grup reddedildiğinde satır düzeyinde ayrıntıya inen bir geri dönüş mekanizması.
Çözümümüz
Döngü başlamadan önce maliyeti Lambda'dan çıkarın, döngü içinde MediaLive yazmalarını birleştirin ve yalnızca bir grup başarısız olduğunda program başına gönderime geçin. Bu sırayla üç fikir — ve 15 dakikalık tavanın bugün gerçekten dağıttığımız katalog boyutları için uygun olduğuna dair bilinçli bir karar. Oynatma listeleri tek bir çağrıyı aştığında, çözüm daha büyük bir Lambda değil; farklı bir runtime'dır.

Mimari
- NestJS arka ucu (schedule.service.ts) — dağıtımı önceden hazırlar: tüm benzersiz videolar için bir Mongo gidiş dönüşü, tüm reklam işaretleyicileri için bir tane, ardından benzersiz video URL'leri üzerinde paralel ffprobe çalıştırır ve sonuçları zenginleştirme döngüsü için önbelleğe alır.
- Lambda orkestratörü (fastChannel-lambda-fun/index.js) — gruplandırma döngüsüne, grup başına kısıtlamaya, program başına geri dönüş mekanizmasına ve yetim temizliğine sahiptir.
- MediaLive BatchUpdateScheduleCommand — tek yazma yüzeyi. Her eylem — giriş anahtarı, filigran, SCTE-35, reklam ekleme — bunun üzerinden akar.
- MongoDB — programlar, videolar ve reklam işaretleyicileri için doğruluk kaynağı; iç döngüde asla sorgulanmaz.
- scheduleResults haritası — program başına scheduled / error durumu arka uca geri döner, böylece operatör bir yığın izi yerine bir fark görür.
Temel Mühendislik Kararları
1. Yavaş işlemleri döngü başlamadan önce önceden ısıtın. Orijinal kod, zenginleştirme döngüsü içinde program başına bir Mongo araması ve program başına bir ffprobe çağrısı yapıyordu — klasik bir N+1, iki kez ödenen bir durum. Mevcut arka uç, her benzersiz video ve reklam işaretleyicisini birer gidiş dönüşte toplu olarak getirir, ardından benzersiz video URL'leri üzerinde paralel ffprobe çalıştırır ve sonucu bir çözüm önbelleğine depolar. İç döngü bir önbellek isabeti haline gelir. ffprobe gecikmesi döngüde seri olarak değil, benzersiz URL başına bir kez ödenir.
2. MediaLive yazmalarını ~25'lik gruplar halinde birleştirin. Orkestratör içinde, 200 eylem kuyruğa alınana veya son programa ulaşılana kadar eylemler tek bir BatchUpdateScheduleCommand içinde birikir. Her program ~7–8 eylem ürettiği için, gruplar doğal olarak yaklaşık 25 program içerir. 200 eylemlik sınır, MediaLive'ın istek başına yük limitlerinin oldukça altında kalmak ve boyut nedeniyle bir grubun reddedilme olasılığını azaltmak için muhafazakar bir şekilde seçilmiştir — ağ maliyetini amorti edecek kadar büyük, çalışması gerektiğinde program başına geri dönüş mekanizmasını (bir sonraki karar) ucuz hale getirecek kadar küçük. Bir ağ gidiş dönüşü yirmi beşi değiştirir. Her program arasında oturan 200ms'lik kısıtlama artık her grup arasında yer alıyor.
3. Hız için gruplandırma, doğruluk için geri dönüş. Birleştirme, yalnızca tek bir hatalı programın grubundaki diğer yirmi dördünü zehirlememesi durumunda güvenlidir. submitProgramBatch bir hata fırlattığında, yakalama retryBatchAsIndividuals'ı çağırır; bu, başarısız gruptaki her programı kendi BatchUpdateScheduleCommand olarak yeniden gönderir, program başına status: 'scheduled' veya status: 'error' durumunu kaydeder, denemeler arasında 200ms bekler ve her kısmi başarıdan sonra eylem zaman çizelgesini yeniden sabitler. Hızlı yol gruplandırılmıştır. Kurtarma yolu ayrıntılıdır. Operatör her durumda program başına bir fark görür.
4. Yetimleri sonunda temizleyin, uçuş sırasında engellemeyin. sweepIncompleteProgramGroups, dağıtımın sonunda bir kez çalışır ve temiz bir terminal durumuna ulaşamayan tüm eylem gruplarını kaldırır. Döngü sırasında kanalı dahili olarak tutarlı tutmaya bilerek çalışmıyoruz — bu, 15 dakikalık bütçeye sığması gereken bir geri alma yolu anlamına gelirdi. Temizleme tek bir süpürmedir, bir işlem değildir.
5. Lambda'yı büyütmeyin; katalog büyüdüğünde onu değiştirin. Bugün dağıttığımız her şey için tek çağrılık yol bütçe içinde iyi bir şekilde tamamlanıyor. Dürüst ölçeklendirme, Step Functions parçalama yoluyla yapılır — oynatma listesini bölümlere ayırın, parçaları paralel durum makineleri olarak çalıştırın, yeniden birleştirin. Bu, >1 aylık ve 6 aylık oynatma listeleri için olan yoldur. Tasarlandı, henüz dağıtılmadı. Bunu bir sonraki adım olarak adlandırmak, zaten çalışıyormuş gibi davranmaktan daha faydalıdır.
Sonuçlar
- Dahili testlerde, 195 programlık bir dağıtım ~44 saniyede tamamlandı — çok dakikalık, tek programlı temelden düşüşle.
- 360 programlık (~1 ay) bir oynatma listesi için hedeflenen süre ≤90 saniyedir, bu da 615 saniyelik arka uç zaman aşımı ve 15 dakikalık Lambda tavanının rahatlıkla içindedir.
- Bir gruptaki bir hatalı program artık diğer 24'ünü durdurmuyor. Operatör, her dağıtımdan sonra program başına durum haritası geri alır.
- İsteğin yavaş kısımları — Mongo aramaları ve ffprobe — program girişi başına bir kez değil, benzersiz kaynak başına bir kez ödenir.
- 15 dakikalık tavan, aslında yayınladığımız katalog boyutları için sınırlayıcı faktör olmaktan çıktı. Tekrar olduğunda, çözüm daha büyük bir Lambda değil, Step Functions parçalamadır.
Teknoloji Yığını: AWS Lambda · AWS MediaLive · NestJS · MongoDB · Node 18 · ffprobe · TypeScript · AWS SDK v3

