11 Eki 2025·6 dk okuma

Go işçi havuzları vs görev başına goroutine (arka plan işleri)

Go işçi havuzları vs görev başına goroutine: her modelin arka plan işlemeleri ve uzun iş akışları için verim, bellek kullanımı ve geri basıncı nasıl etkilediğini öğrenin.

Go işçi havuzları vs görev başına goroutine (arka plan işleri)

Hangi sorunu çözüyoruz?

Çoğu Go servisi sadece HTTP isteklerine yanıt vermekten fazlasını yapar. Arka plan işleri de çalıştırır: e-posta gönderme, görüntü yeniden boyutlandırma, fatura oluşturma, veri senkronizasyonu, olay işleme veya bir arama dizinini yeniden oluşturma. Bazı işler hızlı ve bağımsızdır. Diğerleri, her adımın bir öncekine bağlı olduğu uzun iş akışları oluşturur (bir kartı tahsil et, onay bekle, ardından müşteriyi bilgilendir ve raporlamayı güncelle).

İnsanlar "Go işçi havuzları vs görev başına goroutine" diye karşılaştırma yaptıklarında genellikle tek bir üretim sorununu çözmeye çalışıyorlar: çok sayıda arka plan işini hizmeti yavaşlatmadan, pahalı hale getirmeden veya kararsızlaştırmadan nasıl çalıştırırsınız.

Etkisini birkaç yerde hissedersiniz:

  • Gecikme: arka plan işi CPU, bellek, veritabanı bağlantıları ve ağ bant genişliğini kullanıcıya yönelik isteklerden çalar.
  • Maliyet: denetimsiz eşzamanlılık sizi daha büyük makineler, daha fazla veritabanı kapasitesi veya daha yüksek kuyruk ve API faturalarına iter.
  • Kararlılık: ani patlamalar (ithalatlar, pazarlama gönderimleri, yeniden deneme fırtınaları) zaman aşımı, OOM çökmesi veya zincirleme hatalara neden olabilir.

Gerçek takas noktası basitlik vs kontroltür. Her görev için bir goroutine başlatmak yazması kolaydır ve hacim düşük veya doğal olarak sınırlıysa genellikle iyidir. Bir işçi havuzu yapılandırma ekler: sabit eşzamanlılık, daha net limitler ve zaman aşımı, yeniden deneme ve metrik koymak için doğal bir yer. Maliyeti ise ekstra kod ve sistem meşgulse ne olacağına dair (görevler bekler mi, reddedilir mi, yoksa başka yere mi kaydedilir?) bir karar vermektir.

Bu yazı günlük arka plan işleme ile ilgilidir: verim, bellek ve geri basınç (aşırı yükü nasıl önlersiniz). Her kuyruk teknolojisini, dağıtık iş akışı motorlarını veya tam olarak bir kez (exactly-once) semantiğini kapsamaya çalışmaz.

Eğer AppMaster gibi bir platform kullanarak arka plan mantığı içeren tam uygulamalar inşa ediyorsanız, aynı sorular hızla karşınıza çıkar. İş süreçleriniz ve entegrasyonlarınız hala veritabanları, dış API'lar ve e-posta/SMS sağlayıcıları etrafında sınırlar gerektirir ki tek bir yoğun iş akışı her şeyi yavaşlatmasın.

Düz anlatımla iki yaygın desen

Görev başına goroutine

Bu en basit yaklaşımdır: bir iş gelince onu işlemek için bir goroutine başlatırsınız. "Kuyruk" genellikle işi tetikleyen şeydir; bir kanal alıcısı veya bir HTTP işleyicisinden doğrudan çağrı gibi.

Tipik şekli: bir iş alın, sonra go handle(job) yapın. Bazen yine bir kanal vardır ama sınırlayıcı olarak değil, devretme noktası olarak kullanılır.

Bu yaklaşım, işler çoğunlukla I/O üzerinde bekliyorsa (HTTP çağrıları, DB sorguları, yüklemeler), iş hacmi makulse ve patlamalar küçük veya öngörülebilirse iyi çalışır.

Dezavantajı, eşzamanlılığın net bir sınırı olmadan büyüyebilmesidir. Bu bellek sıçramalarına, çok fazla bağlantı açılmasına veya bir alt sistemi aşırı yüklemeye yol açabilir.

