4 dakika
Dağıtık Sistemler
The Graph, dağıtık bir sistem olarak uygulanmış bir protokoldür.
Bağlantılar kesilir. İstekler sıralanmamış şekilde ulaşır. Saatleri ve durumları senkronize olmayan farklı bilgisayarlar ilişkili istekleri işler. Sunucular yeniden başlatılır. İstekler arasında yeniden düzenlemeler meydana gelir. Tüm bu sorunlar tüm dağıtık sistemlerin doğasında vardır; ancak küresel ölçekte çalışan sistemlerde bu durumlar daha da şiddetlenir.
Bir istemcinin, bir yeniden düzenleme (re-org) sırasında en güncel veriyi almak için bir Endeksleyici’yi yokladığı (polling) durumda yaşanabilecek aşağıdaki örneği göz önünde bulundurun.
- Endeksleyici blok 8’i alır ve işler
- İstemciye blok 8 için istek sunulur
- Endeksleyici blok 9’i alır ve işler
- Endeksleyici blok 10A’yı alır ve işler
- İstemciye blok 10A için istek sunulur
- Endeksleyici, 10B bloğuna yönelik bir yeniden düzenlemeyi algılar ve 10A’yı geri alır (rollback)
- İstemciye blok 9 için istek sunulur
- Endeksleyici blok 10B’yi alır ve işler
- Endeksleyici blok 11’i alır ve işler
- İstemciye blok 11 için istek sunulur
Endeksleyicinin bakış açısından işler mantıklı olarak ilerlemektedir. Zaman ileriye doğru akıyor, her ne kadar bir “uncle” bloğu geri almak ve onun yerine üzerinde konsensüs sağlanan bloku yeniden yürütmek zorunda kalmış olsak da. Bu süreçte, Endeksleyici, o anda bildiği en güncel durumu kullanarak gelen istekleri karşılar.
Ancak istemci bakış açısından işler kaotik görünür. İstemci, yanıtların sırasıyla 8, 10, 9 ve 11 numaralı bloklar için olduğunu gözlemler. Buna “blok dalgalanması” sorunu diyoruz. Bir istemci blok dalgalanması yaşadığında, veri zaman içinde kendisiyle çelişiyormuş gibi görünebilir. Bu durum, tüm Endeksleyicilerin son blokları aynı anda alıp işlememesi ve isteklerinizin birden fazla Endeksleyiciye yönlendirilebilmesi nedeniyle daha da kötüleşir.
Kullanıcıya tutarlı veri sunmak, istemci ve sunucunun ortak sorumluluğundadır ve beraber çalışmalarını gerektirir. Her problem için tek bir doğru program olmadığından, hedeflenen tutarlılık düzeyine göre farklı yaklaşımlar kullanılmalıdır.
Dağıtık sistemlerin sonuçlarını değerlendirmek zor olabilir, ancak çözüm o kadar da karmaşık olmak zorunda değil! Bazı yaygın kullanım senaryolarında yolunuzu bulmanıza yardımcı olmak için API’ler ve kalıplar oluşturduk. Aşağıdaki örnekler bu kalıpları göstermektedir; ancak temel fikirleri gölgelememek adına, hata yönetimi ve iptal gibi üretim ortamında gerekli olan bazı ayrıntılar atlanmıştır.
Güncellenmiş veriler için yoklama yapma
The Graph, yanıtın yalnızca $minBlock
değerine eşit veya daha büyük tek bir blok için verilmesini garanti eden block: { number_gte: $minBlock }
API’sini sağlar. Eğer istek bir graph-node
örneğine yapılırsa ve belirtilen minimum blok henüz senkronize edilmemişse, graph-node
bir hata döndürür. Eğer graph-node
minimum bloğu senkronize ettiyse, yanıtı en son blok için üretir. İstek bir Edge & Node Gateway üzerinden yapılırsa, Gateway henüz minimum bloku senkronize etmemiş olan Endeksleyicileri filtreler ve isteği Endeksleyicinin senkronize ettiği en son blok için yapar.
Bir döngü içinde veri yoklaması yaparken zamanın asla geriye gitmemesini sağlamak için number_gte
ifadesini kullanabiliriz. İşte bir örnek:
1/// The Graph kullanarak protocol.paused değişkenini2/// döngü içerisinde en son bilinen değere günceller.3async function updateProtocolPaused() {4 // minBlock = 0 ile başlamak sorun değildir. Sorgu,5 // mevcut en güncel blok kullanılarak yanıtlanacaktır.6 // minBlock'u 0 olarak ayarlamak, bu argümanı hiç vermemekle aynıdır.7 let minBlock = 089 for (;;) {10 // Bir sonraki Ethereum blokunun muhtemelen hazır olacağı zamanda11 // tetiklenecek bir promise planla.12 const nextBlock = new Promise((f) => {13 setTimeout(f, 14000)14 })1516 const query = `17 query GetProtocol($minBlock: Int!) {18 protocol(block: { number_gte: $minBlock } id: "0") {19 paused20 }21 _meta {22 block {23 number24 }25 }26 }`2728 const variables = { minBlock }29 const response = await graphql(query, variables)30 minBlock = response._meta.block.number3132 // TODO: Burada loglamak yerine yanıt verisiyle bir şey yap.33 console.log(response.protocol.paused)3435 // Bir sonraki bloku beklemek için uykuya geç36 await nextBlock37 }38}
İlişkili ögelerden oluşan bir küme getirme
Bir diğer kullanım senaryosu ise büyük bir kümenin ya da daha genel olarak, birden fazla istek üzerinden ilişkili ögelerin getirilmesidir. Yoklama (polling) senaryosundan farklı olarak (orada hedeflenen tutarlılık zaman içinde ileri gitmekti), burada hedeflenen tutarlılık tek bir zaman noktasına aittir.
Burada, tüm sonuçlarımızı aynı bloka sabitlemek için block: { hash: $blockHash }
argümanını kullanacağız.
1/// Sayfalama kullanarak tek bir bloktan alan adları listesini alır2async function getDomainNames() {3 // // Çekilecek en fazla öge sayısına bir sınır koy.4 let pages = 55 const perPage = 100067 // İlk sorgu, ilk sayfadaki sonuçları alacak ve aynı zamanda8 // kalan sorguların ilk sorguyla tutarlı olabilmesi için blok hash'ini alacak.9 const listDomainsQuery = `10 query ListDomains($perPage: Int!) {11 domains(first: $perPage) {12 name13 id14 }15 _meta {16 block {17 hash18 }19 }20 }`2122 let data = await graphql(listDomainsQuery, { perPage })23 let result = data.domains.map((d) => d.name)24 let blockHash = data._meta.block.hash2526 let query27 // Ya toplamda 5 sayfalık sınırı aşana kadar (yukarıda belirtildiği gibi)28 // son sayfaya ulaştığımızı görene kadar (sayfada tam sayfadan az varlık varsa)29 // ek sayfaları getirmeye devam et.30 while (data.domains.length == perPage && --pages) {31 let lastID = data.domains[data.domains.length - 1].id32 query = `33 query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) {34 domains(first: $perPage, where: { id_gt: $lastID }, block: { hash: $blockHash }) {35 name36 id37 }38 }`3940 data = await graphql(query, { perPage, lastID, blockHash })4142 // Alan adlarını sonuca ekle43 for (domain of data.domains) {44 result.push(domain.name)45 }46 }47 return result48}
Bir yeniden düzenleme durumunda, istemcinin blok hash’ini bir “uncle” olmayan blokla güncellemek için ilk isteği baştan tekrar etmesi gerekeceğini unutmayın.