PHP NFS dosya kilitleme

6 Cevap php

Benim en son webapp kısmı, günlük parçası olarak adil bir miktarda dosya yazmak gerekiyor. Ben fark ettik bir sorun birkaç eşzamanlı kullanıcı varsa, yazma can birbirinin üzerine (yerine dosya ekleme) olmasıdır. Ben bu çünkü hedef dosyanın aynı anda yerlerde bir dizi açık olabilir varsayalım.

flock(...) genellikle mükemmel ama üretim sunucu, bir NFS dizi kullanır gibi benim için büyük bir sorundur ... Hangi NFS üzerinde çalışmak için görünmüyor.

Ben gerçek bir çözüm için gördüğüm yakın şey bir kilit dir oluşturmak için çalışıyor ve bunun oluşturulabilir kadar bekleyen içerir. Bu zarafet yoksun söylemek için yılın yetersizdir, belki on yıl.

Daha iyi bir fikrin?

Düzenleme: Ben sunucu üzerinde kök var ve başka bir şekilde depolama yapıyor olmadığını eklemek gerekir benim süre içinde en azından değil, her zaman yakında gerçekten mümkün değildir.

6 Cevap

Başka bir kirli hack flock() "yerel" bir dosyaya olmak ve yerel dosya üzerinde kilidi tutarsanız sadece açık / NFS dosyaya yazmak istiyorsunuz.

Edit: flock() sayfa:

flock() will not work on NFS and many other networked file systems. Check your operating system documentation for more details.

Edit 2:

Tabii (Ben senin app bir db kullanır varsayarak) erişimi synchonise için veritabanı kullanarak her zaman var. Eğer olsa günlük bir sürü yapıyoruz bu oldukça bir performans hit olurdu.

Sadece giriş için, aslında merkezi bir log dosyası gerekiyor eğer? Yerel log (ve gerekirse günün sonunda döndürmek bile günlükleri birleştirmek) miyiz?

Directory operations are NOT atomic under NFSv2 and NFSv3 (please refer to the book 'NFS Illustrated' by Brent Callaghan, ISBN 0-201-32570-5; Brent is a NFS-veteran at Sun).

NFSv2 iki atom operasyonları vardır:

  • sembolik
  • adını değiştirmek

NFSv3 ile oluşturmak çağrısı da atom olduğunu.

Knowing this, you can implement spin-locks for files and directories (in shell, not PHP):

Geçerli dir kilidi:

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

Bir dosyayı kilitlemek:

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

kilidini (varsayım, çalışan süreç gerçekten kilidi kazanılmış):

Geçerli dir kilidini:

mv lock deleteme && rm deleteme

unBir dosyayı kilitlemek:

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

Remove is also not atomic, therefore first the adını değiştirmek (which is atomic) and then the remove.

For the sembolik and adını değiştirmek calls, both filenames have to reside on the same filesystem. My proposal: use only simple filenames and put file and lock into the same directory.

Bir yaklaşım sanal sunucuların her biri arasında paylaşılan bir Memcache örneği kurmak olabilir. Sen flock() Eğer yerel dosya işlemlerini başlattığınızda önbellek için dosya bir giriş koyarak, ve bittiğinde silerek maymun olabilir.

Her sunucu, örneğin, bir dosya ameliyattan önce bu havuzu erişmek, ve bu "kilit" mevcut olup olmadığını görmek için

// 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);
}

En çözümler zarif, ancak göreli kolaylığı ile kurulum tüm sunuculardan kilitleri kontrol sağlamalıdır değil.

Ayrıca NFS birimlerindeki dosyaları kilitlemek için dio_fcntl () kullanabilirsiniz. Bu varsayılan olarak php kurulum parçası olmayabilir, hangi dio paketini gerektirir.

NFS ve I () dosyalarını akın olsa bile / O, NFS dizin işlemleri are atom asynchroneous olabilir. Yani herhangi bir defada bir dizin yapar, ya da yok demektir.

Eğer kilitli var ve bittiğinde kaldırmak istediğinizde kendi NFS kilitleme özelliğini uygulamak için, bir dizin kontrol edin veya oluşturun.

Ne yazık ki, bu size kendinizi yazmadım muhtemelen başka bir uygulama ile uyumlu değil.

Sadece bir yarış koşulu eklemek ve önlemek memcache kullanmak gerekir.

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