Progettazione per la sincronizzazione client-server

4

Sfondo

Sto lavorando per migliorare il design del backend per un videogioco. Il gioco è vivo e funziona bene, ma vogliamo migliorare varie cose. Come studio di videogiochi, facciamo spesso eventi che a volte richiedono un po 'di complicazioni mentre l'evento è in diretta: ci piacerebbe essere in grado di apportare queste modifiche senza dover forzare un aggiornamento sui giocatori.

Problema

Il nostro back-end attuale utilizza vari valori codificati che utilizzano i nostri endpoint. Questo significa che se vogliamo cambiare il comportamento di un endpoint dobbiamo ridistribuire. Ad esempio, se decidiamo che un determinato elemento del negozio online deve puntare a qualcos'altro, è necessario modificare l'ID a cui fa riferimento l'endpoint. Questo è ingombrante e non ideale; vogliamo un modo più dinamico di cambiare le configurazioni.

L'idea generale che abbiamo è che memorizziamo queste proprietà in un file su S3 / a CDN e il client e il back-end le recuperano periodicamente. Ci sono problemi con questo approccio quando si tratta di garantire che sia il back-end sia il client utilizzino la stessa configurazione.

Soluzioni modificate per chiarezza

Soluzioni possibili

Soluzione A)

Crea un'API che permetta l'origine del file "truthiest" per parlare al server. Spingi questo nuovo file nella cache del server ogni volta che c'è una modifica. Quindi, ogni volta che il client parla al server, controlla la versione / hash del file del client e confrontalo con ciò che abbiamo. Se corrisponde, procedere, altrimenti 1) forzare l'aggiornamento del client, 2) dire al client di aggiornarlo manualmente (nel senso che neghiamo l'accesso fino a quel momento) o 3) avere un margine di versione che darà abbastanza tempo per il client aggiornamento, in teoria.

Pro

  • evitaviaggidiandataeritornotraservereproviderdifile

Contro

  • nonèsicuroqualesialasoluzionemiglioreperlasincronizzazione(1,2o3)
  • piùlavororichiestopercostruireAPIecc...

SoluzioneB)Siailclientcheilservereffettuanochiamateperiodicamentepervederesec'èunanuovaconfigurazione.Quandoilclientparlaalservereleversioninoncorrispondono,abbiamodinuovole3opzioni,solochequestavoltailserverdeveeffettuarechiamateallamemoria(lafontepiùtropo)perverificarequaleversioneèquellacorretta.

Pro

  • meno lavoro della soluzione A

Contro

  • meno affidabile, troppi punti di debolezza
  • troppi round trip tra server-storage e client-storage.

Nota sullo spazio di archiviazione Ci sono problemi sia con S3 che con un CDN. S3 non è sempre onesto - a volte può restituire dati più vecchi - non è una singola fonte di verità. Un CDN è utile in quanto i client scaricheranno questi dati per la loro lingua specifica, ma la ridistribuzione di ciascuna nuova versione può richiedere tempo, motivo per cui potremmo aver bisogno di un margine di manovra.

Questa è una breve panoramica delle idee che avevamo. Ci sono avvertenze che possono o non sono state delineate, ma stiamo cercando di scoprire come viene tipicamente gestito questo genere di cose.

    
posta turnip 24.11.2017 - 17:11
fonte

2 risposte

3

tl; dr: quando giri il contenuto, rev il nome del file.

The general idea we had is that we store these properties in a file on S3 / a CDN and the client and the backend fetch these periodically.

No, questo è il design sbagliato, a causa delle preoccupazioni che citi.

Potresti avere una conversazione in corridoio su qualche codice client "che manipola il file di configurazione", va bene. Ma ciò che è cruciale per la tua configurazione è che l' URI del file di configurazione "the" deve cambiare ogni volta che lo giri. Questo induce errori di cache e fa sì che i client siano esattamente sincronizzati con il server, come desideri. La gerarchia della cache ha molti livelli, alcuni dei quali puoi vedere o controllare, e inventare un nuovo URI ha il piacevole effetto di causare errori di cache ad ogni livello.

È una semplice questione di virare su un timestamp ISO8601 e un numero seriale o un hash sull'URI del file di configurazione.

A seconda della frequenza con cui la tua configurazione si abbandona, potresti voler invecchiare versioni antiche dal tuo CDN.

Il server dovrà onorare richieste corrispondenti ai file di configurazione recenti di K, dove K è almeno 2. Le richieste del client dovrebbero descrivere il file di configurazione in uso dal client in modo che il server possa verificare che sia una richiesta ragionevole.