İşçi havuzu

İşçi havuzu sabit sayıda işçi goroutine başlatır ve işleri genellikle bellek içi tamponlu bir kanaldan onlara besler. Her işçi döngü halinde: bir iş al, işle, tekrarla.

Temel fark kontroldür. İşçi sayısı sert bir eşzamanlılık sınırıdır. İşler işçilere göre daha hızlı gelirse işler kuyrukta bekler (veya kuyruk doluysa reddedilir).

İşçi havuzları, iş CPU-ağırlıklıysa (görüntü işleme, rapor üretimi), kaynak kullanımının öngörülebilir olması gerektiğinde veya bir veritabanını ya da üçüncü taraf API'yı patlamalardan korumanız gerekiyorsa uygundur.

Kuyruğun nerede olduğu

Her iki desen de bellek içi bir kanal kullanabilir; bu hızlıdır ama yeniden başlatmada kaybolur. "Kaybetmememiz gereken" işler veya uzun iş akışları için kuyruk genellikle süreç dışına (veritabanı tablosu, Redis veya bir mesaj aracısı) taşınır. Bu kurulumda yine görev başına goroutine veya işçi havuzu arasında seçim yaparsınız, ama şimdi bunlar harici kuyruğun tüketicileri olarak çalışır.

Basit bir örnek: sistem aniden 10.000 e-posta göndermek zorunda kalırsa, görev başına goroutine hepsini birden göndermeye çalışabilir. Bir havuz 50'şer gönderir ve geri kalanları kontrollü şekilde bekletir.

Verim: ne değişir ne değişmez

İşçi havuzları ile görev başına goroutine arasında büyük bir verim farkı olmasını beklemek yaygındır. Çoğu zaman ham verimlik başka bir şeyle sınırlanır; goroutine başlatma yöntemiyle değil.

Verim genellikle en yavaş paylaşılan kaynakta tıkanır: veritabanı veya dış API limitleri, disk veya ağ bant genişliği, CPU-ağırlıklı işler (JSON/PDF/görüntü yeniden boyutlandırma), kilitler ve paylaşılan durum veya yük altında yavaşlayan downstream servisler.

Eğer paylaşılan kaynak darboğazsa, daha fazla goroutine başlatmak işi daha hızlı bitirmez. Çoğunlukla aynı tıkanma noktasında daha fazla bekleme yaratır.

Görevler kısa, çoğunlukla I/O'ya bağlı ve paylaşılan limitler üzerinde rekabet etmiyorsa görev başına goroutine avantaj sağlayabilir. Goroutine başlatmak ucuzdur ve Go çok sayıda goroutine'i iyi planlar. "Getir, ayrıştır, bir satır yaz" tarzı bir döngüde CPU'ları meşgul tutup ağ gecikmesini gizleyebilir.

İşçi havuzları ise pahalı kaynakları sınırlamanız gerektiğinde kazanır. Her iş bir DB bağlantısı tutuyorsa, dosya açıyorsa, büyük tamponlar ayırıyorsa veya API kotasını zorluyorsa sabit eşzamanlılık hizmeti stabil tutar ve maksimum güvenli verimliliğe ulaşmanızı sağlar.

Gecikme (özellikle p99) farkın genellikle ortaya çıktığı yerdir. Görev başına goroutine düşük yükte iyi görünür, sonra çok fazla iş yığıldığında bir uçurum gibi kötüleşebilir. Havuzlar kuyruğa girme gecikmesi ekler ama davranış daha dengelidir çünkü aynı limiti kapışan bir sürücü sürüsü oluşmasını önlersiniz.

Basit bir zihinsel model:

  • İş ucuz ve bağımsızsa, daha fazla eşzamanlılık verimi artırabilir.
  • İş paylaşılan bir limit tarafından sınırlandırılmışsa, daha fazla eşzamanlılık çoğunlukla beklemeyi artırır.
  • p99 ile ilgileniyorsanız, işlem süresinden ayrı olarak kuyruk süresini ölçün.

Bellek ve kaynak kullanımı

İşçi havuzu vs goroutine başına görev tartışmasının büyük kısmı aslında bellekle ilgilidir. CPU genellikle ölçeklendirilebilir veya yatay olarak artırılabilir. Bellek hataları daha ani olur ve tüm servisi indirebilir.

