Querying > Distribuerade System

Distribuerade System

Reading time: 5 min

The Graph är ett protokoll implementerat som ett distribuerat system.

Anslutningar misslyckas. Förfrågningar anländer i fel ordning. Olika datorer med osynkroniserade klockor och tillstånd bearbetar relaterade förfrågningar. Servrar startar om. Omorganiseringar inträffar mellan förfrågningar. Dessa problem är inneboende för alla distribuerade system men förvärras i system som opererar globalt.

Betrakta detta exempel på vad som kan inträffa om en klient undersöker en Indexer för den senaste datan under en omorganiseringar.

  1. Indexer bearbetar block 8
  2. Förfrågan serveras till klienten för block 8
  3. Indexer bearbetar block 9
  4. Indexer bearbetar block 10A
  5. Förfrågan serveras till klienten för block 10A
  6. Indexer upptäcker omorganiseringar till 10B och rullar tillbaka 10A
  7. Förfrågan serveras till klienten för block 9
  8. Indexer bearbetar block 10B
  9. Indexer bearbetar block 11
  10. Förfrågan serveras till klienten för block 11

Ur Indexerns synvinkel fortskrider saker logiskt framåt. Tiden går framåt, även om vi var tvungna att rulla tillbaka ett uncle-block och spela in blocket under konsensus framåt ovanpå det. Under vägen serverar Indexern förfrågningar med den senaste informationen den känner till vid den tiden.

Ur klientens synvinkel verkar dock saker kaotiska. Klienten observerar att svaren var för block 8, 10, 9 och 11 i den ordningen. Vi kallar detta "block wobble"-problemet. När en klient upplever block wobble kan data verka motsäga sig över tiden. Situationen förvärras när vi tänker på att Indexers inte alla bearbetar de senaste blocken samtidigt, och dina förfrågningar kan routas till flera Indexers.

Det är klientens och serverns ansvar att samarbeta för att ge användaren konsekvent data. Olika metoder måste användas beroende på önskad konsekvens, eftersom det inte finns ett rätt program för varje problem.

Att resonera kring följderna av distribuerade system är svårt, men lösningen behöver inte vara det! Vi har etablerat API:er och mönster för att hjälpa dig hantera några vanliga användningsfall. Följande exempel illustrerar dessa mönster, men utesluter fortfarande detaljer som krävs av produktionskod (som felhantering och avbokning) för att inte försvåra huvudidéerna.

Polla efter uppdaterad data

Länk till detta avsnitt

The Graph tillhandahåller APIblock: { number_gte: $minBlock }, vilket säkerställer att svaret gäller ett enskilt block som är lika med eller högre än $minBlock. Om förfrågan görs till en instans av graph-node och det minsta blocket ännu inte har synkroniserats, kommer graph-node att returnera ett fel. Om graph-node har synkroniserat det minsta blocket kommer det att köra svaret för det senaste blocket. Om förfrågan görs till en Edge & Node Gateway kommer Gatewayen att filtrera bort Indexers som ännu inte har synkroniserat det minsta blocket och göra förfrågan för det senaste blocket som Indexern har synkroniserat.

Vi kan använda number_gte för att säkerställa att tiden aldrig går bakåt när vi pollar efter data i en loop. Här är ett exempel:

/// Uppdaterar variabeln protocol.paused till det senaste
/// kända värdet i en loop genom att hämta det med The Graph.
async function updateProtocolPaused() {
// Det är okej att börja med minBlock på 0. Förfrågan kommer att serveras
// med den senaste tillgängliga blocket. Att sätta minBlock till 0 är detsamma som
// att utelämna det argumentet.
let minBlock = 0
for (;;) {
// Schemalägg ett löfte som kommer vara redo så snart
// nästa Ethereum-block sannolikt kommer att vara tillgängligt.
const nextBlock = new Promise((f) => {
setTimeout(f, 14000)
})
const query = `
query GetProtocol($minBlock: Int!) {
protocol(block: { number_gte: $minBlock } id: "0") {
paused
}
_meta {
block {
number
}
}
}`
const variables = { minBlock }
const response = await graphql(query, variables)
minBlock = response._meta.block.number
// TODO: Gör något med svarsdatan här istället för att logga den.
console.log(response.protocol.paused)
// Vänta för att nästa block ska behandlas
await nextBlock
}
}

Hämta en uppsättning relaterade objekt

Länk till detta avsnitt

Ett annat användningsfall är att hämta en stor uppsättning eller mer generellt att hämta relaterade objekt över flera förfrågningar. Till skillnad från fallet med att hämta uppdaterade data (där önskad konsekvens var att gå framåt i tiden), är önskad konsekvens här att få data från en enda tidpunkt.

Här kommer vi att använda argumentet block: { hash: $blockHash } för att binda alla våra resultat till samma block.

/// Gets a list of domain names from a single block using pagination
async function getDomainNames() {
// Set a cap on the maximum number of items to pull.
let pages = 5
const perPage = 1000
// The first query will get the first page of results and also get the block
// hash so that the remainder of the queries are consistent with the first.
const listDomainsQuery = `
query ListDomains($perPage: Int!) {
domains(first: $perPage) {
name
id
}
_meta {
block {
hash
}
}
}`
let data = await graphql(listDomainsQuery, { perPage })
let result = data.domains.map((d) => d.name)
let blockHash = data._meta.block.hash
let query
// Continue fetching additional pages until either we run into the limit of
// 5 pages total (specified above) or we know we have reached the last page
// because the page has fewer entities than a full page.
while (data.domains.length == perPage && --pages) {
let lastID = data.domains[data.domains.length - 1].id
query = `
query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) {
domains(first: $perPage, where: { id_gt: $lastID }, block: { hash: $blockHash }) {
name
id
}
}`
data = await graphql(query, { perPage, lastID, blockHash })
// Accumulate domain names into the result
for (domain of data.domains) {
result.push(domain.name)
}
}
return result
}

Observera att i händelse av en omorganisation måste klienten försöka igen från den första begäran för att uppdatera blockhashen till ett icke-farbrorblock.

Redigera sida

Tidigare
Att göra förfrågningar från en Applikation
Nästa
GraphQL API
Redigera sida