2014-09-18 15 views
16

Ho una webapp java piuttosto pesante che serve migliaia di richieste/sec e utilizza un DB Postgresql master che si replica su un database secondario (di sola lettura) utilizzando la replica streaming (asincrona).Lettura/scrittura suddivisione Hibernate

Quindi, separo la richiesta da primaria a secondaria (sola lettura) utilizzando URL per evitare chiamate di sola lettura al database primario di bug considerando che il tempo di replica è minimo.

NOTA: Io uso una sessionFactory con un RoutingDataSource fornito da molla che guarda in alto db da utilizzare in base un tasto. Sono interessato alla multitenancy perché sto utilizzando ibernazione 4.3.4 che lo supporta.

Ho due domande:

  1. non penso splitting sulla base degli URL è efficiente come posso muovere solo il 10% del traffico intorno significa che non ci sono molti di sola lettura URL . Quale approccio dovrei prendere in considerazione?
  2. Potrebbe essere, in qualche modo, sulla base degli URL che raggiungo un certo livello di distribuzione tra i due nodi ma cosa farei con i miei lavori al quarzo (che hanno anche JVM separata)? Quale approccio pragmatico dovrei assumere ?

So che potrei non ottenere una risposta perfetta qui in quanto questo è davvero ampio, ma voglio solo la tua opinione per il contesto.

Dudes ho nel mio team:

  • Spring4
  • Hibernate4
  • Quartz2.2
  • Java7/Tomcat7

Si prega di prendere interesse. Grazie in anticipo.

+0

Avrei due unità di persistenza: una per sola lettura e una per lettura-scrittura, lavoro. La sola lettura potrebbe indicare un PgBouncer che esegue il backup su più repliche di PostgreSQL. Quindi sceglierei quale utilizzare in base al particolare metodo richiamato sui miei oggetti di astrazione di accesso ai dati e altri contesti pertinenti. Bisogna pensare molto attentamente alla coerenza logica se si fa questo, ed evitare cicli di lettura/modifica/scrittura. –

+0

** Il tracciamento utente ** è un'area che può essere ottimizzata, se non già eseguita: separazione nelle tabelle R/O + R + W, cache di sessione, scritta. ** Le tabelle di archiviazione ** che ricevono solo nuovi record, ma i record sono immutabili, possono essere divisi in R/O e R + W, eventualmente con trigger DB. –

risposta

1

Stai dicendo che l'URL dell'applicazione è solo del 10% in lettura, quindi l'altro 90% ha almeno una qualche forma di scrittura del database.

10% LEGGERE

È possibile pensare di utilizzare un CQRS design che può migliorare il database di leggere le prestazioni. Può certamente leggere dal database secondario ed essere reso più efficiente progettando le query e i modelli di dominio specificatamente per il livello di lettura/visualizzazione.

Non hai detto se le richieste% 10 sono costosi o meno (ad esempio, i rapporti in esecuzione)

io preferirei usare un sessionFactory separato se si dovesse seguire la progettazione CQRS come gli oggetti corso di caricamento/cache molto probabilmente saranno diversi da quelli scritti.

90% WRITE

Per quanto riguarda il restante 90% va, non si vuole leggere dal database secondario (durante la scrittura sul primario) durante una certa logica di scrittura, come non si vuole potenzialmente dati obsoleti coinvolti.

Alcune di queste letture potrebbero cercare dati "statici". Se la cache di Hibernate non riduce gli accessi al database per le letture, prenderei in considerazione una cache di memoria come Memcached o Redis per questo tipo di dati. Questa stessa cache potrebbe essere utilizzata da entrambi i processi di scrittura 10% e lettura del 90%.

Per le letture che non sono statiche (ovvero i dati di lettura che sono stati scritti di recente) Hibernate deve contenere i dati nella sua cache degli oggetti se è 'dimensionato in modo appropriato. Riesci a determinare la tua performance hit/miss cache?

QUARZO

Se si sa per certo che un lavoro pianificato non avrà un impatto lo stesso insieme di dati come un altro lavoro, si poteva eseguirli contro diverse banche dati, tuttavia in caso di dubbio eseguire sempre gli aggiornamenti batch per un server (primario) e la replica cambiano. È meglio essere logicamente corretti, piuttosto che introdurre problemi di replica.

DB PARTITIONING

Se le 1.000 richieste al secondo stanno scrivendo un sacco di dati, guarda partitioning database. Potresti scoprire di avere tavoli in continua crescita. Il partizionamento è un modo per affrontarlo senza archiviare i dati.