Bir goroutine ucuzdur ama bedava değildir. Her biri küçük bir yığınla başlar ve daha derin fonksiyon çağırdıkça veya büyük yerel değişkenler tuttukça büyür. Ayrıca zamanlayıcı ve runtime defter işleri vardır. On bin goroutine iyi olabilir. Yüz bin sürpriz yaratabilir, özellikle her biri büyük iş verisine referans tutuyorsa.

Daha büyük gizli maliyet genelde goroutine değil, onun hayatta tuttuğu şeydir. İşler bitmekten daha hızlı gelirse görev başına goroutine sınırsız bir yığıntı yaratır. "Kuyruk" örtük olabilir (goroutinelerin kilitler veya I/O üzerinde beklemesi) veya açık (tamponlu kanal, dilim, bellek içi parti). Her durumda bellek yığıntı ile büyür.

İşçi havuzları işe yarar çünkü sınır koyar. Sabit işçiler ve sınırılı bir kuyruk ile gerçek bir bellek limiti ve net bir hata modu elde edersiniz: kuyruk dolduğunda üreticiyi bloklayın, yükü atın veya yukarı akışa geri basın.

Kaba bir hesap:

  • Zirve goroutine sayısı = işçiler + işlemdeki işler + oluşturduğunuz "bekleyen" işler
  • İş başına bellek = yük (bayt) + meta + referanslar (istekler, ayrıştırılmış JSON, DB satırları)
  • Zirve yığın belleği ~= bekleyen işler * iş başına bellek

Örnek: her iş 200 KB yük tutuyorsa ve 5.000 iş birikmesine izin veriyorsanız, bu sadece yük için yaklaşık 1 GB yapar. Goroutineler sihirli şekilde ücretsiz olsa bile, yığın öyle değil.

Geri basınç: sistemi erimekten korumak

Yığınınıza bağlanın
E-posta, SMS, Telegram, Stripe ve daha fazlasını çekirdek servisinizi yeniden yazmadan bağlayın.
Entegrasyon Ekle

Geri basınç basit: iş, bitirebildiğinizden daha hızlı geliyorsa, sistem görünmez şekilde birikmesine izin vermek yerine kontrollü şekilde geri basar. Olmazsa sadece yavaşlamakla kalmazsınız. Zaman aşımı, bellek artışı ve yeniden üretmesi zor hatalar yaşarsınız.

Eksik geri basıncı genellikle bir patlama olduğunda fark edersiniz: bellek yükselir ve düşmez, kuyruk süresi artar ama CPU meşgul kalır, ilgisiz isteklerde gecikme atlar, yeniden denemeler birikir veya "çok fazla açık dosya" ve bağlantı havuzu tükenmesi gibi hatalar ortaya çıkar.

Pratik bir araç sınırlı bir kanaldır: kaç işin bekleyebileceğini sınırlayın. Kanal dolunca üreticiler bloklanır ve bu iş oluşturmayı kaynağında yavaşlatır.

Bloklama her zaman doğru seçim değildir. Opsiyonel işler için açık bir politika seçin ki aşırı yük öngörülebilir olsun:

  • Düşür düşük değerdeki işleri (ör. yinelenen bildirimler)
  • Partile birçok küçük işi tek bir yazma veya API çağrısında birleştir
  • Geciktir işlere jitter uygulayarak yeniden deneme fırtınalarını önle
  • Ertele işi kalıcı kuyruğa aktarıp hızlıca dön
  • Yük at sistem zaten meşgulse net bir hata döndür

Hız sınırlama ve zaman aşımı da geri basınç araçlarıdır. Hız sınırlama bir bağımlılığa ne kadar hızlı vurduğunuzu sınırlar (e-posta sağlayıcısı, veritabanı, üçüncü taraf API). Zaman aşımı ise bir işçinin ne kadar süre takılabileceğini sınırlar. Birlikte, yavaş bir bağımlılığın tam bir kesintiye dönüşmesini engellerler.

Örnek: ay sonu ekstre üretimi. 10.000 istek bir anda gelirse sınırsız goroutineler 10.000 PDF render ve yükleme başlatabilir. Sınırlı bir kuyruk ve sabit işçilerle render ve yeniden denemeyi güvenli bir tempoda yaparsınız.

