Wiederherstellen von Dateien in einem gelöschten Ordner (ext3)

Eine Datei ist so schnell gelöscht und ein Backup nicht immer zur Hand. Zum Glück gibt es bei ext3 und ext4 Hoffnung auf eine relativ einfache Wiederherstellung der Daten.

Hier ein einfaches Beispiel:

Die Lösung ist unter Debian und Ubuntu denkbar einfach.

Bauen wir doch zuerst unsere kleine Testumgebung auf:

Wir erstellen einen Ordner und welchseln in diesen:

mkdir test && cd test

Wir erstellen unser Test-Image und formatieren es mit ext3:

dd if=/dev/zero of=test.img count=2k bs=4096 status=noxfer && echo j | mkfs.ext3 test.img

Nun müssen wir es nur noch mounten (falls der mount Befehl nicht funktioniert, das ganze mit sudo probieren):

mkdir mnt; mount -o loop test.img mnt/

Einen einfachen Ordner erstellen:

mkdir mnt/directory

Nun erstellen wir ein paar Dateien (10 an der Anzahl):

for i in {1..10} ; do echo "Erstelle die Datei Nummer $i" ; dd if=/dev/urandom of=mnt/directory/myfile_$i count=1k bs=512 status=noxfer ; done

Nun noch das ganze definitiv auf die Festplatte schreiben:

sync

Nun löschen wir testweise fünf Dateien:

for i in {3..7} ; do echo "Erstelle die Datei Nummer $i" ; rm mnt/directory/myfile_$i ; done

umounten das ganze und löschen den Ordner

sudo umount mnt; rmdir mnt

Um die Datei wiederherzustellen unter Debian:

aptitude install ext3grep

Wir halten nun ausschau nach unseren Dateien:

ext3grep --dump-names test.img
Running ext3grep version 0.10.1
WARNING: I don't know what EXT3_FEATURE_COMPAT_EXT_ATTR is.
Number of groups: 1
Minimum / maximum journal block: 306 / 1335
Loading journal descriptors... sorting... done
The oldest inode block that is still in the journal, appears to be from 1340653254 = Mon Jun 25 21:40:54 2012
Number of descriptors in journal: 472; min / max sequence numbers: 2 / 31
Finding all blocks that might be directories.
D: block containing directory start, d: block containing more directory entries.
Each plus represents a directory start that references the same inode as a directory start that we found previously.
Searching group 0: DDD++++++++++
Writing analysis so far to 'test.img.ext3grep.stage1'. Delete that file if you want to do this stage again.
Result of stage one:
  3 inodes are referenced by one or more directory blocks, 3 of those inodes are still allocated.
  2 inodes are referenced by more than one directory block, 2 of those inodes are still allocated.
  0 blocks contain an extended directory.
Result of stage two:
  3 of those inodes could be resolved because they are still allocated.
All directory inodes are accounted for!
Writing analysis so far to 'test.img.ext3grep.stage2'. Delete that file if you want to do this stage again.
directory
directory/myfile_1
directory/myfile_10
directory/myfile_2
directory/myfile_3
directory/myfile_4
directory/myfile_5
directory/myfile_6
directory/myfile_7
directory/myfile_8
directory/myfile_9
lost+found

Logischerweise ist dies für unsere Suche ein wenig gar viel Text. Schränken wir also mittels regex ein wenig ein, damit wir nur noch unsere 5 gelöschten Dateien sehen:

ext3grep --dump-names test.img | egrep myfile_[3-7]
directory/myfile_3
directory/myfile_4
directory/myfile_5
directory/myfile_6
directory/myfile_7

Um zum Beispiel die Datei “myfile_4” wiederherzustellen, genügt folgender Befehl:

ext3grep --restore-file directory/myfile_4 test.img

Wenn wir die ganze Liste wiederherstellen möchten, können wir dies auch so machen:

for i in $(ext3grep --dump-names test.img | egrep myfile_[3-7] | xargs) ; 
do echo "################" ; 
echo "Stelle die Datei $i wieder her" ; 
ext3grep --restore-file $i test.img ; 
done

Die Dateien wurden nun im Ordner RESTORED_FILES abgelegt. Ein kurzer find-befehl zeigt uns alle wiederhergestellten Dateien:

manuel@nmalinux:~/test$ find RESTORED_FILES/ | sort -n
RESTORED_FILES/
RESTORED_FILES/directory
RESTORED_FILES/directory/myfile_3
RESTORED_FILES/directory/myfile_4
RESTORED_FILES/directory/myfile_5
RESTORED_FILES/directory/myfile_6
RESTORED_FILES/directory/myfile_7

Wichtige Hinweise:

  • Benutze nie ext3grep für die Wiederherstellung von Daten bei einem gemountetem System!
  • Bei grossen Filesystemen und einer 32-bit Architektur kann ext3grep gerne crashen. Daher lieber vorgängig schon ein 64-Bit System benutzen.
  • ext3grep kann keine Dateien wiederherstellen wenn keine “Rückstände” vorhanden sind
  • Einige Dateien welche mit ext3grep wiederhergestellt sind, haben null bytes. Diese Dateien werden wohl nicht wiederhergestellt werden können.

Ursprünglich wurde dieser Blog-Eintrag von einem unserer Mitarbeiter geschrieben: Blog von: Manuel Ambauen

Rails Server: Performance Optimierung

Performance Optimierung am Rails Server durch Passenger Konfigurationen

Im letzten Artikel habe ich gezeigt wie man eine Applikation auf dem Rails Server installiert. Heute werde ich darauf eingehen wie man die Performance mit dem Rails Server noch weiter steigern kann.

Als Beispiel nehme ich wieder die Applikation vereine.ch.

Stand der Applikation

Es wurden Query-Optimierungen mit DB-Indexes vorgenommen. Zudem profitieren wir vom Rails Caching im production Environment.

Da vereine.ch zuerst auf normalem Internet Standard Hosting betrieben wurde konnten keine Optimierungen an MySQL und Apache/Passenger Konfiguration gemacht werden. Auch auf Result Caching mit memcached mussten wir verzichten.

Messungen mit altem Hosting

Wir haben die meistbesuchten Pages von vereine.ch einem Stresstest unterzogen. Dazu wird jede Page parallel von mehreren Threads abgerufen. Als Resultate erhalten wir die Response Time der Applikation in MS. Wir verwenden hier den 90% Wert um noise auszufiltern.

Diese Resultate erhalte ich mit 5 Threads die je 10 Requests absetzen:

Hier ist eine kurze Erklärung der Abfragen angebracht.

  • Live Search ist eine Abfrage auf Vereine mit Einschränkung auf Kategorie und Umkreis (geo-Daten). Es simuliert einen AJAX Request und lädt somit keine Layoutdaten. Ist auf 15 Resultate beschränkt.
  • Kategorien zeigt mir die 15 Hauptkategorien und die Anzahl dazu eingetragener Vereine und Dienstleistungen an.
  • Index ist ähnlich wie Live Search nur diesmal mit Layout.
  • Kategorien Vereineinfo ist wieder ein AJAX Request der von der grössten Kategorie (mit ca 600 Vereinen) alle Vereine mit Link lädt. In den Resulateten zeigt sich hier eindeutiges Verbesserungspotenzial.
  • More Results ist nochmal ein Live Search Request diesmal einfach mit offset.
  • String Search macht auch eine Abfrage auf 15 Vereine, diesmal wird aber Fulltext Search über ein Textfeld verwendet.

Den Werten ist zu entnehmen, dass Kategorien Vereineinfo viel zu langsam lädt und auch Index mit über einer Sekunde relativ viel Zeit beansprucht. Die Anderen Pages sind mit einer Response Time von 300 bis 700 ms zwar annehmbar aber bestimmt nicht optimal.

Im zweiten Durchlauf erhöhen wir die Anzahl Threads auf 10 und belassen die Anzahl Requests pro Thread auf 10.

Die Resulate sind katastrophal. Die beste Response Time liegt bei 2.7 Sekunden und ist damit weit über dem Grenzwert für ein angenehmes Benutzererlebnis.

Wie lässt sich diese drastische Verschlechterung erklären?

