GraphQL abonelikleriyle sunucudan istemciye anlık veri akışı kurmak
Beceri rehberi

GraphQL abonelikleriyle sunucudan istemciye anlık veri akışı kurmak

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 5 dk okuma

GraphQL subscription nasıl kurulur: Subscription tipi, pub/sub akışı, WebSocket ve SSE taşıması, ölçekleme zorlukları ve polling ile karşılaştırma.

Abonelik, sorgudan ve mutation'dan nasıl ayrılır?

Sorgu ve mutation, tek istek ve tek yanıt döngüsüne dayalı durumsuz işlemlerdir. GraphQL belirtimi bunlara ek olarak, uzun ömürlü isteklerle gerçek zamanlı güncelleme almayı da tarif eder: abonelik (subscription). İstemci aboneliği başlatır, bağlantı açık kalır ve sunucu veri değiştikçe istemciye yeni sonuçlar iter.

Abonelik, sorgu ve mutation'ın yanındaki işlem türüdür ve alanları Subscription kök tipinde tanımlanır. Mesajların kaynağı genellikle ayrı bir pub/sub sistemidir: veri güncellendiğinde bir olay yayımlanır ve abonelik alanının resolver'ı bu olayı tüketip bağlı istemcilere gönderir. Abonelik, bazı uygulamaların sunduğu ve gevşek tanımlı bir özellik olan canlı sorgu (live query) ile aynı şey değildir.

Şemada tanım ve istemcide başlatma

Şemaya kök tip eklenir:

type Subscription { orderCreated: Order }

İstemci aboneliği subscription anahtar kelimesiyle başlatır ve istediği alanları seçer:

subscription NewOrderCreated { orderCreated { id status } }

Bir abonelik işleminin tam olarak tek bir kök alanı olmalıdır. Bir belgede birden fazla abonelik işlemi bulunabilir, ancak her birine ad verilmesi gerekir. Aynı işlemde birden fazla kök alanı birlikte seçmek geçersizdir. Sorgudaki alan seçimi, değişken ve takma ad gibi birçok özellik abonelikte de kullanılabilir.

Sunucu tarafı akış: yayımla, dinle, ilet

Tipik akış şudur: bir mutation çalışır ve veriyi değiştirir; ardından sunucu pub/sub sistemine bir olay yayımlar; abonelik alanının resolver'ı bu olayı dinler ve her olay geldiğinde abone istemciye sonucu gönderir. Şu sözde kod mantığı gösterir (gerçek yöntem adları kullandığınız kütüphaneye göre değişir):

Mutation: { createOrder: async (parent, args, context) => { const order = await context.db.orders.create(args.input); await context.pubsub.publish('ORDER_CREATED', { orderCreated: order }); return order; }, }, Subscription: { orderCreated: { subscribe: (parent, args, context) => context.pubsub.subscribe('ORDER_CREATED'), }, },

Olay yükünü (payload) küçük ve amaca yönelik tutun: orderCreated gibi bir olayda tüm sipariş nesnesini göndermek yerine, istemcinin ihtiyaç duyduğu alanlara yetecek kadar veri taşıyın; ayrıntıyı gerekirse istemci ayrı bir sorguyla alır.

Üretimde bellek içi bir pub/sub yetmez; birden fazla sunucu örneği çalışıyorsa olaylar bir mesaj aracısı üzerinden dağıtılmalıdır, aksi halde bir örnekte yayımlanan olay başka örneğe bağlı istemciye ulaşmaz.

Taşıma katmanı: WebSocket ya da sunucu tarafından gönderilen olaylar

GraphQL, hangi taşıma protokolünün kullanılacağını belirtmez; bu sunucunun kararıdır. Uygulamada abonelikler çoğunlukla WebSocket ya da sunucu tarafından gönderilen olaylar (server-sent events, SSE) üzerinden çalıştırılır. Bu yöntemlerin her biri için topluluk tarafından yazılmış protokol belirtimleri bulunur (graphql-ws ve graphql-sse). İstemci, sunucunun seçtiği protokolü desteklemek zorundadır.

Seçim kriterleri: SSE tek yönlü ve HTTP üzerinden işlediği için ağ altyapısıyla uyumu kolaydır; çift yönlü iletişime ihtiyaç varsa WebSocket daha uygundur. Güvenlik duvarı, vekil sunucu ve yük dengeleyici ayarlarının uzun ömürlü bağlantılara izin verdiğini baştan doğrulayın.

Ölçekleme, durum ve yetki: abonelikler neden daha zordur?

Abonelik durumludur: sunucunun, aboneliğin belgesini, değişkenlerini ve bağlamını bağlantı boyunca saklaması gerekir. Yatay ölçeklemede her abone istemci belirli bir sunucu örneğine bağlıdır; bu, durumsuz sorguları ölçeklemekten daha zordur. Bağlantı sayısı arttıkça bellek ve açık bağlantı limitleri planlanmalıdır.

Yetkilendirme de ayrıca düşünülmelidir. Kimlik doğrulama bağlantı kurulurken yapılır; ancak bağlantı açık kaldığı süre boyunca yetki değişebilir. Olay yayımlandığında hangi abonenin hangi veriyi görmeye yetkili olduğunu filtreleyin; yalnızca "abone oldu" bilgisine güvenmeyin. Örneğin yalnızca kendi siparişlerini izleyebilen bir kullanıcıya başkasının siparişi iletilmemelidir.

