System.IO.FileSystemWatcher per monitorare una cartella del server di rete - Considerazioni sulle prestazioni

StackOverflow https://stackoverflow.com/questions/151804

Domanda

Voglio guardare un albero delle cartelle su un server di rete per le modifiche. Tutti i file hanno un'estensione specifica. Ci sono circa 200 cartelle nell'albero e circa 1200 file con l'estensione che sto guardando.

Non riesco a scrivere un servizio da eseguire sul server (off-limits!), quindi la soluzione deve essere locale per il client. La tempestività non è particolarmente importante. Posso vivere con un minuto o più di ritardo nelle notifiche. Sto guardando per creare, eliminare, rinominare e modifiche.

L'uso di .NET System.IO.fileSystemWatcher creerebbe molto carico sul server?

Che ne dici di 10 osservatori separati per ridurre il numero di cartelle / file che si stanno guardando? (fino a 200 da 700 cartelle, 1200 da 5500 file in totale) Più traffico di rete invece di meno? I miei pensieri sono un rimpasto sul server per mettere i file guardati sotto un albero. Potrei non avere sempre questa opzione, quindi il team di osservatori.

Suppongo che l'altra soluzione sia un controllo periodico se FSW crea un carico eccessivo sul server o se non funziona per un sacco di motivi di tipo SysAdmin.

C'è un modo migliore per farlo?

È stato utile?

Soluzione

Dal punto di vista del carico del server, usando IO .FileSystemWatcher per le notifiche di modifica remota nello scenario che descrivi è probabilmente il metodo più efficiente possibile. Utilizza FindFirstChangeNotification e ReadDirectoryChangesW Le funzioni API Win32 internamente, che a loro volta comunicano con il redirector di rete in modo ottimizzato (assumendo una rete Windows standard : se viene utilizzato un redirector di terze parti e non supporta la funzionalità richiesta, le cose non funzioneranno affatto). Il wrapper .NET utilizza anche l'I / O asincrono e tutto il resto, garantendo ulteriormente la massima efficienza.

L'unico problema con questa soluzione è che non è molto affidabile. Oltre a dover gestire temporaneamente le connessioni di rete (il che non è un grosso problema, poiché IO.FileSystemWatcher genererà un evento di errore in questo caso che è possibile gestire), il meccanismo sottostante presenta alcune limitazioni fondamentali. Dalla documentazione MSDN per le funzioni dell'API Win32:

  • ReadDirectoryChangesW non riesce con ERROR_INVALID_PARAMETER quando la lunghezza del buffer è maggiore di 64 KB e l'applicazione sta monitorando una directory sulla rete. Ciò è dovuto a una limitazione della dimensione dei pacchetti con i protocolli di condivisione file sottostanti

  • Le notifiche non possono essere restituite quando si chiama FindFirstChangeNotification per un file system remoto

In altre parole: sotto carico elevato (quando sarebbe necessario un buffer di grandi dimensioni) o, peggio ancora, in circostanze casuali non specificate, potresti non ricevere le notifiche che ti aspetti. Questo è persino un problema con gli osservatori di file system locali, ma è molto più un problema sulla rete. Un'altra domanda qui su SO descrive in dettaglio i problemi di affidabilità intrinseca con l'API.

Quando si usano i watcher del file system, l'applicazione dovrebbe essere in grado di gestire queste limitazioni. Ad esempio:

  • Se i file che stai cercando hanno numeri di sequenza, archivia l'ultimo numero di sequenza di cui sei stato avvisato, in modo da poter cercare "spazi vuoti" nelle notifiche future ed elaborare i file per i quali non hai ricevuto notificato;

  • Alla ricezione di una notifica, eseguire sempre una scansione completa della directory. Questo può sembrare davvero negativo, ma poiché la scansione è guidata dagli eventi, è ancora molto più efficiente del polling stupido. Inoltre, purché si mantenga il numero totale di file in una singola directory, nonché il numero di directory da scansionare, meno di un migliaio di volte, l'impatto di questa operazione sulle prestazioni dovrebbe essere comunque minimo.