Unser Internet Standard Hosting erlaubt es uns leider nur 2 Passenger Instanzen gleichzeitig laufen zu lassen. Da jede Instanz nur einen Request verarbeiten kann steigt somit die Response Time linear zur Anzahl Benutzer und erreicht somit sehr schnell eine kritische Länge.

Optimierung am Rails Server

Apache und Passenger

Wir wissen jetzt, dass die Anzahl Passenger Instanzen einen starken Einfluss auf die Performance einer Rails Applikation hat. Aber wie verhält sich das genau?

Eine Passenger Instanz ist ein Prozess der eine Kopie meiner Rails Applikation im RAM hält um möglichst schnell einen Request beantworten zu können. Das heisst wie viele Passenger Instanz ich starten kann hängt davon ab wie viel unbenutztes RAM mir auf meinem Server zur Verfügung steht. Wenn ich aber zu viele Instanzen starte fängt der Server an zu swappen was für die Performance noch schädlicher ist als zu wenig Passenger Prozesse zu haben.

Die perfekte Zahl von Instanzen hängt dabei natürlich immer von der Applikation ab. Um diese zu bestimmen sind die Befehel passenger-memory-stats und free -m sehr hilfreich. Wobei der Erste mir sagt wie viel RAM meine Applikation braucht und der Zweite mir sagt wie viel auf dem Server noch ungenutzt ist. Als Faustregel hat es sich bewährt 15 Instanzen pro GB Memory zu konfigurieren.

Um das so für vereine.ch zu Konfigurieren öffne ich das entsprechende Apache Configfile und füge folgendes zur VirtualHost Direktive hinzu:

PassengerMaxPoolSize 15

Hier sind noch ein paar weitere Passenger Optionen die sich für uns bewährt haben.

  # Speeds up spawn time by a lot but some apps might be incompatible
  PassengerSpawnMethod smart
  # ApplicationSpawner is kept alive. 
  # This speeds up spawning of new Application Instances.
  RailsAppSpawnerIdleTime 0
  # Application Instances are kept alive longer
  PassengerPoolIdleTime 1000
  # Perform filesystem checks (i.e. check for restart.txt) only once every 5 seconds. 
  # Default is on every request
  PassengerStatThrottleRate 5
  # Explicitly specify that the host is a Ruby on Rails application.
  RailsAutoDetect off
  RailsBaseURI /

So, wie verhält sich unser Test mit 5 Benutzern à 10 Requests nun mit der neuen Konfiguration?

Man sieht jetzt schon eine klare Verbesserung gegenüber dem Standard Hosting. Die Response Time fast aller Requests ist stark gesunken und zwischen 100 – 400ms schon viel näher am Optimum.

Den massivsten Unterschied sieht man aber wenn man den Test mit 10 Benutzern à 10 Requests durchführt.

Die meisten Requests können hier eine Responsetime von unter einer Sekunde halten. Das ist schon eine massive Verbesserung wenn man bedenkt wie wenig Aufwand dazu nötig war.

Durch diese Resultate wird auch klar, dass der Engpass von Kategorien Vereineinfo in der Datenbank zu suchen sein wird.

Im nächsten Artikel werde ich Rails Server Optimierungen im Bereich Caching behandeln.

Rails Server: SSL für vereine.ch

In Rails Server: vereine.ch schnell und einfach deployed habe ich über das Deployment der vereine.ch Applikation gesprochen.

Da wir mit dieser auch https Logins erlauben wollen, muss ich den Webserver noch entsprechend Konfigurieren.

Dazu lege ich einen neuen VirtualHost auf Basis der normalen vereine.ch Konfiguration an.

cp /etc/apache2/sites-enabled/prod.vereine.conf  /etc/apache2/sites-enabled/prod.vereine.conf_443

Dieser muss noch für SSL Zugriffe angepasst werden.

NameVirtualHost 193.247.72.65:443
<VirtualHost 193.247.72.65:443>
    PassengerAppRoot /var/www/rails_apps/prod/vereine/
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/vereine.ch.crt
    SSLCertificateChainFile /etc/ssl/certs/vereine.ch.ca
    SSLCertificateKeyFile /etc/ssl/private/vereine.ch.key
    ...
</VirtualHost>

und damit ist vereine.ch auf schon unter https://vereine.ch erreichbar.

« Ältere Einträge Neuere Einträge »