İstemci tarafında da ek iş vardır: bağlantı koptuğunda yeniden abone olmak ve ilk sorgu ile abonelikten gelen güncelleme arasındaki yarış durumlarını yönetmek gerekir.

Abonelik ne zaman doğru seçimdir, ne zaman değildir?

Abonelikler, sık ve artımlı değişen verilerde ve istemcinin bu güncellemeleri gerçek zamana mümkün olduğunca yakın almasının gerektiği durumlarda uygundur. Örneğin sohbet mesajları, canlı sipariş durumu, anlık pano göstergeleri ya da ortak düzenleme ekranları.

Veri daha seyrek güncelleniyorsa daha basit yöntemler yeterli olabilir: periyodik sorgulama (polling), mobil anlık bildirimler ya da kullanıcı etkileşimine göre sorguyu yeniden çekmek. Abonelik içeren bir API daha karmaşık bir mimari gerektirir ve bu karmaşıklık kullanılabilirlik, ölçeklenebilirlik ve güvenlik gereksinimlerine göre değişir. Önce gerçek zamanlılık ihtiyacının ne kadar sıkı olduğunu sorun: birkaç saniyelik gecikme kabul edilebiliyorsa polling daha ucuz bir çözüm olabilir.

Abonelik kurarken sık yapılan hatalar

  • Tek bir sunucu örneğinde çalışan bellek içi pub/sub ile yayına çıkmak.
  • Abonelik alanlarında filtre ve yetki kontrolü yapmamak.
  • Çok geniş olaylar yayımlamak: her küçük değişikliğin bütün nesneyi göndermesi gereksiz trafik üretir; olay yükünü gereken alanlarla sınırlayın.
  • İstemcide bağlantı kopması senaryosunu denememek.
  • Aboneliği kapatmayı unutmak: ekran ya da bileşen kapandığında aboneliği iptal etmezseniz sunucuda gereksiz açık bağlantı ve bellek birikir.
  • Abonelik sayısını ve bağlantı süresini izlememek; açık bağlantılar sessizce birikir.
  • Her ekrana abonelik eklemek: gerçekten anlık olması gerekmeyen veriyi sorguyla almak sistemi sadeleştirir.

Bu beceriyi Mindset programlarında nerede çalışırsınız?

GraphQL ile API Geliştirme eğitimindeki Gerçek Zamanlı: Abonelikler modülü, bu sayfadaki Subscription tipi, pub/sub akışı ve taşıma seçimini çalışır; eğitim, GraphQL sunucusu geliştiren arka yüz mühendislerine ve gerçek zamanlı ekranlar tasarlayan ekiplere uygundur. Apollo GraphQL ile İstemci ve Sunucu Geliştirme eğitiminin Abonelikler ve Gerçek Zamanlı Veri modülü ise aynı konuyu Apollo ekosistemiyle, istemci ve sunucu tarafını birlikte ele alır.

Örneğin canlı bir sipariş panosu kurarken, panonun yalnızca durum değişikliklerini dinlemesi ve ilk yüklemeyi normal bir sorguyla yapması, bağlantı kesildiğinde de sorguyu yeniden çekerek eksik kalan güncellemeleri kapatması dayanıklı bir yaklaşımdır. Takım olarak çalışırken sorulacak ortak soru şudur: hangi ekranlar gerçekten anlık veri istiyor ve bunun maliyetini ödemeye değer mi?

İlgili Mindset programı

GraphQL ile API Geliştirme

Sık sorulanlar

Sık sorulan sorular

GraphQL subscription WebSocket zorunlu mu?

Hayır. GraphQL belirtimi taşıma protokolünü belirlemez. Uygulamada WebSocket ve sunucu tarafından gönderilen olaylar (SSE) yaygındır. İstemci ve sunucunun aynı protokolü kullanması yeterlidir; her yöntem için topluluk protokol belirtimleri vardır. Örneğin güvenlik duvarının WebSocket bağlantısını kestiği bir kurumsal ağda SSE tabanlı aktarım tercih edilebilir.

Subscription ile polling arasında nasıl karar verilir?

Veri sık ve artımlı değişiyorsa ve istemci güncellemeyi neredeyse anında görmeliyse abonelik uygundur. Güncelleme seyrekse ya da kısa gecikme kabul ediliyorsa polling, anlık bildirim ya da etkileşimde yeniden sorgu daha basit ve ucuz olabilir.

Abonelikte neden birden fazla kök alan seçemem?

Belirtime göre her abonelik işleminin tam olarak tek kök alanı olmalıdır. Aynı anda birden fazla olay akışı dinlemek istiyorsanız her biri için ayrı, adlandırılmış abonelik işlemi tanımlarsınız. Birden fazla kök alanı tek işlemde seçmek geçersiz sayılır.

Abonelikler yatay ölçeklemeyi nasıl etkiler?

Her abone istemci belirli bir sunucu örneğine bağlı kaldığı için durumsuz sorgulardan daha zor ölçeklenir. Birden fazla örnek kullanıyorsanız olayları bir mesaj aracısı üzerinden dağıtmanız ve açık bağlantıların kaynak tüketimini planlamanız gerekir.

GraphQL Subscription ile Gerçek Zamanlı Veri