Bir işçi havuzu adım adım nasıl kurulur

Geri basıncı görünür kılın
API'nizin yanında yönetim araçları ve iş kontrolleri ekleyin, operatörler olup biteni görebilsin.
Bir Uygulama Oluştur

Bir işçi havuzu, sabit sayıda işçi çalıştırıp onlara kuyruktan iş vererek eşzamanlılığı sınırlar.

1) Güvenli bir eşzamanlılık limiti seçin

İşlerinizin çoğunlukla ne üzerinde zaman geçirdiğinden başlayın.

  • CPU-ağırlıklı işler için işçi sayısını CPU çekirdek sayısına yakın tutun.
  • I/O-ağırlıklı işler (DB, HTTP, depolama) için daha yüksek olabilirsiniz, ama bağımlılıklar zaman aşımı veya kısıtlama yapmaya başladığında durun.
  • Karışık işler için ölçün ve ayarlayın. Makul başlangıç aralığı genelde CPU çekirdeklerinin 2x ila 10x'i arasındadır, sonra ayarlayın.
  • Paylaşılan limitlere saygı gösterin. DB havuzu 20 bağlantıysa 200 işçi sadece o 20 ile yarışır.

2) Kuyruğu seçin ve boyutunu ayarlayın

Tamponlu bir kanal yaygındır çünkü yerleşik ve akla yatkındır. Tampon patlama amortisörünüzdür.

Küçük tamponlar aşırı yükü hızlı ortaya çıkarır (gönderenler daha erken bloklanır). Büyük tamponlar ani şokları düzleştirir ama sorunları gizler ve bellek ile gecikmeyi artırır. Tamponu amaçlı boyutlandırın ve dolunca ne olacağını karar verin.

3) Her görevi iptal edilebilir yapın

Her işe bir context.Context geçirin ve iş kodunun bunu kullandığından emin olun (DB, HTTP). Bu, dağıtımlarda, kapanışlarda ve zaman aşımı durumlarında temiz durmayı sağlar.

func StartPool(ctx context.Context, workers, queueSize int, handle func(context.Context, Job) error) chan\u003c- Job {
    jobs := make(chan Job, queueSize)
    for i := 0; i \u003c workers; i++ {
        go func() {
            for {
                select {
                case \u003c-ctx.Done():
                    return
                case j := \u003c-jobs:
                    _ = handle(ctx, j)
                }
            }
        }()
    }
    return jobs
}

4) Gerçekten kullanacağınız metrikleri ekleyin

Sadece birkaç sayı takip edecekseniz, bunlar olsun:

  • Kuyruk derinliği (ne kadar geride kaldığınız)
  • İşçi meşguliyet süresi (havuzun ne kadar doyduğuna dair)
  • Görev süresi (p50, p95, p99)
  • Hata oranı (ve yeniden deneme sayıları)

Bunlar işçi sayısını ve kuyruk boyutunu tahmin yerine kanıta dayalı ayarlamanızı sağlar.

Yaygın hatalar ve tuzaklar

Çoğu ekip yanlış deseni seçtiği için zarar görmez. Trafik arttığında küçük varsayılanlar nedeniyle sorun yaşarlar.

Goroutinelerin çoğalması

Klasik tuzak, bir patlama altında görev başına bir goroutine spawn etmektir. Birkaç yüz iyidir. Yüz binler zamanlayıcıyı, heap'i, logları ve soketleri doldurabilir. Her goroutine küçük olsa bile toplam maliyet toplanır ve kurtarma zamanı alır çünkü işler zaten işlemde.

Bir diğer hata büyük bir tamponlu kanalı "geri basınç" olarak görmek. Büyük bir tampon sadece gizli bir kuyruktur. Zaman kazandırabilir ama bir bellek duvarına çarpana kadar sorunları saklar. Eğer bir kuyruğa ihtiyacınız varsa, boyutunu bilinçlice seçin ve dolunca ne olacağını belirleyin (blokla, düşür, sonra dene veya kalıcı depolamaya yaz).

Gizli darboğazlar

Birçok arka plan işi CPU-bağımlı değil; downstream bir şeyle sınırlı. Bu limitleri görmezden gelirseniz hızlı üretici yavaş tüketiciyi ezer.