EDIT: hai aggiunto di recente gli schemi A & B. In (A) si propone di aggiornare il client "stesso file" dai server. Sto suggerendo che le cache intermedie "trasparenti" possono confondere tale disposizione, ed è opportuno occasionalmente dire al cliente un nuovo nome di file di configurazione, in modo che subisca la mancanza della cache e recupererà dal server. In (B) hai ancora meno controllo sugli effetti di memorizzazione nella cache, quindi inventare un nuovo nome di file di configurazione è ancora più importante, per gestire il problema "dati più vecchi da S3" che hai menzionato. La sinossi è semplicemente che pubblichi il contenuto sotto ogni nome di file esattamente una volta, e giri il nome del file quando giri il contenuto. In questo modo puoi evitare approcci più pesanti come il Paxos / ZK. Devi solo premere un nuovo rev all'istante t0, attendere N secondi finché i tuoi server ne hanno una copia, e quindi dopo t0 + N i server sono liberi di inviare il nuovo nome ai client in modo che i client lo usino. Ciò offre coerenza con uno sforzo minimo. In alternativa, si supponga che il bilanciamento del carico esegua l'hash di un determinato client su un singolo server, quindi entro il breve intervallo necessario a tutti i server per ottenere una nuova configurazione, i client comunicheranno solo con un singolo server e quindi saranno banalmente sincronizzati con quel server. / p>     

risposta data 24.11.2017 - 17:27
fonte
2

In primo luogo, le cose facili. Presumo che tu stia utilizzando HTTP per i tuoi endpoint. Esistono intestazioni standardizzate ( ultima modifica , ETag ) per determinare se il client ha la versione più aggiornata di una risorsa e recupera condizionatamente una risorsa solo quando è stato aggiornato. Ti consiglierei di non reinventare la ruota e utilizzare uno di questi meccanismi esistenti per determinare quando la configurazione (una risorsa) è cambiata. Se si desidera poter restituire più versioni della configurazione come suggerito nella risposta di J_H, è possibile creare una risposta che elenchi le versioni disponibili con gli URL di tali risorse di configurazione. In questo schema, non modificherai le configurazioni (in generale), ma aggiungerai di nuove quando necessario e semplicemente aggiornerai la directory. Puoi ancora usare le intestazioni per determinare se la directory è cambiata.

Ora per la parte difficile. Dovresti familiarizzare con il CAP Theorm . Ecco la versione abbreviata: Consistency , Availabilty , Partition Tolerance : puoi avere al massimo due. Molto di quello che stai chiedendo qui è legato a questo.

How do we handle outgoing requests in the moment we receive an update?

Questa domanda, penso, è al centro della domanda a cui devi rispondere. Diciamo che hai un client che recupera la configurazione un minuto prima di aggiornarlo? Che ne dici di un secondo? Che dire di un millisecondo? Se sei d'accordo con un cliente che riceve una risorsa di pochi nanos prima che sia aggiornato, sarebbe importante se avessero ottenuto la vecchia versione mentre era aggiornata? Direi di no e restituisco solo la versione corrente al momento in cui hai iniziato a soddisfare la richiesta.

Hai davvero due opzioni qui, il polling: controllare continuamente la risorsa in base a una pianificazione, o eventi: spingere i messaggi a un client per dire loro che c'è un aggiornamento. Nella mia esperienza, il primo è molto più facile e più robusto rispetto al secondo. E anche quando si preme, ci sarà un certo ritardo che non è possibile controllare tra quando si aggiorna la risorsa viene aggiornata e quando la recuperano. Il risultato è che se il tuo design non può tollerare che il client sia dietro il server per un certo periodo di tempo, è impossibile da implementare.

In definitiva, è necessario determinare per quanto tempo si desidera consentire al client di essere dietro. Quindi prendi quel tempo e dimezzalo per il tuo intervallo di polling come punto di partenza. Se è troppo frequente, potresti voler guardare qualcosa come websocket.

In termini di distribuzione delle configurazioni ai server e ai client con lo stesso mezzo, penso che creerà alcune sfide attorno ai tempi che tocchi. Invece, probabilmente utilizzerei un processo diverso per distribuire la configurazione ai server di quanto non utilizzerei per distribuirlo al client. Mi aspetto che i server abbiano bisogno di informazioni diverse, ma non ho abbastanza dettagli per sapere. Un modo per affrontarlo è distribuire la configurazione a tutti i server tramite un DB distribuito come Zookeeper . Si potrebbe fare in modo che ogni server tenga traccia della versione della configurazione presente nel db distribuito. Una volta aggiornati, lo si distribuisce al CDN e si consente ai client di recuperarlo. Ciò garantirebbe che i tuoi clienti non anticipassero mai i server.

Se sei veramente sicuro di volerlo distribuire ai client e ai server allo stesso modo, un altro approccio sarebbe quello di chiedere a client e server di negoziare la versione della configurazione che useranno. Questo sarebbe simile a come Minecraft gestisce le sue versioni del software client e quale versione (s) il server può supportare. Essenzialmente, il server presenterebbe le versioni che è in grado di supportare e quindi il cliente ne sceglierà una in quel set. In questo caso sembra che tu voglia sempre che sia l'ultimo che entrambi supportano ma non è essenziale.

    
risposta data 27.11.2017 - 19:03
fonte

Leggi altre domande sui tag