2015-11-26 25 views
16

Sto lavorando su un'API REST per un servizio Web utilizzando Pyramid e Cornice; i dati sul lato server vengono gestiti utilizzando SQLAlchemy e MySQL. Il server Web è nginx utilizzando uwsgi, ed è configurato per l'esecuzione più processi Python:API REST Pyramid: come posso gestire in modo sicuro l'accesso simultaneo ai dati?

[uwsgi] 
socket = localhost:6542 
plugins = python34 
... 
processes = 2 # spawn the specified number of workers/processes 
threads = 2 # run each worker in prethreaded mode with the specified number of threads 

Problema

Supponiamo che un tavolo customers sul lato server. Utilizzando l'API è possibile leggere i dati dei clienti, modificarli o eliminarli. In aggiunta a ciò ci sono altre funzioni API che leggono i dati dei clienti.

ho potuto emettere chiamate API multipli contemporaneamente che poi competono per la stessa risorsa cliente:

# Write/modify the customer {id} data 
curl --request POST ... https://some.host/api/customer/{id} 
# Delete customer {id} and all of its associated data 
curl --request DELETE https://some.host/api/customer/{id} 
# Perform some function which reads customer {id} 
curl --request GET ... https://some.host/api/do-work 

Essenzialmente questo è un Readers-Writers Problem, ma perché più di un processo è coinvolto, la sincronizzazione tradizionale filo utilizzando locks/mutexes/semaphores non funzionerà qui.

Domanda

Vorrei capire il modo migliore per attuare il bloccaggio e sincronizzazione per tale API web basato piramide, tale che le chiamate simultanee, come nell'esempio di cui sopra sono gestite in modo sicuro ed efficiente (cioè senza serializzazione non necessaria).

Solutions (?)

  • Non credo abbia senso per marcare/bandiera cliente {id} come locked perché SQLAlchemy memorizza nella cache tali modifiche, e flush() non sembra sufficiente atomica in questo contesto?
  • This article descrive l'utilizzo di HTTP ETag per gestire le risorse condivise.
  • Uno potrebbe anche utilizzare Redis come distributed lock manager per uno spinlock per avvolgere una funzione di visualizzazione?
  • E a proposito di Pyramid transaction manager?

risposta

3

Di solito si inizia a determinare quale tipo di consistency model è accettabile. Più sono deboli le tue esigenze di coerenza, più facile diventa questo problema sul lato server.

Ad esempio:

E 'possibile farla franca concorrenza ottimistica? Cioè supponi di avere il blocco, eseguire l'operazione, ma rilevare quando c'è una situazione di concorrenza in modo da poter recuperare correttamente? Questa può essere una buona opzione se non ti aspetti molta collisione. Sqlalchemy dovrebbe essere in grado di rilevare che sta aggiornando una riga che è già stata modificata, ad esempio.

Se ciò non è accettabile, è possibile utilizzare distributed locking in redis. Probabilmente potresti usarlo per ottenere qualche forma di sincronizzazione.

+0

Grazie! WRT SQLAlchemy, [questa risposta] (http://stackoverflow.com/questions/21653319/sqlalchemy-concurrency-update-issue#21695216) sembra essere una soluzione praticabile. Basta trovare un modo per integrarlo con la gestione della sessione di Pyramid. – Jens

12

Suppongo che abbia a che fare con un database MySQL e che i blocchi non debbano coprire altre risorse (Redis, API di terze parti, ecc.).Suppongo inoltre che le funzioni lato client non debbano necessariamente lavorare sui dati delle transazioni (mantenere una sessione su più chiamate API), ma solo impedire che l'accesso simultaneo all'API danneggi il database.

Esistono due tipi di blocco, blocco pessimistico e blocco ottimistico.

Il blocco pessimistico è ciò che la maggior parte delle persone normalmente conosce bloccando: si creano e si acquisiscono i blocchi in anticipo, a livello di codice in codice. Questo è ciò che è il gestore del blocco distribuito.

Il blocco ottimistico è quello che si può facilmente ottenere con i database SQL. Se due transazioni competono con la stessa risorsa, il database danneggia effettivamente una delle transazioni e il framework dell'applicazione (in questo caso Pyramid + pyramid_tm) può riprovare la transazione N volte prima di rinunciare.

Il blocco ottimistico è la soluzione più ideale dal punto di vista dello sviluppo, in quanto non attribuisce alcun carico cognitivo allo sviluppatore dell'applicazione per ricordare di bloccare correttamente le risorse o creare meccanismi di blocco interni. Invece, lo sviluppatore si basa su framework e database per riprovare e gestire situazioni di concorrenza. Tuttavia, il blocco ottimistico non è molto noto tra gli sviluppatori web, perché il blocco ottimistico in ambienti PHP molto diffusi è difficile a causa della mancanza di flessibilità nel linguaggio di programmazione.

pyramid_tm implementa una soluzione di blocco ottimistica e ti consiglierei di usarlo o qualche altra soluzione di blocco ottimistica, a meno che tu non conosca un motivo molto specifico che non vuoi.

  • pyramid_tm legami del ciclo di vita delle transazioni a richiesta HTTP, molto naturale dal punto di vista degli sviluppatori web

  • pyramid_tm possono legare altri eventi per le operazioni di successo, ad esempio, pyramid_mailer invia e-mail agli utenti solo se le transazioni commettono

  • pyramid_tm è ben testato e sulla base ZODB transaction gestore delle transazioni, che è stato in uso di produzione dall'inizio del 2000

  • Assicurarsi che il SQLAlchemy session è impostato su SERIALIZABLE SQL isolation livello - si inizia con il modello di consistenza più alto. Puoi ridurre questo requisito in termini di prestazioni se sai che le chiamate API lo tollerano, ad es. chiama fare analisi statistiche di sola lettura.

  • Il blocco ottimistico di solito ha prestazioni migliori in "normali" molte letture: pochi scrive carichi di lavoro in cui è raro che si verifichi un conflitto (due chiamate API aggiornano lo stesso utente una volta). La penalità per il tentativo di transazione colpisce solo se c'è un conflitto.

  • Se la transazione ha esito negativo dopo N tentativi, ad es. sotto insolita situazione di carico, questo dovrebbe essere risolto dal lato API consumatore dire che i dati lato server è stato modificato e l'utente deve verificare o riempire nuovamente il modulo

Letture