Yaygın tuzaklar:

  • İptal veya zaman aşımı yok, bu yüzden işçiler bir API isteği veya DB sorgusunda sonsuza dek takılabilir
  • Gerçek sınırlar kontrol edilmeden seçilen işçi sayıları (DB bağlantıları, disk I/O, üçüncü taraf kotaları)
  • Yükü artıran yeniden denemeler (1.000 başarısız işte anında yeniden denemeler)
  • Her şeyi seri hale getiren tek bir paylaşılan kilit veya tek işlem
  • Görünürlük eksikliği: kuyruk derinliği, iş yaşı, yeniden deneme sayısı ve işçi kullanımına dair metrik yok

Örnek: gece yapılan bir dışa aktarım 20.000 "bildirim gönder" işi tetikler. Her iş veritabanına ve bir e-posta sağlayıcısına vuruyorsa bağlantı havuzlarını veya kota limitlerini aşmak kolaydır. 50 işçili bir havuz ve her iş için zaman aşımı ve küçük bir kuyruk limiti limiti netleştirir. Görev başına goroutine ve devasa bir tampon sistem iyi görünene kadar çalışır, sonra aniden durur.

Örnek: düzensiz dışa aktarımlar ve bildirimler

İş akışlarını daha hızlı gönderin
Kuyruklar, zaman aşımı ve yeniden denemelerle her şeyi elle bağlamadan bir backend oluşturun.
Hemen Başlayın

Bir destek ekibinin denetim için veri ihtiyacı olduğunu düşünün. Bir kişi "Export" butonuna tıklar, birkaç ekip arkadaşı da aynısını yapar ve bir dakika içinde 5.000 dışa aktarım işi oluşur. Her dışa aktarım veritabanından okur, CSV formatlar, bir dosya depolar ve hazır olunca bildirim (e-posta veya Telegram) gönderir.

Görev başına goroutine yaklaşımıyla sistem bir an için harika hisseder. Tüm 5.000 iş neredeyse anında başlar ve kuyruk hızlıca tükeniyormuş gibi görünür. Sonra maliyetler ortaya çıkar: binlerce eşzamanlı veritabanı sorgusu bağlantılar için yarışır, bellek işler tamponları tutarken yükselir ve zaman aşımı yaygınlaşır. Hızla bitebilecek işler yeniden denemeler ve yavaş sorguların arkasında takılır.

İşçi havuzu ile başlangıç daha yavaştır ama genel çalışma daha sakin olur. 50 işçi ile bir anda yalnızca 50 dışa aktarım ağır iş yapar. Veritabanı kullanımı öngörülebilir aralıkta kalır, tamponlar daha sık yeniden kullanılır ve gecikme daha stabildir. Tamamlanma süresi de tahmin edilebilir: kabaca (işler / işçi) * ortalama iş süresi artı bazı overhead.

Fark, havuzların sihirli şekilde daha hızlı olması değil. Patlamalar sırasında sistemin kendi kendine zarar vermesini engellemeleridir. Kontrollü 50'şer çalıştırma çoğu zaman 5.000 işin birbirleriyle kavga etmesinden daha çabuk biter.

Geri basıncı nerede uygulayacağınız, korumak istediğiniz şeye bağlıdır:

  • API katmanında, sistem meşgulse yeni dışa aktarım isteklerini reddedin veya geciktirin.
  • Kuyrukta, istekleri kabul edin ama işleri sıraya alın ve güvenli hızda tüketin.
  • İşçi havuzunda, pahalı parçalar için eşzamanlılığı sınırlayın (DB okuma, dosya oluşturma, bildirim gönderme).
  • Kaynak başına ayrı limitler koyun (ör. dışa aktarımlar için 40 işçi, bildirimler için 10 işçi).
  • Dış çağrılarda, e-posta/SMS/Telegram için hız sınırı koyun ki engellenmeyin.

Yayına almadan önce hızlı kontrol listesi

Uygun yerde dağıtın
AppMaster Cloud'da, kendi bulutunuzda veya dışa aktarılan koddan self-host olarak çalıştırın.
Şimdi Dağıt

