7

Implementazione di un'app Android + Firebase, che ha una relazione molti-a-molti: Utente < -> Widget (i widget possono essere condivisi a più utenti).Firebase Android: "join" lento utilizzando molti listener, sembra contraddire la documentazione

Considerazioni:

  1. Elenco tutti i widget che un utente ha.
  2. Un utente può vedere solo i widget che sono condivisi con lui/lei.
  3. Essere in grado di vedere tutti gli utenti a cui un determinato widget è condiviso.
  4. Un singolo Widget può essere posseduto/amministrato da più Utenti con uguali diritti (modifica il Widget e cambia a chi è condiviso). Simile a come Google Drive condivide con utenti specifici.

Uno degli approcci per implementare il recupero (join-style), sarebbe quello di andare con questo consiglio: https://www.firebase.com/docs/android/guide/structuring-data.html ("Joining Flattened Data"):

// fetch a list of Mary's groups 
ref.child("users/mchen/groups").addChildEventListener(new ChildEventListener() { 
    @Override 
    public void onChildAdded(DataSnapshot snapshot, String previousChildKey) { 
    // for each group, fetch the name and print it 
    String groupKey = snapshot.getKey(); 
    ref.child("groups/" + groupKey + "/name").addListenerForSingleValueEvent(new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot snapshot) { 
     System.out.println("Mary is a member of this group: " + snapshot.getValue()); 
     } 
     @Override 
     public void onCancelled(FirebaseError firebaseError) { 
     // ignore 
     } 
    }); 
    } 
}); 

Sorge quindi la domanda se avere potenzialmente molti ascoltatori avrà un impatto negativo sulle prestazioni o forse colpirà qualche limite.

Ma veniamo rassicurati nel doc:

È davvero giusto per cercare ogni record singolarmente? Sì. Il protocollo Firebase utilizza socket Web e le librerie client eseguono una grande quantità di ottimizzazione interna delle richieste in entrata e in uscita. Fino a quando non entriamo in decine di migliaia di record, questo approccio è perfettamente ragionevole. In effetti, il tempo necessario per scaricare i dati (ad esempio il conteggio dei byte) eclissa qualsiasi altra preoccupazione relativa al sovraccarico della connessione.

Ma, per essere sicuro, ho fatto una piccola applicazione di prova che confronta 2-approcci:

  1. Collegamento molti ValueEventListener -s per tutti i widget one-by-one (come da Firebase del " strutturazione-dati" guida di cui sopra)
  2. Collegamento di un singolo ChildEventListener ad un nodo che ospita tutti i widget (richiede un'adeguata strutturazione di Widgets dell'utente sotto un nodo)

provata su 4 differiscono dispositivi ent e versioni Android (4.x - 5.x). Firebase lib: 'com.firebase:firebase-client-android:2.3.1'.
Nel primo approccio la performance è stata piuttosto deludente. Ho visto costantemente ~ 15-100 eventi/s. La prestazione più bassa, ~ 15 eventi/s stava arrivando abbastanza spesso, quindi sembra che dovrebbe essere presa sul serio. In tal caso, se l'utente avesse 100 widget, sarebbero necessari ~6 secondi per ottenere informazioni su tutti i widget (ad esempio scorrere un elenco). Questo è troppo lento. Con 1000 widget, spesso richiedevano fino a 40 secondi per recuperare le informazioni da ascoltatori separati. Troppo lento.

Nel secondo approccio ho osservato 200-3000 eventi/s. Quindi 15-30 volte più veloce del primo approccio!
Quindi sembra che la sicurezza in Firebase doc [...] Until we get into tens of thousands of records, this approach is perfectly reasonable [...] non sia realmente precisa dato quanto lentamente ha funzionato.

Dato tutto ciò, ho 4 domande correlate.

  1. Qualcuno può confermare/confutare le mie scoperte sulla base della propria esperienza/benchmark? Anche le informazioni su altre piattaforme sono benvenute, in quanto esiste un piano per sviluppare questa app su più piattaforme.
  2. Quale potrebbe essere la ragione di tale drammatica differenza di prestazioni? Strutture dati interne forse?
  3. C'è un modo per migliorare le prestazioni mantenendo il primo approccio (multi-listener)?
  4. L'approccio multi-listener dovrebbe essere abbandonato completamente a favore di un approccio multi-copia denormalizzato che è stato presentato nel tutorial di Firebase + Udacity (https://github.com/udacity/ShoppingListPlusPlus nel nodo "liste utenti" - dove mantengono copie per utente delle informazioni della lista acquisti) ? Chiedo delle implicazioni di questo approccio, in un'altra domanda - Firebase: structuring data via per-user copies? Risk of data corruption?.

Eventuali altri suggerimenti/considerazioni benvenuti. TIA.

+0

Il test qui non è correlativo, dal momento che non è stato isolato il recupero dei dati dal rendering dell'interfaccia utente (suggerimento: riverniciare l'interfaccia utente è probabile che si tratti del problema). La velocità del download è quasi certamente direttamente correlata al numero di byte che vengono recuperati, poiché ciò potrebbe eclissare il sovraccarico dell'attività del socket. Se credi in un altro modo, dovresti confrontare un download diretto e crudo dei dati con la velocità di recupero di ogni record, isolando il processo di download da qualsiasi rendering e utilizzo dei dati. – Kato

+1

Grazie, @Kato. 1. Ho realizzato una versione del test della velocità senza interfaccia utente, solo tempi. Stessi risultati 2. Un altro fattore è che i dati vengono memorizzati nella cache localmente ('Firebase.getDefaultConfig(). SetPersistenceEnabled (true)'), quindi non si tratta solo della larghezza di banda. – KarolDepka

+0

@Kato puoi commentare il mio commento su questo essendo storage-io-speed related (offline)? – KarolDepka

risposta

0

"This prompts the question whether having potentially many listeners will have a negative impact on performance or perhaps would hit some hard limit."

la risposta è la stessa per Firebase Realtime database come lo è per la nuova Cloud Firestore database.

Non importa quante connessioni hai o quanti listener hai, è importante quanti dati stai elaborando sul lato client.

Quindi se hai 100 ascoltatori, ascoltando 100 bit di piccoli dati, è diventato piuttosto economico ma se ognuno di questi ascoltatori sta ascoltando un flusso di dati in continua evoluzione, è diventato molto costoso per il cliente per affrontarlo molto velocemente.

E poiché i dispositivi mobili sono molto diversi è molto difficile sapere quanti ne siano troppi. Quindi, se ti rivolgi agli utenti americani che tendono ad avere telefoni di fascia alta, questo sarà un limite diverso se puntiamo a paesi con telefoni che hanno una potenza molto inferiore.

Così puoi avere quanti ascoltatori vuoi, se li stai rimuovendo di conseguenza al ciclo di vita dell'attività, come spiegato here.

C'è anche un altro approccio, per usare uno addListenerForSingleValueEvent. In questo caso, non è necessario rimuovere un listener.

Problemi correlati