Un endpoint separato specifico per la sincronizzazione in una API REST

3

Sto lavorando su un'app multi client / server singolo. La comunicazione tra i due avviene tramite RESTful API. Esistono diverse risorse che devono rimanere sincronizzate su tutti i client, comprese le immagini acquisite da fotocamera, i Mi piace e i commenti su queste immagini, i profili utente e i seguaci / i seguaci degli utenti. Il mio approccio attuale riguarda GET tutte le risorse modificate sul server dall'ultima sincronizzazione, come GET /images?since=<last-sync-timestamp> , GET /users/:id/followers?since=<last-sync-timestamp> ecc. E POST tutte le modifiche client dall'ultima sincronizzazione agli stessi endpoint, come POST /images , POST /user/:id/followers

Lo svantaggio principale di questo approccio è troppe chiamate di rete - Per ogni risorsa che ho bisogno di sincronizzare, ho bisogno di eseguire almeno 2 chiamate di rete.

Quindi sto pensando di introdurre un nuovo endpoint come /sync che fornisce tutte le risorse sincronizzabili che sono state modificate dall'ultimo timestamp di sincronizzazione. Sia il client che il server dovranno analizzare il JSON e inserire i rispettivi dati nelle tabelle appropriate, ma ora, non importa quante risorse devo sincronizzare, ho solo bisogno di eseguire due chiamate di rete, ma cambiare la struttura del JSON come le ripetizioni vengono aggiunte / rimosse.

Qualche idea sul perché il secondo approccio è superiore / inferiore al primo?

    
posta iTwenty 02.12.2014 - 07:20
fonte

5 risposte

1

In REST, dovresti pensare agli URI come a identificare una risorsa indirizzabile. Quindi, se pensi a una "sincronizzazione" come nome;) puoi definire quella risorsa in qualsiasi modo si adatti alle tue esigenze.

A livello di superficie, in REST parliamo di risorse di raccolta (come la raccolta di utenti) e di risorse individuali (come un singolo utente), quindi una risorsa che è un aggregato di altre risorse è in linea con quella.

L'idea di "una risorsa" è estremamente ampia. Non so se esiste una definizione precisa. Quindi una risorsa aggregata che raggruppa le risorse più piccole consente di risparmiare larghezza di banda e riduce i suoni di latenza come una buona idea.

    
risposta data 02.12.2014 - 07:39
fonte
1