Arka plan işlerini üretime almadan önce limitler, görünürlük ve hata işleme açısından bir kontrol yapın. Çoğu olay "yavaş kod"tan değil; yük patladığında veya bir bağımlılık dalgalandığında eksik gardarıplardan kaynaklanır.

  • Her bağımlılık için sert maksimum eşzamanlılık belirleyin. Tek bir genel sayı seçip her şeyin sığacağını ummayın. DB yazılarını, dış HTTP çağrılarını ve CPU-ağırlıklı işleri ayrı ayrı sınırlayın.
  • Kuyruğu sınırlandırın ve gözlemlenebilir kılın. Bekleyen işler için gerçek bir limit koyun ve birkaç metrik sergileyin: kuyruk derinliği, en eski işin yaşı ve işleme hızı.
  • Jitter ile yeniden denemeler ve bir dead-letter yolu ekleyin. Yeniden denemeleri seçici yapın, yayarak yapın ve N başarısızlıktan sonra işi yeniden gözden geçirmek ve tekrar oynamak için dead-letter kuyruğuna veya "failed" tablosuna taşıyın.
  • Kapatma davranışını doğrulayın: drain, cancel, güvenli devam. Deploy veya çökme sırasında ne olacağını kararlaştırın. İşlerin idempotent olmasını sağlayın, böylece yeniden işleme güvenli olsun ve uzun iş akışları için ilerlemeyi saklayın.
  • Zaman aşımı ve devre kesicilerle sistemi koruyun. Her dış çağrı için bir zaman aşımı koyun. Bir bağımlılık kapalıysa hızlıca başarısız olun (veya alımı durdurun) ki iş birikmesin.

Pratik sonraki adımlar

Normal gününüzde sisteminizin nasıl göründüğüne uygun deseni seçin, mükemmel güne değil. İşler patlayıcı geliyorsa (yüklemeler, dışa aktarımlar, e-posta patlamaları) sabit işçi havuzu ve sınırılı bir kuyruk genellikle daha güvenli bir varsayılan olur. İş hacmi stabil ve her görev küçükse görev başına goroutine uygun olabilir, yeter ki bir yerde sınır uygulansın.

Kazanan seçim genelde başarısızlığı sıkıcı yapan seçimdir. Havuzlar limitleri bariz kılar. Görev başına goroutine ise genellikle sınırları unutmayı kolaylaştırır, ta ki ilk gerçek spike gelene kadar.

Basit başla, sonra sınırlar ve görünürlük ekle

Basit bir şeyle başlayın, ama erken iki kontrol ekleyin: eşzamanlılıkta bir sınır ve kuyruklama ve hataları görmenizi sağlayan bir yol.

Pratik bir devreye alma planı:

  • İş yükünüzün şeklini tanımlayın: patlamalı, sabit veya karışık (ve "tepe"nin ne olduğunu).
  • Eşzamanlı işlem için sert bir üst sınır koyun (havuz boyutu, semaphore veya sınırlı kanal).
  • Üst sını dolunca ne olacağını kararlaştırın: blokla, düşür veya net bir hata döndür.
  • Temel metrikleri ekleyin: kuyruk derinliği, kuyrukta geçirilen süre, işleme süresi, yeniden denemeler ve dead-letter'lar.
  • Beklenen tepenizin 5x'i ile bir yük testi yapın ve bellek ile gecikmeyi izleyin.

Bir havuz yetmezse

İş akışları dakika ila günler sürebiliyorsa basit bir havuz zorlanır çünkü iş yalnızca "bir kere yap" değil. Durum, yeniden deneme ve sürdürme gerekir. Bu genelde ilerlemeyi kalıcı hale getirmeyi, adımları idempotent yapmayı ve gerileme uygulamayı gerektirir. Büyük bir işi güvenli şekilde yeniden başlatabilmek için işi daha küçük adımlara bölmek gerekebilir.

Tam bir backend ile iş akışlarını daha hızlı dağıtmak isterseniz, AppMaster (appmaster.io) pratik bir seçenek olabilir: veriyi ve iş mantığını görsel olarak modelleyip gerçek Go kodu ürettirerek eşzamanlılık limitleri, kuyruklama ve geri basınç etrafında aynı disiplini elle her şeyi bağlamadan korumanıza yardımcı olur.

SSS

