2008-10-20 34 views
5

Parte de mi última aplicación web necesita escribir en el archivo una cantidad justa como parte de su registro. Un problema que he notado es que si hay algunos usuarios simultáneos, las escrituras pueden sobrescribirse entre (en lugar de anexarse ​​al archivo). Supongo que esto se debe a que el archivo de destino puede abrirse en varios lugares al mismo tiempo.Bloqueo de archivos NFS en PHP

flock(...) suele ser excelente, pero no parece funcionar en NFS ... Lo cual es un gran problema para mí ya que el servidor de producción utiliza una matriz NFS.

Lo más parecido que he visto a una solución real implica tratar de crear un directorio de bloqueo y esperar hasta que se pueda crear. Decir que esto carece de elegancia es subestimar el año, posiblemente la década.

¿Alguna idea mejor?

Editar: Debo añadir que no tengo root en el servidor y hacer el almacenamiento de otra manera no es realmente posible en el corto plazo, no menos dentro de mi fecha límite.

Respuesta

2

Otro hack sucio sería flock() un archivo "local", y solo abrir/escribir en el archivo NFS si mantiene el bloqueo en el archivo local.

Editar: desde la página flock():

flock() no funcionará en NFS y muchos otros sistemas de archivos en red. Consulte la documentación de su sistema operativo para obtener más información.

Edición 2:

Por supuesto, siempre está usando la base de datos para el acceso synchonise (estoy asumiendo que su aplicación utiliza una base de datos). Sin embargo, esto sería un gran golpe de rendimiento si estás haciendo un montón de registro.

Si solo es para iniciar sesión, ¿realmente necesita un archivo de registro centralizado? ¿Podría iniciar sesión localmente (e incluso combinar los registros cuando rotan al final del día si es necesario)?

+0

Por el momento, estaría bien, pero una vez que esto esté fuera de desarrollo, se extenderá a través de varios servidores virtuales para equilibrar la carga y eso arrojaría una llave [más] en proceso. – Oli

3

Un enfoque podría ser configurar una instancia Memcache, compartida entre cada uno de sus servidores virtuales. Puede simular flock() poniendo una entrada del nombre de archivo en la memoria caché al iniciar las operaciones de archivos locales, y borrarla cuando termine.

Cada servidor puede acceder a este grupo antes de una operación de archivo y ver si este "bloqueo" está presente, p.

// Check for lock, using $filename as key 
$lock = $memcache->get($filename); 

if(!$lock) { 
    // Set lock in memcache for $filename 
    $memcache->set($filename, 1); 

    // Do file operations... 

    // Blow away "lock" 
    $memcache->delete($filename); 
} 
No

el más elegante de soluciones, sino que debe permitirle controlar las cerraduras de todos los servidores en la configuración con relativa facilidad.

0

Debería usar Memcache agregar y evitar una condición de carrera.

if ($memcache->add($filename, 1, 1)) 
{ 
    $memcache->delete($filename); 
} 
1

A pesar de que no se puede flock() en los archivos NFS y de E/S pueden ser asynchroneous, las operaciones de directorio de NFS son atómica. Eso significa que en un momento dado, un directorio lo hace, o no existe.

Para implementar su propia característica de bloqueo NFS, verifique o cree un directorio cuando desee tenerlo bloqueado y eliminarlo cuando haya terminado.

Desafortunadamente, probablemente no sea compatible con ninguna otra aplicación que no haya escrito usted mismo.

14

operaciones de directorio son NO atómica bajo NFSv2 y NFSv3 (consulte el libro 'NFS ilustradas por Brent Callaghan, ISBN 0-201-32570-5 ; Brent es un NFS-veterano al Sol).

NFSv2 tiene dos operaciones atómicas:

  • enlace simbólico
  • cambiar el nombre

Con NFSv3 crear la llamada también es atómica.

Sabiendo esto, se puede implementar spin-cerraduras para archivos y directorios (con cáscara, no PHP):

bloquear directorio actual:

while ! ln -s . lock; do :; done 

bloquear un archivo:

while ! ln -s ${f} ${f}.lock; do :; done 

desbloqueo (suposición, el proceso de ejecución realmente adquirió el bloqueo):

desbloqueo directorio actual:

mv lock deleteme && rm deleteme 

desbloqueo de un archivo:

mv ${f}.lock ${f}.deleteme && rm ${f}.deleteme 

Quitar tampoco es atómica, por lo tanto, en primer lugar el cambio de nombre (que es atómica) y luego la eliminación.

Para el enlace simbólico y renombrar llamadas, ambos nombres de archivo deben residir en el mismo sistema de archivos . Mi propuesta: use solo nombres de archivo simples y ponga el archivo y bloquéelo en el mismo directorio.

+0

Estos comentarios en la página del manual de flock están relacionados y los encontré bastante útiles. http://www.php.net/manual/en/function.flock.php#46085 http://www.php.net/manual/en/function.flock.php#68875 http: //www.php.net/manual/en/function.flock.php#82521 – aiham

2

También puede usar dio_fcntl() para bloquear archivos en volúmenes NFS. Requiere el paquete de dio, que puede no ser parte de su instalación de php por defecto.