Linux alt dizinleri sayı sınırı nasıl çözülür?


9

Kullanıcı profili görüntülerini depolayacak bir web sitem var. Her görüntü kullanıcıya özgü bir dizinde (Linux) saklanır. Şu anda 30'dan fazla müşteri tabanım var, yani 30'dan fazla klasörüm olacak. Ancak mevcut Linux kutum (ext2 / ext3) 32000'den fazla dizin oluşturmayı desteklemiyor. Bunu nasıl aşabilirim? YouTube'lu çocuklar bile video küçük resimlerinde aynı sorunu yaşıyor. Ancak ReiserFS'ye geçerek çözdüler. Daha iyi bir çözümümüz olamaz mı?

Güncelleme: IRC'de sorulduğunda, insanlar bunu 64k sınırına sahip ext4'e yükseltmeyi soruyorlardı ve elbette bunu bile geçebilirsiniz . Ya da sınırı değiştirmek için çekirdek kesmek.

Güncelleme: Kullanıcı tabanını, kullanıcı kimliği aralığına göre klasörlere ayırmaya ne dersiniz? Bir klasörde 1-1000, diğerinde 1000-2000 anlamına gelir. Bu basit gibi görünüyor. Ne diyorsun beyler?

Açıkçası, başka yolu yok mu?


1
Neden dosya sistemini değiştirmek istemiyorsunuz? Bu ext2 / 3'ün bir sınırlamasıysa, dosya sistemini değiştirmek veya mevcut FS'yi daha küçük FS'lere (daha farklı bağlama noktaları) bölmekten başka bir değişiklik yapamazsınız.
Manuel Faux

1
Manuel: Dosya sistemini değiştirirse, uygulamasına belirli bir FS bağlar. Her ne kadar cevap bu olsa da, muhtemelen bu uygulama düzeyinde çözülmesi gereken bir sorun olurdu. Çekirdeği veya dosya sistemini hacklemeniz gerekiyorsa, bazı çok özel gereksinimler olmadıkça muhtemelen yanlış yola inersiniz.
Kyle Brandt

Yanıtlar:


16

Bu sınır, tüm dosya sistemi için değil, dizin başınadır, bu nedenle daha fazla alt bölümlere ayırarak bu sorunu çözebilirsiniz. Örneğin, aynı dizindeki tüm kullanıcı alt dizinlerinin adın ilk iki karakterine bölünmesi yerine şöyle bir şey elde edersiniz:

top_level_dir
|---aa
|   |---aardvark1
|   |---aardvark2
|---da
|   |---dan
|   |---david
|---do
    |---don

Daha da iyisi, isimlerin bir tür karmasını oluşturmak ve bunu bölüm için kullanmak olacaktır. Bu şekilde ilk harf örneği yerine "da" çok dolu ve "zz" tamamen boş olmak yerine dizinler arasında daha iyi bir yayılma elde edersiniz. Örneğin, CRC veya MD5'i alırsanız ve ilk 8 biti kullanırsanız, şöyle bir şey alırsınız:

top_level_dir
|---00
|   |---some_username
|   |---some_username
|---01
|   |---some_username
...
|---FF
|   |---some_username

Bu, gerektiğinde daha fazla derinliğe genişletilebilir, örneğin, kullanıcı adı karma değeri olarak kullanılmıyorsa:

top_level_dir
|---a
|   |---a
|       |---aardvark1
|       |---aardvark2
|---d
    |---a
    |   |---dan
    |   |---david
    |---o
        |---don

Bu yöntem, kalamarın önbelleği, Ludwig'in örneğini ve web tarayıcılarının yerel önbelleklerini kopyalamak için birçok yerde kullanılır.

Dikkat edilmesi gereken önemli bir nokta, ext2 / 3 ile, dizinler doğrusal olarak arandığından, 32.000 sınırına yaklaşmadan önce performans sorunlarını vurmaya başlayacağınızdır. Başka bir dosya sistemine (örneğin ext4 veya reiser) geçmek, bu verimsizliği (reiser, ikili bölünmüş bir algoritmaya sahip dizinleri arar, böylece uzun dizinler çok daha verimli bir şekilde işlenir, ext4 de yapabilir) ve dizin başına sabit sınır.


Soru açıklamasını şu şekilde içerecek şekilde güncelledik: "Güncelleme: Kullanıcı tabanını kullanıcı kimliği aralığına göre klasörlere ayırmaya ne dersiniz. Bir klasörde 1-1000, diğerinde 1000-2000 gibi. Bu basit gibi görünüyor. diyor musun?"
None-da