A volte è necessario poco o nessun cambiamento al codice dell'applicazione.

L'archiviazione è ovviamente un'altra opzione

Note legali: Ogni domanda come questa è sempre sarà specifica applicazione. Cerca sempre di mantenere la tua architettura il più semplice possibile.

4

si dovrebbe avere:

  1. un DataSource configurato per connettersi al nodo master
  2. un DataSource configurato per connettersi al nodo slave
  3. il DataSource di routing sta di fronte a questi due, essendo quello utilizzato da SessionFactory.
  4. è possibile utilizzare il flag @Transactional (readOnly = true) per assicurarsi di instradare le transazioni di sola lettura alloSourceSource slave.
  5. Sia il master che lo slave DataSource richiedono un meccanismo di connessione e il più veloce è sicuramente HikariCP. HikariCP è così veloce che su one test of mine ho ottenuto un tempo medio di connessione 100us.
  6. È necessario assicurarsi di impostare le dimensioni corrette per i pool di connessione, poiché ciò può fare un'enorme differenza. Per questo consiglio di usare flexy-pool. Potete trovare di più su di esso here e here.
  7. È necessario essere molto diligenti e assicurarsi di contrassegnare tutte le transazioni di sola lettura di conseguenza. È insolito che solo il 10% delle transazioni sia di sola lettura.È possibile che tu abbia un'applicazione di tipo "write-most" o tu stia utilizzando transazioni di scrittura in cui emetti solo dichiarazioni di query?
  8. Monitora tutte le esecuzioni delle query utilizzando uno SQL logging framework. Più breve è l'esecuzione della query, più breve è il tempo di acquisizione del blocco, maggiore è il numero di transazioni al secondo che il tuo sistema accetterà.
  9. Per batch processing è sicuramente necessario eseguire la maggior parte delle transazioni, ma OLTP in generale e Hibernate in particolare non sono la soluzione migliore per OLAP. Se si decide di utilizzare Hibernate per i lavori di quarzo assicurarsi enable JDBC batching e si dovrebbe avere queste proprietà Hibernate impostate:

    <property name="hibernate.order_updates" value="true"/> 
    <property name="hibernate.order_inserts" value="true"/> 
    <property name="hibernate.jdbc.batch_versioned_data" value="true"/> 
    <property name="hibernate.jdbc.fetch_size" value="25"/> 
    <property name="hibernate.jdbc.batch_size" value="25"/> 
    

per il dosaggio è possibile utilizzare una fonte di dati separato che utilizza un pool di connessioni diversa (e perché hai già detto di avere una JVM diversa, ecco cosa hai già). Assicurati solo che le dimensioni totali della connessione di tutti i pool di connessioni siano inferiori al numero di connessioni con cui PostgreSQL è stato configurato.

Quindi il processore batch utilizza una HikariCPDataSource separata che si collega al master. Ogni processo batch deve utilizzare una transazione dedicata, quindi assicurati di utilizzare una dimensione batch ragionevole. Vuoi tenere serrature e completare le transazioni il più velocemente possibile. Se il processore batch sta utilizzando worker di elaborazione simultanea, assicurarsi che la dimensione del pool di connessione associata sia uguale al numero di worker, in modo che non attenda che altri rilascino le connessioni.

0

Se ho capito correttamente, il 90% delle richieste HTTP per la tua webapp coinvolgono almeno una scrittura e devono operare sul database master. È possibile indirizzare solo le transazioni di sola lettura al database di copia, ma il miglioramento riguarderà solo il 10% delle operazioni di database globali e anche quelle di sola lettura colpiranno un database.

L'architettura comune qui consiste nell'utilizzare una buona cache di database (Infinispan o Ehcache). Se è possibile offrire una cache sufficientemente grande, si può sperare che una buona parte del database legga solo la cache e diventi solo operazioni di memoria, essendo parte di una transazione di sola lettura o meno. La regolazione della cache è un'operazione delicata, ma IMHO è necessario per ottenere un guadagno elevato. Quella cache consente anche i front-end distribuiti anche se la configurazione è un po 'più difficile in quel caso (potrebbe essere necessario cercare i cluster di Terracotta se si desidera utilizzare Ehcache).

Attualmente, la replica del database viene principalmente utilizzata per proteggere i dati e viene utilizzata come meccanismo di miglioramento della concorrenza solo se si dispone di parti elevate dei sistemi informativi che leggono solo i dati e non è ciò che si sta descrivendo.