System.IO.FileSystemWatcher para monitorear una carpeta de servidor de red - Consideraciones de rendimiento

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

Pregunta

Quiero ver un árbol de carpetas en un servidor de red para ver los cambios. Todos los archivos tienen una extensión específica. Hay alrededor de 200 carpetas en el árbol y alrededor de 1200 archivos con la extensión que estoy viendo.

No puedo escribir un servicio para ejecutar en el servidor (¡fuera de los límites!), por lo que la solución debe ser local para el cliente. La puntualidad no es particularmente importante. Puedo vivir con un minuto o más de retraso en las notificaciones. Estoy pendiente de Crear, Eliminar, Cambiar nombre y Cambios.

¿Usar el .NET System.IO.fileSystemWatcher crearía mucha carga en el servidor?

¿Qué tal 10 observadores separados para reducir la cantidad de carpetas / archivos que se están viendo? (hasta 200 de 700 carpetas, 1200 de 5500 archivos en total) ¿Más tráfico de red en lugar de menos? Mis pensamientos son una reorganización en el servidor para colocar los archivos observados en 1 árbol. Es posible que no siempre tenga esta opción, por lo tanto, el equipo de observadores.

Supongo que la otra solución es una verificación periódica si el FSW crea una carga indebida en el servidor, o si no funciona por muchas razones de tipo SysAdmin.

¿Hay una mejor manera de hacer esto?

¿Fue útil?

Solución

Desde el punto de vista de la carga del servidor, utilizando el IO .FileSystemWatcher para notificaciones de cambio remoto en el escenario que describa es probablemente el método más eficiente posible. Utiliza el FindFirstChangeNotification y ReadDirectoryChangesW Win32 API funciona internamente, lo que a su vez se comunica con el redirector de red de manera optimizada (suponiendo que la red de Windows estándar : si se utiliza un redirector de terceros y no es compatible con la funcionalidad requerida, las cosas no funcionarán en absoluto). El contenedor .NET también utiliza E / S asíncrona y todo lo demás, lo que garantiza aún más la máxima eficiencia.

El único problema con esta solución es que no es muy confiable. Además de tener que lidiar con las conexiones de red que desaparecen temporalmente (lo cual no es un gran problema, ya que IO.FileSystemWatcher disparará un evento de error en este caso que puede manejar), el mecanismo subyacente tiene ciertas limitaciones fundamentales. De la documentación de MSDN para las funciones de la API Win32:

  • ReadDirectoryChangesW falla con ERROR_INVALID_PARAMETER cuando la longitud del búfer es mayor que 64 KB y la aplicación está monitoreando un directorio a través de la red. Esto se debe a una limitación de tamaño de paquete con los protocolos subyacentes para compartir archivos

  • Las notificaciones no se pueden devolver al llamar a FindFirstChangeNotification para un sistema de archivos remoto

En otras palabras: bajo una carga alta (cuando necesitaría un búfer grande) o, lo que es peor, en circunstancias aleatorias no especificadas, es posible que no reciba las notificaciones que espera. Esto es incluso un problema con los observadores locales del sistema de archivos, pero es mucho más un problema en la red. Otra pregunta aquí sobre SO detalla los problemas de confiabilidad inherentes con la API con un poco más de detalle.

Al usar los observadores del sistema de archivos, su aplicación debería poder manejar estas limitaciones. Por ejemplo:

  • Si los archivos que está buscando tienen números de secuencia, almacene el último número de secuencia sobre el que recibió una notificación, para que pueda buscar 'huecos' en notificaciones futuras y procesar los archivos para los que no obtuvo notificado;

  • Al recibir una notificación, siempre realice un análisis completo del directorio. Esto puede sonar muy mal, pero dado que el escaneo se basa en eventos, sigue siendo mucho más eficiente que el sondeo tonto. Además, siempre que mantenga la cantidad total de archivos en un solo directorio, así como la cantidad de directorios para escanear, menos de mil, el impacto de esta operación en el rendimiento debería ser bastante mínimo de todos modos.

Configurar varios oyentes es algo que debe evitar tanto como sea posible: en todo caso, esto hará que las cosas sean menos menos confiables ...

De todos modos, si absolutamente tiene que usar observadores del sistema de archivos, las cosas pueden funcionar bien siempre que conozca las limitaciones y no espere una notificación 1: 1 por cada archivo modificado /creado.

Entonces, si tiene otras opciones (esencialmente, hacer que el proceso de escritura de los archivos le notifique de manera no basada en el sistema de archivos: cualquier método RPC regular será una mejora ...), definitivamente vale la pena considerarlos un punto de vista de fiabilidad.

Otros consejos

He usado los observadores del sistema de archivos de C # varias veces. La primera vez que los usé, tuve problemas para que dejaran de funcionar, principalmente debido al hecho de que estaba procesando los cambios en el hilo que informaba el cambio.

Ahora, sin embargo, simplemente empujo el cambio a una cola y la proceso en otro hilo. Esto parece resolver el problema que tuve originalmente. Para su problema, podría tener varios observadores presionando en la misma cola.

Sin embargo, no he usado esto con su tipo de escala de problema.

En mi experiencia, un FSW no crea un alto tráfico de red. Sin embargo, si hay un problema de rendimiento, su enfoque de usar varios observadores y dividirlo en menos carpetas que se vean parece razonable.

Sin embargo, tuve algunos problemas importantes con FSW en las unidades de red: la eliminación de un archivo siempre generaba el evento de error, nunca el evento eliminado. No encontré una solución, así que ahora evito usar FSW si hay alguna forma de evitarlo ...

El la documentación de MSDN indica que puede usar el componente FileSystemWatcher para ver los cambios del sistema de archivos en una unidad de red .

También indica que el componente de observador escucha las notificaciones de cambio del sistema de archivos en lugar de interrogar periódicamente la unidad de destino en busca de cambios.

En base a eso, la cantidad de tráfico de red depende completamente de cuánto espera que cambie el contenido de esa unidad de red. El componente FSW no se agregará al nivel de tráfico de red.

Watcher parece 100% confiable, solo mire el tamaño del búfer en el objeto observador. He probado miles de actualizaciones de archivos, ninguna perdida.

Recomiendo usar un enfoque de subprocesos múltiples: el activador es el observador de archivos. Puede lanzar un hilo para cada cambio de archivo detectado. El observador puede procesar mucho más rápido con menos posibilidades de desbordamiento. (use hilo asíncrono)

Después de usar System.IO.FileSystemWatcher por algún tiempo. No es lo suficientemente estable como para manejar eventos que llegan demasiado rápido. Para garantizar el 100% de lectura de los archivos. Utilizo métodos de directorio simples para buscar a través de los archivos. Después de leerlo, copie inmediatamente los archivos a otra carpeta. Para aislarlo de los nuevos archivos que se agregan mientras lee los archivos.

El temporizador se usa para leer regularmente la carpeta. Al copiar el archivo ya leído en la carpeta de archivo, esto asegura que no se volverá a leer. La lectura posterior será siempre archivos nuevos.

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

No creo que haya ningún tipo de estado activo o comunicación entre la computadora con el FSW y la computadora cuya ubicación se está monitoreando. En otras palabras, el FSW no está haciendo ping al sistema operativo en red para verificar el archivo.

Uno podría imaginar que un mensaje o evento solo se genera / envía al FSW en red cuando se produce un cambio.

Pero todo esto es solo especulación. :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top