1
Kullanıcılar genellikle kullanıcı adı yerine (veya yanı sıra) kullanıcı kimliğiyle tanımlanırsa, bu iyi çalışır ve bir karma değerinden daha verimli olur. Her zaman onlara sistemde başka bir yerde isimle başvurursanız, her yere ekstra ad -> kimlik aramaları eklemeniz gerekir.
David Spillett

Teşekkürler David! Farklı bir çözüm denedim. Ben 1-30000, 30000-60000 vb aralığı ile neredeyse 4 klasör oluşturdum .. Böyle büyük bir dizinden bir dosya almak 1000 dosyaları (önceki yaklaşım) olan bir dizinden daha fazla zaman alacaktır düşünüyorum. Ne dersin?
None-da

1
Bu dosya sistemine bağlıdır. Eğer ext2 veya ext3 kullanıyorsanız, dizin başına 30.000'den daha küçük olmasını tavsiye ederim. Bazı araçlar 10.000 civarında uyarı verir. Yardım etmek için ext3 / 4'te dizin indekslemeyi açabilirsiniz: tune2fs -O dir_index / dev / <volumename> ama sadece bir dizindeki nesne sayısını düşük tutmak (birkaç bin veya daha az?) .
David Spillett

@Maddy, Ext2 / 3'ün çok sayıda dosyayı nasıl işlediğine ilişkin diğer sınırlamalar nedeniyle bu çözümü istiyorsunuz. Ayrıntılar için serverfault.com/questions/43133/… adresine bakın . Adları alt dizinler olarak bölümlere ayırmak, sonunda karşılaşacağınız diğer sorunları hafifletir. Bunun, Squid'in nesne önbelleğini ilk kez ayarlarken kullandığı stratejiyle aynı olduğunu unutmayın - örneğin, her biri içinde 64 dizin bulunan 64 dizin.
Avery Payne

7

Eğer ext2 / ext3'e bağlıysanız, gördüğüm tek şey verilerinizi bölümlere ayırmaktır. Verilerinizi benzer boyuttaki yönetilebilir parçalara ayıran bir ölçüt bulun.

Sadece yaptığım profil resimleri ile ilgili ise:

  1. Görüntünün karmasını (örn. SHA1) kullanın
  2. SHA1'i dosya ve dizin adı olarak kullanma

Örneğin, SQUID önbelleği bunu şu şekilde yapar:

f / 4b / 353ac7303854033

Üst düzey dizin ilk onaltılık basamak, ikinci düzey sonraki iki onaltılık basamaktır ve dosya adı kalan onaltılık basamaktır.


2

Daha iyi bir çözümümüz olamaz mı?

Daha iyi bir çözümünüz var - farklı bir dosya sistemi kullanın, birçoğu farklı görevler için optimize edilmiş çok sayıda kullanılabilir. Belirttiğiniz gibi ReiserFS, bir dizindeki çok sayıda dosyayı işlemek için optimize edilmiştir.

Dosya sistemlerinin karşılaştırması için buraya bakın .

Sadece bir dizindeki birçok dosya için gerçekten dipsiz olan NTFS ile sıkışıp kalmamaya sevindim. Eğer nispeten yeni (ama görünüşte kararlı) ext4 FS kullanarak fantezi yoksa JFS yerine tavsiye ederim.


NTFS dosya sistemi performansına iyi bağlarınız var mı?
Thorbjørn Ravn Andersen

evet, bir dizinde yeni dosyalar oluşturmak için çok uzun bırakılan bir uygulama ile kişisel deneyim dışında .. (hepsini silmek saatler sürdü) ve bir dizindeki dosya sayısını 1000 ile sınırlandırarak subversion performans artışı. : support.microsoft.com/kb/130694 Ben hala bir perf olarak belirtildiği gibi bunu "sabit" sanmıyorum. NTFS için tweak.
gbjbaanb

1

Profil resmi küçük mü? Profil verilerinin geri kalanıyla veritabanına koymaya ne dersiniz? Bu sizin için en iyi seçenek olmayabilir, ancak dikkate değer ...

İşte konuyla ilgili bir (eski) Microsoft teknik raporu: BLOB'a veya BLOB'a değil .


1

Bu problemin bir varyasyonuyla sonuçlandığım küçük bir web galerisini birlikte hackledim; Ben "sadece" önbellek dizininde ~ 30.000 görüntü vardı, bu oldukça yavaş olduğu ortaya çıktı (hatırladığım gibi ext2 dizin dizinleri için bağlantılı listeleri kullanır).

Sonunda şu hatlar boyunca bir şeyler yaptım:

def key2path(key):
    hash = md5(key)
    return os.path.join(hash[0], hash[1], key)

