Pianificazione di attività parallele con I / O (soluzione di backup)

2

Voglio implementare una soluzione di backup in Python in cui un server di backup avvia backup su un numero di server virtuali e fisici (un server = un'attività di backup). Ignorando i dettagli delle attività di backup effettive, mi occupo della parte di pianificazione / multiprocessing per ora.

I vincoli che ho sono:

  1. Esegui il backup di due server contemporaneamente (ad esempio al massimo due thread di backup eseguiti contemporaneamente)
  2. Non eseguire il backup di due server sulla stessa macchina fisica (spesso più server virtuali condividono una macchina hardware comune) contemporaneamente.

Dato che non ho molta esperienza in multiprocessing in Python mi chiedo quale sarebbe una soluzione Python ottimale. Mi è venuto in mente il seguente:

  • Avere un thread per ogni processo di backup (ad esempio per ciascun server) e utilizzare un threading.BoundedSemaphore per assicurarsi che solo due siano in esecuzione contemporaneamente. Utilizzare più semafori / condizioni per garantire che più thread non stiano supportando due server sulla stessa macchina fisica.
  • Hanno esattamente due thread che sono in esecuzione tutto il tempo e recuperano le loro attività da una coda. Contemporaneamente la coda dovrebbe assicurarsi che nessuna attività sulla stessa macchina fisica venga distribuita contemporaneamente (ad esempio saltando / riordinando le attività a volte). Probabilmente lo fare sottoclasse Queue.PriorityQueue per aggiungere i vincoli aggiuntivi.

Mi sto appoggiando alla seconda opzione, ma non sono sicuro che una coda sia la giusta struttura dati per distribuire le attività a più thread di lavoro. Non ho bisogno di aggiungere attività alla coda in fase di esecuzione (che una coda consente) e ho bisogno di un po 'di logica per distribuire le attività piuttosto che elaborarle in un ordine lineare. C'è una struttura dati migliore (standard) per questo?

Sarei grato di ascoltare alcuni pensieri dei programmatori più esperti.

    
posta Simon Fromme 11.01.2017 - 15:54
fonte

2 risposte

2

Avrei una coda per macchina fisica.

Pertanto, un processo di backup richiederebbe al massimo N = 2 attività e si assicurerà che non prelevi un'attività da una coda per la quale un'altra attività è già in esecuzione.

(N potrebbe essere facilmente regolato quando necessario.)

    
risposta data 12.01.2017 - 17:53
fonte
1

Per rendere la tua vita molto più facile, e con molto meno codice boilerplate, ti suggerisco di dare un'occhiata a Advanced Python Scheduler

È molto facile iniziare a lavorare e ti farà risparmiare tempo e problemi nella gestione di code, thread e pianificazione.

Può essere eseguito in multiprocesso o in modalità threading. è possibile limitare il numero di attività eseguite contemporaneamente mediante una semplice configurazione. vedi esempi qui

Diventa ancora migliore, non eseguirà di nuovo la stessa attività se già l'attività precedente è ancora in esecuzione, essa rimarrà in attesa impostando max_instances: 1 .
se hai bisogno di uno stato, puoi utilizzare il jobstore per rendere persistenti le tue attività.

esempio di codice:

from pytz import utc

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.mongodb import MongoDBJobStore
from apscheduler.jobstores.redis import RedisJobStore
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor


jobstores = {
    'mongo': MongoDBJobStore(),
    'redis' : RedisJobStore(),
    'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
executors = {
    'default': ThreadPoolExecutor(20),
    'processpool': ProcessPoolExecutor(5)
}
job_defaults = {
    'coalesce': False,
    'max_instances': 3
}
scheduler = BackgroundScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)  

def backup_job(**kwargs):
    print('doing backup stuff')


scheduler.add_job(backup_job, 'interval', seconds=600, jobstore='redis'
                  id=1, name='backup', kwargs={'key':'value'})

spero che aiuti

    
risposta data 12.01.2017 - 12:13
fonte

Leggi altre domande sui tag