Il secondo approccio è un'idea cattiva / inferiore.

  • Si perde la possibilità di memorizzare nella cache singole risorse utilizzando metodi di memorizzazione nella cache standard (sia sul server che sul client).
  • Perderai la possibilità di sincronizzare lo stato delle singole risorse utilizzando intestazioni e timestamp HTTP
  • Perdi la possibilità di aggiornare le risorse man mano che vai (perché aspettare per inviare una modifica al server, basta spingerlo quando l'utente è pronto a spingerlo)
  • Avrai un catch di tutto il tipo di contenuto per ogni singola risorsa che hai, piuttosto che uno per ogni tipo di risorsa (cioè il tuo JSON dovrà incorporare tutti i tipi di dati
  • Il tuo cliente sarà troppo complesso, invece di gestire la modifica di una risorsa e spingerlo al server deve gestire la risorsa di sincronizzazione.

Tutto per evitare di effettuare chiamate di rete più piccole. Se si utilizzano le intestazioni HTTP e la compressione gzip, queste chiamate dovrebbero essere piccole o minuscole, quindi qual è il problema? Guadagni molto di più di quello che perdi.

    
risposta data 08.12.2014 - 17:42
fonte
1

Quanta differenza nelle prestazioni delle applicazioni o nel sovraccarico del server sta avendo una chiamata di rete piuttosto che due per aggiornamento? Bene, dipende da quanti client simultanei ti aspetti e quanto spesso invieranno i sondaggi per gli aggiornamenti. Se hai un "piccolo numero di client" come 10 o 50 e richiedono aggiornamenti ogni N secondi (diciamo N tra 10 e 120), puoi fare i conti e scoprire che non si tratta di un carico di rete o di server sostanziale, quindi tu? Probabilmente stai sprecando il tuo tempo per ottimizzarlo.

D'altra parte, se avessi 100s, 1Ks o 1Ms di client simultanei e / o richiedano aggiornamenti ogni secondo o alcuni secondi, e / o non hai solo due tipi di oggetti da comunicare ma M & gt ; 2, con tutti i mezzi fare tutto il possibile per ottimizzare le interazioni.

Questo lascia ancora aperta una domanda chiave: l'aggiunta di un nuovo endpoint mega-REST ( /sync ) è davvero il modo migliore per farlo?

Forse no. Cormac Mulhall ha delineato alcuni aspetti negativi . Un problema più sottile è che la sincronizzazione è fondamentalmente difficile . Sembra non così difficile, ma molti negozi hanno ripetutamente rotto le loro scelte su di esso.

Perché la sincronizzazione è difficile? Bene, cerchiamo di graffiare quella superficie. Si menzionano gli URL che specificano ?since=<last-sync-timestamp> . È il timestamp del server o del client? Saranno diversi . Il cronometraggio distribuito è di per sé difficile. Gli orologi variano. Puoi aiutarlo aggiungendo un'altra chiamata di riposo /time che aiuta il cliente a stimare quanto il suo orologio è lontano dall'orologio del server. Ma ora hai la complessità della stima della deriva temporale, proprio come all'interno di Network Time Protocol . REST non è più così semplice. E che cosa significa un timestamp, comunque? ?since=1418070480 significa ...? È l'inizio di quel secondo, o la fine? Tieni presente che le CPU possono eseguire ~ 10 ** 11 istruzioni al secondo. I secondi sono una metrica grezza. Quindi tu dici: "Sai una cosa? Ci sarà un errore, quindi mi limiterò a mettere un margine di errore". Si coordinano gli orologi nel miglior modo possibile, quindi si aggiungono altri 20 o 30 o 60 secondi indietro, solo per catturare i ritardatari. Ora pensi di aver leccato il problema degli "aggiornamenti accidentalmente mancanti" - non lo hai davvero, in un sistema di qualsiasi complessità, ma facciamo solo finta. Ma hai creato un altro problema: la possibilità di duplicazione, perché stai chiedendo un altro N secondi di dati prima di dove pensi davvero di averne bisogno. Dovrai creare un codice lato client per assicurarti che gli oggetti non vengano pubblicati due volte. Il REST doveva essere semplice!

Anche con tutto questo, non hai affrontato l'elefante nella stanza: hai ancora un aggiornamento in stile sondaggio, in cui i clienti devono continuamente chiedere, chiedere e chiedere nuovamente: "Nulla di nuovo? No? Okay Che ne dici di adesso? No? Ok. E adesso? No? Okay ... "Il tuo server continua a essere colpito da richieste inutili. 90% del quale risponderà sempre "Niente di nuovo da segnalare."

La verità è che non hai ancora uno stile di comunicazione che sia anche a metà strada adatto ai requisiti di sincronizzazione. Il polling sarà sempre una chiacchierata, tecnica di caricamento del server. Quello di cui hai veramente bisogno non è AJAX o AJAJ aggiorna i sondaggi, ma al minimo Cometa (chiamate AJAX inverse a lungo polling) - o meglio ancora, un meccanismo di comunicazione avanti e indietro completo come WebSockets . Questi permettono al tuo codice lato server di stabilire tecniche push o interazioni push-pull che, pur non correggendo automagicamente tutte le semantiche difficoltà di sincronizzazione in un mondo distribuito, ridurre sostanzialmente la chiamata di rete, l'overhead del server e la complessità del codice necessaria per avere endpoint realmente sincronizzati.

In sintesi, un mega endpoint piuttosto che due singoli è un problema minore. Se vuoi una sincronizzazione temporale efficiente, il vero problema è che hai bisogno di un meccanismo di interazione migliore.

    
risposta data 08.12.2014 - 21:55
fonte
0

Offrire richieste più piccole e più numerose non dovrebbe comportare un rischio così elevato per il server, a meno che non si lasci la sincronizzazione come evento attivato dall'utente.

Vedi, quando lasci la sincronizzazione all'utente, sarà sempre pesante, indipendentemente dal fatto che le richieste siano piccole ma molte, o poche, ma grandi, sei sempre a rischio di avere troppo traffico di rete per handle: gli utenti tendono a premere il pulsante di aggiornamento molto più del necessario, soprattutto se l'app sembra rallentare o non rispondere all'evento di aggiornamento (il che significa che, non appena si verifica un carico pesante, diventerà ancora più pesante).

Ma ci sono altri modi. E non intendo dirti di inserire un timer nella tua app e di eseguire il polling delle modifiche ogni x secondi. Voglio dire, usare qualcosa di veramente efficiente, come le notifiche push.

Le notifiche push possono essere utilizzate per comunicare all'app client che vi sono modifiche da sincronizzare e, opzionalmente, quali risorse esatte devono essere sincronizzate. Questa tecnica è chiamata send-to-sync .

Con send-to-sync, quando qualcosa viene modificato nel server (ricevendo un'operazione POST / PUT), è possibile fare in modo che il server notifichi a tutti i client obsoleti che devono sincronizzarsi con quella modifica. Puoi anche eliminare il timestamp delle tue richieste e lasciare le cose il più semplici possibile in termini di risorse REST, ed inoltre evitare completamente di dover tener conto delle differenze di orario nei vari dispositivi.

    
risposta data 08.12.2014 - 23:31
fonte
0

Ecco come lo facciamo, non sono sicuro che sia buono o cattivo, ma funziona così bene.

Anch'io ho un endpoint dedicato per la sincronizzazione

/sync/{syncKey}

Non appena l'utente si autentica, se il client dell'utente (app mobili) desidera avere la sincronizzazione può chiamare l'API di aggiunta alla sincronizzazione, io memorizzo una voce per dispositivo per utente e restituisco la chiave di accesso come chiave di sincronizzazione

Quindi ogni volta che si verificano cambiamenti su qualsiasi risorsa per quell'utente, aggiungo la chiave dell'entità (solo la chiave primaria) a tutte le voci di sincronizzazione dei dispositivi per quell'utente (supporta tutte le operazioni CRUD)

Quindi il client chiama l'API get sync utilizzando la chiave di sincronizzazione per recuperare la voce di sincronizzazione, se è presente una chiave per qualsiasi risorsa, il client effettuerà una chiamata API separata per ogni risorsa utilizzando la chiave della risorsa e apporterà le modifiche appropriate alla fine e infine inviare una chiara API chiamate di sincronizzazione per rimuovere le chiavi sincronizzate da db

Quando l'utente si disconnette, il client invierà la richiesta di cancellazione per rimuovere completamente la voce di sincronizzazione

    
risposta data 01.03.2015 - 20:54
fonte

Leggi altre domande sui tag