Configurare più ascoltatori è qualcosa che dovresti evitare il più possibile: semmai, questo renderà le cose ancora meno affidabili ...

Comunque, se assolutamente devi usare i watcher del file system, le cose possono funzionare bene fintanto che sei a conoscenza delle limitazioni e non aspettarti una notifica 1: 1 per ogni file modificato /creato.

Quindi, se hai altre opzioni (essenzialmente, il processo di scrittura dei file ti avvisa in un modo non basato su file system: qualsiasi metodo RPC normale sarà un miglioramento ...), vale sicuramente la pena esaminare da un punto di vista dell'affidabilità.

Altri suggerimenti

Ho usato i watcher del file system da C # diverse volte. La prima volta che li ho usati, ho avuto problemi a smettere di funzionare, principalmente a causa del fatto che stavo elaborando le modifiche nel thread che ha segnalato la modifica.

Ora, tuttavia, inserisco la modifica in una coda ed elaboro la coda su un altro thread. Questo sembra risolvere il problema che avevo originariamente. Per il tuo problema, potresti avere più osservatori che spingono sulla stessa coda.

Tuttavia, non l'ho usato con il tuo tipo di scala di problemi.

Nella mia esperienza, un FSW non crea traffico di rete elevato. Tuttavia, se si verifica un problema di prestazioni, l'approccio dell'utilizzo di più watcher e la suddivisione in un numero inferiore di cartelle visualizzate sembra ragionevole.

Ho avuto alcuni grossi problemi con FSW sulle unità di rete, tuttavia: l'eliminazione di un file ha sempre generato l'evento di errore, mai l'evento eliminato. Non ho trovato una soluzione, quindi ora evito di usare FSW se c'è un modo per aggirare ...

La la documentazione MSDN indica che è possibile utilizzare il componente FileSystemWatcher per controllare le modifiche al file system su una unità di rete.

Indica anche che il componente watcher ascolta le notifiche di modifica del file system anziché interrogare periodicamente l'unità di destinazione per le modifiche.

In base a ciò, la quantità di traffico di rete dipende interamente da quanto ci si aspetta che il contenuto di tale unità di rete cambi. Il componente FSW non si aggiungerà al livello del traffico di rete.

Watcher sembra affidabile al 100%: basta guardare la dimensione del buffer sull'oggetto watcher. Ho testato migliaia di aggiornamenti di file, nessuno perso.

Consiglio di usare un approccio multi-thread - Il trigger è il file watcher. Può lanciare un thread per ogni cambiamento di file rilevato. L'osservatore può elaborare molto più velocemente con meno possibilità di overflow. (usa il thread Async)

Dopo aver usato System.IO.FileSystemWatcher per qualche tempo. Non è abbastanza stabile per gestire eventi che arrivano troppo velocemente. Per garantire la lettura al 100% dei file. Uso semplici metodi di directory per cercare tra i file. Dopo averlo letto, copia immediatamente i file in un'altra cartella. Per isolarlo dai nuovi file aggiunti durante la lettura dei file.

Il timer viene utilizzato per leggere regolarmente la cartella. Copiando il file già letto nella cartella di archiviazione, questo assicura che non verrà letto di nuovo. La lettura successiva sarà sempre nuovi file.

var fileNames = Directory.GetFiles(srcFolder);
foreach (string fileName in fileNames)
{
   string[] lines = File.ReadAllLines(fileName);
}

Non credo ci sia alcun tipo di stato attivo o comunicazione tra il computer con l'FSW e il computer la cui posizione viene monitorata. In altre parole, FSW non esegue il ping del sistema operativo in rete per verificare il file.

Si potrebbe immaginare che un messaggio o un evento venga solo sollevato / inviato all'FSW in rete quando si verifica una modifica.

Ma questa è solo una speculazione. :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top