Bu, verileri üç dizinin her biri için hızlı bir dizin araması sağlayan 256 dizinte bölümlendirir.

  • MD5, 32 bit 12'yi değiştirirseniz farklı bir çıktıyı garanti ettiği için SHA-1 üzerinden MD5 kullanmayı seçtim, bu yüzden hash kullanıcı adları, dizinler ve diğer kısa şeyler için iyi bir uyum buluyorum. Ve hızlı da ...
  • Çok fazla dizin üreteceği ve disk önbelleğini defalarca çöpe atacağı için tüm karma değerini dahil etmiyorum.

1
Muhtemelen CRC gibi daha basit bir karma kullanabilirsiniz, çünkü karma MD5 veya SHA gibi kriptografik olarak güçlü olmak zorunda değildir ... ama performans farkı zaten ihmal edilebilir ...
sleske

0

Sorununuza hemen bir yanıt değil, ancak ileride başvurmak için izlenecek bir şey, 'Epitome' adlı OpenBSD bağlantılı projedir.

Epitome, Tek Örnek Depolama, İçerik Adreslenebilir Depolama ve Veri Tekilleştirme hizmetleri sunan bir motordur.

Tüm verileriniz, bir veri deposunda karma bloklar olarak depolanır, alan kullanımını azaltmak için benzersiz olmayan blokları kaldırır ve içeriği UUID tarafından veri deposundan kolayca isteyebileceğinizden, temel olarak depolama mekanizmasını unutmanızı sağlar.

Epitom şu anda deneysel, ancak gelecek için izlenecek bir şey.


0

Genellikle içinde çok sayıda dosya / dizin bulunan dizinlere sahip olmaktan kaçınmak istersiniz. Birincil neden, komut satırındaki joker karakter genişletmesinin, bu dizinlerle çalışmaya çalışırken çok fazla bağımsızlığa neden olan "Çok fazla bağımsız değişken" hatasına yol açmasıdır.

Daha derin ama daha dar bir ağaç yapan bir çözüm için gidin, örneğin diğerleri gibi alt klasörler oluşturarak.


0

Benzer bir sorun yaşadık, çözüm - daha önce de belirtildiği gibi - bir dizin hiyerarşisi oluşturmaktır.

Elbette düz bir dizin yapısına dayanan karmaşık bir uygulamanız varsa, muhtemelen çok fazla yama yapmanız gerekecektir. Bu nedenle, bir geçici çözüm olduğunu bilmek güzel, belirtilen 32k sınırına sahip olmayan semboller kullanın. Sonra uygulamayı düzeltmek için bol zamanınız var ...


0

Neden bir zaman damgası yaklaşımı kullanmıyorsunuz ve taşma seçeneğiniz var.

Örneğin

Diyelim ki zaman damganız: 1366587600

Son 2 basamağı atlayın (ya da sadece biraz saçma olur). Damgayı 4'lü kümelere ayırın (dizin sayısı 9999'dan fazla olmamalıdır - isterseniz farklı şekilde ayırabilirsiniz).

Bu size böyle bir şey bırakmalıdır:

/files/1366/5876/

Ayrıca, yüklemeden önce dir içindeki miktarı da kontrol edin, eğer çok sayıda yükleme alıyorsa (yani 100 saniyede 32000 +), ardından dizini ikinci veya bir harfle yineleyin, örneğin:

/files/1366/5876/a/file.txt

veya

/files/1366/5876/00/file.txt

Ardından, zaman damgası + harfini veya tam yol kodunu kullanıcıyla birlikte bir db'ye kaydedin ve ayarlamanız gerekir.

pathstamp: 1366587600 veya 13665876a (harf kullanıyorsanız).

Bu, çok sayıda dizinle sonuçlanır, ancak dosya revizyonlarını işlemek için gerçekten yararlı olabilir. Örneğin, bir kullanıcı yeni bir profil resmi kullanmak istiyorsa, değişiklikleri geri almak istemesi durumunda, eskisinin eski zaman damgalı versiyonuna sahip olursunuz (sadece aşırı yazılmış değil).


0

Üst klasörde kaç tane maksimum alt dizin olmasını istediğinizi (veya yapabileceğinizi) karar vermenizi öneririm.

Ardından, kullanıcı kimliğinizi 1'den başlayacak şekilde dönüştürmeniz gerekir.

Sonra şunları yapabilirsiniz: modulo = currentId % numberOfSubdirectories

moduloartık hiçbir zaman numberOfSubdirectoriesseçtiğinizden daha büyük olmayacak alt dizin numaranızı içerecektir .

Modulo ile ne istersen yap, örneğin hash yap.

Ayrıca bu şekilde alt dizinler doğrusal olarak doldurulur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.