When should I use a worker pool instead of starting a goroutine for every task?

Varsayılan olarak, işler patlayabilir veya DB bağlantıları, CPU ya da üçüncü taraf API kotaları gibi paylaşılan sınırlara dokunuyorsa işçi havuzu kullanın. İş hacmi az, görevler kısa ise ve bir yerde (ör. semafor veya hız sınırlayıcı) net bir sınırınız varsa görev başına goroutine tercih edilebilir.

What’s the real tradeoff between goroutine-per-task and a worker pool?

Görev başına goroutine yazması hızlıdır ve düşük yükte yüksek verim sağlayabilir, ama dalgalanmada sınır tanımayan birikime yol açabilir. İşçi havuzu ise sert eşzamanlılık sınırı, zaman aşımı ve yeniden deneme uygulamak için net bir yer sağlar; bu da üretimde daha öngörülebilir davranış getirir.

Will a worker pool reduce throughput compared to goroutine-per-task?

Genellikle çok az. Çoğu sistemde verim, veritabanı, dış API, disk veya CPU gibi paylaşılan bir darboğazla sınırlanır. Daha fazla goroutine bu limiti aşmaz; çoğunlukla beklemeyi ve rekabeti artırır.

How do these patterns affect latency (especially p99)?

Goroutine-per-task düşük yükte iyi gecikme sağlayabilir, fakat yüksek yükte her şey aynı kaynak için yarışınca gecikmeler, özellikle p99, kötüleşir. Havuzlar kuyruğa girme gecikmesi ekler ancak bağımlılıklar üzerinde kasırga etkisi yaratmayı engelleyerek p99’u daha sabit tutar.

Why can goroutine-per-task cause memory spikes?

Aslında büyük maliyet genelde goroutine değil, biriken işlerin tuttuğu veri ve referanslardır. Görevler yığılıp her biri büyük nesneler tutuyorsa bellek hızla yükselebilir. İşçi havuzu ve sınırlı kuyruk bunu tanımlı bir bellek tavanına ve öngörülebilir bir aşırı yük davranışına dönüştürür.

What is backpressure, and how do I add it in Go?

Geri basınç, sistem zaten meşgulken yeni işi yavaşlatmak veya kabul etmeyi durdurmaktır; bu sayede iş görünmez şekilde birikmez. Basit bir formu, dolu olduğunda üreticilerin bloklandığı sınırlı bir kanal kullanmaktır; bu, bellek ve bağlantı tükenmesini önler.

How do I choose the right number of workers?

Gerçek sınırdan başlatın. CPU-ağırlıklı işler için işçi sayısını CPU çekirdek sayısına yakın tutun. I/O-ağırlıklı işler için daha fazla olabilirsiniz ama veritabanı, ağ veya üçüncü taraf API’lar zaman aşımına veya kısıtlamaya başlayınca artırmayı durdurun; bağlantı havuzlarını göz önünde bulundurun.

How big should the job queue/buffer be?

Normal dalgalanmaları absorbe eden, ama dakikalarca sorunu gizlemeyecek bir boyut seçin. Küçük tamponlar aşırı yükü hızlı gösterir; büyük tamponlar bellek kullanımını artırır ve hataların ortaya çıkmasını geciktirir. Kuyruk dolduğunda ne olacağını (blokla, reddet, düşür veya başka yere kalıcı kaydet) baştan kararlaştırın.

How do I prevent workers from getting stuck forever?

Her işe context.Context geçirin ve DB/HTTP çağrılarının bunu kullanmasını sağlayın. Dış çağrılarda zaman aşımı koyun ve kapatma davranışını açık hale getirin ki işçiler temiz şekilde durabilsin ve asılı goroutine kalmasın.

What metrics should I monitor for background jobs?

Kuyruk derinliği, kuyrukta geçirilen süre, görev süresi (p50/p95/p99) ve hata/yeniden deneme sayıları. Bu metrikler işçi sayısını, kuyruk boyutunu ve zaman aşımı/limit ihtiyaçlarını veriyle ayarlamanıza imkan verir.

Başlaması kolay
Harika bir şey yaratın

Ücretsiz planla AppMaster ile denemeler yapın.
Hazır olduğunuzda uygun aboneliği seçebilirsiniz.

Başlayın