Posts mit dem Label FreeBSD werden angezeigt. Alle Posts anzeigen
Posts mit dem Label FreeBSD werden angezeigt. Alle Posts anzeigen

Samstag, 9. Juli 2011

DTrace and it's impact on JVM performance

So, I did this blogpost that gave a very shallow introduction to what DTrace can do with the JVM and I got an amazing feedback after that. Actually I'm quite flattered that it had such an impact.

One message I received pointed out that DTrace probes are having a significant impact on the JVM's performance, he (the author) would never recommend using the DTrace JVM integration, and then he pointed me… well, a product by his own company (which shall remain nameless, since I don't want to advertise commercial products on this blog). To be fair: I admit that I would do the same. When you put a lot of effort into a piece of software you do it for reasons you believe in.

However, he gave me a link to some benchmarks that showed some impressive results and diagrams about how much the performance of the JVM suffers when DTrace probes are enabled. The bar diagrams were scary, DTrace looked pretty bad compared to the "rival" technology (you can't really call it a rival since DTrace has a completely different objective). But something was fishy about this, and that was: the axes of the diagrams were not labeled. They did show a small blue bar and a big green bar and nothing else. The code for the test case was provided as a gif (no copy and paste to reproduce the results nice and easy). Numbers were not put into any perspective. And blog comments were disabled.

None the less, this was interesting enough to start a little bit of research on the topic.

The benchmarks seemed to focus on how much enabled probes did slow down method calls. I personally don't like benchmarks that use extremely unrealistic cases as a foundation (look how fast I can increment them integers in a tight loop suckaz! Mah language iz teh fast!) but this time I will just go with the flow because this is pretty much what they did in that benchmark (don't try this at home kids, use realistic conditions to benchmark your stuff). I'm not using the same test code here but the idea seems to be pretty much the same.

The system I'm running this on is a Thinkpad X201 with a core i7 and 8 gigs of RAM (yeah I know, I'm just compensating, get over it ;)). The operating system is OpenIndiana Build 151-beta with DTrace 1.7. Java is at 1.6.0_25.

The stupid test case I will be using is this Java program:

class Test {

public int callTest(int i) {
if (i != 0)
callTest(i - 1);

return i;
}

public static void main(String[] args) {
Test t = new Test();

long starttime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++)
callTest(100)
long endtime = System.currentTimeMillis();

System.out.println(endtime - starttime);
}
}

Once again, this is not a realistic example. I will just use it to demonstrate that there really is an impact.

> java Test
118
> java -XX:+ExtendedDTraceProbes Test
4106

Wow, this really seems to hurt… the programm is about 35 times slower with DTrace probes enabled.

To put this into perspective I will commit a capital crime in programming. I will compare this stupid program in language A to the same stupid program written in language B. Let language B be Python in this case. To be crystal clear about this: this is NOT a comparison of Python and Java performance. I just need some landmarks to make all those numbers meaningful (at least to some extent since this is a very badly chosen scenario to begin with).

Here is our Python test case.

import time

def callTest(i):
if not i == 0:
callTest(i - 1)

return i

r = range(0,1000000)

starttime = time.time()

for i in r:
callTest(100)

endtime = time.time()
print (endtime - starttime)

And the result:

> python test.py
21.9892270565


OK, our software runs slower with probes enabled, but we are still faster than Python and Python's performance is acceptable for a lot of use cases. We now have a slower JVM that can be instrumented. So I'd say: No real harm done.

Now let's use those probes and aggregate some real data. For this test I will use a slightly modified version of j_methodcalls.d, a script by Brendan Gregg that is shipped with the DTrace Toolkit. The script is licensed under CDDL but I did remove the license header here to make it more concise and blog-friendly.

#!/usr/sbin/dtrace -Zs

hotspot$target:::method-entry
{
this->class = (char *)copyin(arg1, arg2 + 1);
this->class[arg2] = '\0';
this->method = (char *)copyin(arg3, arg4 + 1);
this->method[arg4] = '\0';
this->name = strjoin(strjoin(stringof(this->class), "."),
stringof(this->method));
@calls[pid, this->name] = count();
}

Let's run it!

> pfexec ./j_methodcalls.d -c "java -XX:+ExtendedDTraceProbes Test"
[…snip…]
249126

OK, this is A LOT slower, even slower than Python. 4 Minutes!

We are now aggregating data and that means we are copying data from userspace into kernelspace from where it can be fetched by DTrace consumers (in our case the dtrace command line tool). What data did we get in this amount of time? Actually: A LOT. It flooded my terminal and I had to pipe the result into less to be able to read all of it. DTrace recorded every method call that happened in the JVM while the program was running. It counted the calls per method, and the class the method belongs to. Keep in mind that we did not need to modify our code to get these results. We don't even need to restart a running JVM to enable the probes we can activate them by using the jinfo command. And we could have used DTrace to gather system wide data in the same script (something I might demonstrate sometime on this blog)

Now lets use the most naive debugging technique on earth. We will print out "CALLED!" every time our callTest method gets called (if you ever did this before you know how disastrous the result well be). This gives us pretty much no information. We just know that a particular method has been called and we need to modify our code, recompile and load it into running JVM.

> time java Test
[…snip…]
CALLED!
5958514

real 1h39m18.15s
user 3m53.29s
sys 7m55.68s

As we expected, the result is a disaster. Calling print in a tight loop is an extremely stupid thing to do. We could have used a counter that get incremented with every method call, proxy objects, interceptors etc. (all of them would have been significantly faster).

To do something similar like the print example with DTrace I just a another clause to the script:

tick-1s {
printa(@calls);
trunc(@calls);
}

This addition prints out what happened in 1 second intervals

1 75779 :tick-1s
4028 Test.callTest 400379

1 75779 :tick-1s
4028 Test.callTest 404720

1 75779 :tick-1s
4028 Test.callTest 402135

1 75779 :tick-1s
4028 Test.callTest 398934

253064
dtrace: pid 4028 has exited


real 4m14.23s
user 4m13.89s
sys 0m0.46s

The performance impact stays pretty much the same with DTrace, we are done in 4 Minutes while we are presented with a readable stream of information.

There are a lot of ways to generate similar data, but most of them require code changes, are not able to do system wide tracing, are limited to one process and/or just one specific runtime.

Conclusion

Tracing the JVM costs (this shows especially in this pathological use case), but DTrace provides us with a very broad spectrum of probes. The JVM ones are just one source of data. We can actually instrument every part of the system with our DTrace script. Maybe a problem is not even related to our program at all, maybe it's NFS misbehaving, something is wrong with the database or there is some heavy IO going on. With DTrace the whole system becomes transparent. This changes the whole "blame game" and that's the whole point of DTrace. Looking at the system as a whole.

The bottom line is: trace the JVM only if you need to and be aware of the performance impact. This tool is for hunting down problems that are very hard or even impossible to analyze with traditional tools. I did use it to trace obscure memory leaks and dead-locks (both in non-Java contexts) and I was able to exactly pinpoint the culprit.

Don't use DTrace when there is a tool that does a better job for this specific task. Use it wisely. Anyway, it's a great utility to have in your toolbox.

Last but not least: use realistic use cases for benchmarking, label your diagram axes, and compare tools that have the same objective.

Mittwoch, 6. Juli 2011

DTrace and Scala

DTrace is one of my favorite technologies ever, it absolutely redefined my view on software and how it can be debugged. In a lot of situations you are basically forced to debug your software by vomiting print-statements just all over the place. To make things worse you have to take them out when you are actually shipping your software, leaving you blind to errors to come. In other cases you probably are missing some print-statements to trace down a very nasty bug, or the bug is hidden in some 3rd-party lib that would take hours to recompile with your new print statement (don't start thinking about libs that you don't have the code of…). In most cases this can become a very unpleasant situation (to put it mildly). DTrace takes a lot of the hassle away by providing you with a mechanism that can modify your program while it's running without stopping it.
Pretty amazing, huh? Wait, it gets better. You can even trace into the runtime of some high level languages (if they provide the probes). This is also true for the JVM, and that means we can instrument a running Scala program.

In this post I will walk you through a very basic script that shows what methods from Predef get called by your program. DTrace is a tool that reaches deep down into the lower levels of your machine. Sounds scary? Nah not really, one of the design goals of DTrace is safety. Your scripts run in a managed environment that keeps it from doing harmful things.

OK, enough sweet-talk. Time to get our hands dirty by writing a very simple Scala program:

import scala.annotation.tailrec

object Main {
@tailrec
def sayHallo() {
println("HALLO!")
Thread.sleep(1000)
sayHallo()
}

def main(args: Array[String]) {
sayHallo()
}
}

This just prints out "HALLO!" in 1 second intervals (not exactly rocket science, but I put a little sugar on top of it by replacing the while loop with a tail recursive function for fun and profit).

What's that? When running my program DTrace is not showing me ANY probes!!?!?! FFFFUUUUUUUU! That's because we have to enable them first, we can instruct a running JVM to do this by using jinfo. Since I only got one JVM running on this box I will fetch the PID with pgrep.

jinfo -flag +ExtendedDTraceProbes $(pgrep java)

The JVM probes are now armed and "dangerous" (just kiddin') and you will have access to the hotspot provider.

Now lets write the DTrace script. Keep in mind: this script is running in kernel space, so we have to copy in some information from userspace, we do this by using copyin and we have to NULL-terminate the strings ourselves. Yep, this is what it feels like to program low-level stuff, it's not as pretty as FP but aaaaaaaaaanyway, here is the little bugger.

#!/usr/sbin/dtrace -s

#pragma D option quiet

hotspot$$target:::method-entry
{
this->class = (char *) copyin(arg1, arg2 + 1);
this->class[arg2] = '\0';
self->tracefunc = stringof(this->class);
}

hotspot$$target:::method-entry
/self->tracefunc == "scala/Predef$"/
{
this->method = (char *) copyin(arg3, arg4 + 1);
this->method[arg4] = '\0';
printf("%s %Y\n", stringof(this->method), walltimestamp);
self->tracefunc = 0;
}

hotspot$$target:::method-entry
/self->tracefunc/
{
self->tracefunc = 0;
}

This thing will fire whenever a function from Predef is called and will give us the function name (in our test case this is just println) and the time when this function was being called. I run this on OpenIndiana build151-beta by issuing pfexec dtrace ./tracescript.d -p $(pgrep java) after I enabled the hotspot provider on the JVM. (pfexec is kind of like sudo, just use whatever gives you the permission to run dtrace on your box)
The output will look like this:

println 2011 Jul 6 21:27:34
println 2011 Jul 6 21:27:35
println 2011 Jul 6 21:27:36
println 2011 Jul 6 21:27:37
println 2011 Jul 6 21:27:38
println 2011 Jul 6 21:27:39
println 2011 Jul 6 21:27:40
println 2011 Jul 6 21:27:41
println 2011 Jul 6 21:27:42
println 2011 Jul 6 21:27:43
println 2011 Jul 6 21:27:44
println 2011 Jul 6 21:27:45
println 2011 Jul 6 21:27:46
println 2011 Jul 6 21:27:47
println 2011 Jul 6 21:27:48
println 2011 Jul 6 21:27:49
println 2011 Jul 6 21:27:50
println 2011 Jul 6 21:27:51
println 2011 Jul 6 21:27:52
println 2011 Jul 6 21:27:53
println 2011 Jul 6 21:27:54
println 2011 Jul 6 21:27:55


WTF IS THIS I DON'T EVEN!?!?!? TL;DR

OK, this is not even the tip of the iceberg but I think I will wrap it up because there is a lot of ground to cover when it comes to DTrace. If you are hungry for more you should check out the "DTrace Review" by @bcantrill, this stuff will blow your mind (seriously, WATCH IT!) or buy the book by @brendangregg. I will make sure to dig deeper on the topic, so stay tuned. Tell me what you think, good tool or best tool? :P

Donnerstag, 24. Juni 2010

FreeBSD 8.1 und die JVM

Alios hat gerade seinen Server auf den neusten Stand gebracht und prompt funktionierte Sakura natürlich wieder nicht. Das Problem war das die JVM wohl anscheinen den IPv6 Stack genommen hat und sich damit nicht verträgt, ein Workaround ist die JVM einfach dazu zu zwingen den IPv4 Stack zu nehmen. Das geht mit der -Djava.net.preferIPv4Stack=true Option.

Wenn euch also das nächste mal ein Socket beim Connect aus unerfindlichen Gründen abraucht, versucht es mal damit.

Freitag, 6. November 2009

By popular demand: Meine .kshrc

Ich werde des öfteren mal nach meinen Einstellungen für die ksh93 die ich als meine Defaultshell auf allen Systemen die ich derzeit aktiv verwende einsetze. Der Commandeditor fc hat es mir in dieser Shell besonders angetan ganz zu schweigen davon das sie im Vergleich zu anderen Shells ziemlich bugfrei ist.

Für alle nicht vi-User VORSICHT: Diese Config kommt mit aktiviertem vi-Modus daher ;) Außerdem habe ich PS ein wenig blogtauglicher formatiert.

Noch ein Tipp für die Mac-User: die ksh in der Standardinstallation ist ziemlich veraltet. Schnappt euch Macports und installiert sie euch daraus. Danach die neue Shell in die /etc/shells eintragen und sudo chsh -s /opt/local/bin/ksh username und ksh93 ist eure Defaultshell.


set -o noclobber
set -o ignoreeof
set -o globstar
set -o vi

HISTFILE=$HOME/.histfile.$(tty | cut -d/ -f 3)
RED=$(print -n "\033[0;31m")
GREEN=$(print -n "\033[0;32m")
YELLOW=$(print -n "\033[0;33m")
BLUE=$(print -n "\033[0;34m")
PURPLE=$(print -n "\033[0;35m")
CYAN=$(print -n "\033[0;36m")
WHITE=$(print -n "\033[0;38m")

export HOSTNAME=$(hostname)
export EDITOR="vim"
export HISTEDIT="vim"

_checkdir() {
if [[ $PWD == $HOME ]]
then
print -n "~"
elif [[ $PWD == "/" ]]
then
print $PWD
else
print -n ${PWD##*/}
fi
}

if [[ $(uname) == "Darwin" ]]
then
export PS1='${WHITE}[${GREEN}${USER}${WHITE}@${YELLOW}\
${HOSTNAME}${WHITE}:${BLUE}$(_checkdir)${WHITE}]:\
${RED}$HISTCMD${WHITE}> '
alias ls='ls -FG'
alias pkill='killall'
alias pgrep='ps -A | grep -i'
alias grep='grep --color=always'
elif [[ $(uname) == "SunOS" ]]
then
export PS1='[${WHITE}[${GREEN}${USER}${WHITE}@${CYAN}\
${HOSTNAME}${WHITE}:${BLUE}$(_checkdir)${WHITE}]:\
${RED}${HISTCMD}${WHITE}> '
export PATH="/bin:/sbin:/usr/bin:/usr/sbin:\
/opt/SunStudioExpress/bin:$PATH"
alias ls='ls -F'
elif [[ $(uname) == "FreeBSD" ]]
then
export PS1='[${WHITE}[${GREEN}${USER}${WHITE}@${PURPLE}\
${HOSTNAME}${WHITE}:${BLUE}$(_checkdir)${WHITE}]:\
${RED}${HISTCMD}${WHITE}> '
alias ls='ls -FG'
alias pkill='killall'
alias grep='grep --color=always'
alias pgrep='ps -A | grep -i'
fi

alias !!='fc -s -1'
alias vi='vim'

Sonntag, 6. September 2009

Bug: Snow Leopard's dynamic_cast und explizit instanziierte C++ Templates

Derzeit arbeite ich an einem Projekt welches ich auf dem Mac (allerdings nicht für den Mac) entwickle. Dabei verwende ich unter anderem auch gerne die RTTI (RunTime Type Information) Fähigkeiten von C++ die mir unter anderem auch sichere Downcasts zur Verfügung stellen (Ist ein Downcast nicht möglich wird der Nullpointer zurückgegeben). Das alles klappt durchaus gut, es sei denn ich schreibe eine Lib in der ich bereits die Templates instanziiere die ich später in meiner Applikation nutzen will. Alles kompiliert zwar wunderbar und das Template lässt sich ebenfalls nutzen sobald ich aber auf Polymorphie zurückgreife wird es hässlich, da anscheinend die Typinformationen verloren gehen und dynamic_cast nicht mehr in der Lage ist richtig zu arbeiten.

Der ganze Fehler lässt sich mit folgendem Testfall reproduzieren:


//TestLib.hpp
class Base {
public:
virtual ~Base() {}
};

template <typename T>
class Derived : public Base {
public:
Derived();
};

/*TestLib.cpp
* compile with: g++ -dynamiclib TestLib.cpp -o libTestLib.dylib
*/
#include "TestLib.hpp"
#include <typeinfo>
#include <iostream>

template <typename T>
Derived<T>::Derived() {
std::cout << typeid(*this).name() << std::endl;
}

template class Derived<int>;

Wie man in der letzten Zeile sieht wird das Template Derived explizit mit int in TestLib.cpp instanziiert. Diesen Typen werden wir jetzt in einer kleinen Anwendung etwas durch die Typhierarchie scheuchen und ein sehr seltsames Verhalten beobachten.

/* main.cpp
* compile with: g++ -L. -lTestLib main.cpp -o main
*/
#include "TestLib.hpp"
#include <iostream>

int main() {
Derived<int>* i = new Derived<int>();
std::cout << typeid(*i).name() << std::endl;
Base *o = i;
std::cout << typeid(*o).name() << std::endl;
std::cout << o << std::endl;
std::cout << dynamic_cast< Derived<int>* >(o) << std::endl;
std::cout << typeid(*o).name() << std::endl;
delete i;
}

Wir erhalten folgende Ausgabe:

7DerivedIiE
7DerivedIiE
0x100100080
0
7DerivedIiE

Die Typid verändert sich nicht und trotzdem liefert ein gültiger Downcast den Nullpointer zurück. Ich habe den Code ebenfalls unter FreeBSD und DragonflyBSD getestet, in beiden Fällen war der Downcast erfolgreich. Meines Wissens tritt dieses Verhalten erst seit Snow Leopard auf, aber da ich derzeit nirgends eine aktuelle Version von Leopard laufen habe kann ich nicht testen ob es sich hier um einen neuen Bug handelt.

Der einzige Workaround der mir derzeit einfällt ist die Instanziierung des Templates in die Compilezeit der Anwendung zu verlegen.

UPDATE: Mal ein delete nachgebessert, nicht das sich hier noch jemand beschwert das mein Testcase leakt :P

Dienstag, 16. Juni 2009

LLVM: Neue Compiler braucht das Land!

In letzter Zeit macht die Low Level Virtual Machine immer mehr von sich Reden. Blöderweise ist der Name doch ein wenig verwirrend und man denkt schnell an die Java VM oder dergleichen. In Wirklichkeit handelt es sich um ein Compilerframework (und eine eigene Sprache) welches einem sehr interessante Möglichkeiten eröffnet. Apple verwendet LLVM unter anderem um OpenCL zu realisieren.
Was mich besonders an LLVM interessiert sind vor allem die Möglichkeiten zur Analyse von Fehlern die es bietet. Hier mal gcc und clang (ein C/C++/ObjC Frontend für LLVM) im Vergleich.

$ gcc-4.2 -fsyntax-only t.c
t.c:7: error: invalid operands to binary + (have 'int' and 'struct A')
$ clang -fsyntax-only t.c
t.c:7:39: error: invalid operands to binary expression ('int' and 'struct A')
return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);
~~~~~~~~~~~~~~ ^ ~~~~~

Clang nagelt den Fehler auf Zeile UND Spalte fest, nebenher verbraucht er zum kompilieren auch noch weniger Speicher und ist auch noch schneller. Ziemlich beeindruckend.

LLVM wird sicherlich den Compilermarkt in der Opensource Welt nachhaltig verändern. So gibt es z.B. Ambitionen FreeBSD komplett mit Clang anstelle von GCC zu übersetzen.

Auch die Rubyfraktion will von LLVM profitieren und so experimentiert das MacRuby-Projekt ebenfalls mit LLVM um Ruby auf dem Mac zu beschleunigen.

Für alle die jetzt neugierig geworden sind gibt es hier einen interessanten Tech Talk zum Thema, genauso wie einen Podcast vom Chaosradio Express

Samstag, 1. November 2008

ZFS: Eine Einführung

Krank sein nervt, aber wenn man im Bett liegt kann man sich mit ein paar Sachen befassen die man sonst eher selten macht. Ich hab die letzten Tage die ich mit Grippe im Bett gelegen hab einfach mal damit verbracht mich in einige ZFS Features einzuarbeiten und mir Gedanken darüber zu machen wie man sie in einem Blog packt. Damit auch die Linuxwelt etwas davon hat hab ich mich auch gleich noch darum gekümmert ZFS unter Ubuntu zum fliegen zu bringen.

Naja lange Rede kurzer Unsinn.

ZFS! Immer wieder hört man das es sich hierbei "nur" um ein Filesystem handelt. Ich will heute mal zeigen das das zwar stimmt, ZFS aber sehr viel mehr ist. Es ist praktisch ein Storage Werkzeugkoffer der fast alles abdeckt was einem in Sachen Storage so über den Weg laufen kann. Das Element mit dem alles anfängt ist der sogenannte zpool. In einem zpool packen wir alles was wir an Storage so nutzen wollen: Festplatte, USB-Sticks, einfach nur Dateien und was weiß ich noch für Devices. Ich werde hier aufgrund eines notorischen Festplattenmangels einfach ganz normale Files nehmen die jeweils 100MB Größe haben.

ZPools

Als erstes werden wir einfach mal die einfachste Sorte von zpools anlegen, nämlich solche die nur aus einem Datenträger bestehen.

[root@itzkoatl:zfsdemo]> zpool create tank $PWD/disk1
[root@itzkoatl:zfsdemo]> zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
tank 95.5M 73.5K 95.4M 0% ONLINE -
[root@itzkoatl:zfsdemo]> zpool status tank
pool: tank
state: ONLINE
scrub: none requested
config:

NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk1 ONLINE 0 0 0

errors: No known data errors

Das wars eigentlich schon. Alleine durch die Eingabe von zpool create tank $PWD/disk1 haben wir einen neuen zpool erstellt. Kein formatieren, kein mounten. Das File wurde direkt mit einem ZFS Filesystem auf dem mountpunkt /tank angehängt. Das dauert nur wenige Sekunden.
Was aber machen wenn man mehrere Festplatten hat und deren Platz in einem pool verwenden will?

[root@itzkoatl:zfsdemo]> zpool add tank $PWD/disk2
[root@itzkoatl:zfsdemo]> zpool status tank
pool: tank
state: ONLINE
scrub: none requested
config:

NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk1 ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk2 ONLINE 0 0 0

errors: No known data errors
[root@itzkoatl:zfsdemo]> zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
tank 191M 82.5K 191M 0% ONLINE -

Wir haben die neue Platte einfach durch add in den zpool eingefügt und wir zpool list zeigt hat sich die Kapazität von tank verdoppelt.
Wir können aber auch zpool mit RAID Fähigkeiten erstellen, dazu gibt es die subkommandos mirror, raidz und raidz2.

[root@itzkoatl:zfsdemo]> zpool create tank mirror $PWD/disk1 $PWD/disk2
[root@itzkoatl:zfsdemo]> zpool status tank
pool: tank
state: ONLINE
scrub: none requested
config:

NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk1 ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk2 ONLINE 0 0 0

errors: No known data errors
...
[root@itzkoatl:zfsdemo]> zpool create tank raidz2 $PWD/disk1 $PWD/disk2 $PWD/disk3 $PWD/disk4
[root@itzkoatl:zfsdemo]> zpool status tank
pool: tank
state: ONLINE
scrub: none requested
config:

NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2 ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk1 ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk2 ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk3 ONLINE 0 0 0
/export/home/raichoo/zfsdemo/disk4 ONLINE 0 0 0

errors: No known data errors

Man kann noch sehr viel mehr mit zpools anstellen, aber das reicht fürs erste ;).

Filesysteme

Das erste Filesystem haben wir ja schon mit dem Erstellen des zpools angelegt. Es trägt den Namen tank und ist unter /tank gemountet.

[root@itzkoatl:zfsdemo]> zfs list
NAME USED AVAIL REFER MOUNTPOINT
tank 98.6K 158M 26.9K /tank

Wir tun jetzt einfach mal so als würden wir eine Art home-Struktur anlegen wollen. Dazu legen wir ein separates home-Filesystem und ein Filesystem für jeden Benutzer an. ZFS Filesysteme sind in etwa vergleichbar mit dem was man unter herkömmlichen Filesystemen als Partitionen bezeichnet, nur das sie sich in ihrer Größe dem Inhalt anpassen. Ein ZFS Filesystem in dem also nichts liegt wird auch praktisch nichts an Plattenplatz belegen.

[root@itzkoatl:zfsdemo]> zfs create tank/home
[root@itzkoatl:zfsdemo]> zfs create tank/user1
[root@itzkoatl:zfsdemo]> zfs create tank/user2
[root@itzkoatl:zfsdemo]> zfs create tank/user3
[root@itzkoatl:zfsdemo]> zfs list
NAME USED AVAIL REFER MOUNTPOINT
tank 247K 158M 34.4K /tank
tank/home 26.9K 158M 26.9K /tank/home
tank/user1 26.9K 158M 26.9K /tank/user1
tank/user2 26.9K 158M 26.9K /tank/user2
tank/user3 26.9K 158M 26.9K /tank/user3

So wir haben unsere Filesysteme erstellt aber UPS! unsere User sind ja gar nicht an der richtigen Stelle gemountet, eigentlich gehören die ja nach /tank/home. Kein Problem, wir können den Mountpoint im Nachhinein einfach setzen

[root@itzkoatl:tank]> zfs set mountpoint=/tank/home/user1 tank/user1
[root@itzkoatl:tank]> zfs rename tank/user1 tank/home/user1
[root@itzkoatl:tank]> zfs list
NAME USED AVAIL REFER MOUNTPOINT
tank 258K 158M 32.9K /tank
tank/home 55.3K 158M 28.4K /tank/home
tank/home/user1 26.9K 158M 26.9K /tank/home/user1
tank/user2 26.9K 158M 26.9K /tank/user2
tank/user3 26.9K 158M 26.9K /tank/user3

Das rename ist eigentlich nicht nötig, ich habe es allerdings hier aus Schönheitsgründen mal gemacht ;). Durch das Umsetzen des Mountpoints wird das Filesystem von seinem alten Standort ausgehängt und am neuen Mountpoint eingehängt, alles automatisch.
Wir räumen jetzt einfach mal die anderen Filesysteme weg und arbeiten nur noch mit user1 weiter.

[root@itzkoatl:tank]> zfs destroy tank/user2
[root@itzkoatl:tank]> zfs destroy tank/user3


Filesystem Attribute

Jetzt zu ein paar interessanten Attributen die man mit set und get setzen und auslesen kann. Ich werde nur ein paar davon zeigen weil es wirklich eine ganze Menge sind, aber ich halte diese für die praktischsten.

Reservation

Hiermit läßt sich Plattenplatz aus dem zpool reservieren. Dem Filesystem wird also eine bestimmte Menge Storage zugesichert, wie man unten sieht hat tank/home/user1 10MB mehr Speicher zur Verfügung als alle anderen Filesysteme.

[root@itzkoatl:tank]> zfs set reservation=10m tank/home/user1
[root@itzkoatl:tank]> zfs list
NAME USED AVAIL REFER MOUNTPOINT
tank 10.2M 148M 28.4K /tank
tank/home 10.0M 148M 28.4K /tank/home
tank/home/user1 26.9K 158M 26.9K /tank/home/user1


Quotas

Was man reservieren kann, kann man aus begrenzen. Mit Quotas lassen sich Filesysteme klein halten.


[root@itzkoatl:tank]> zfs set quota=10m tank/home/user1
[root@itzkoatl:tank]> zfs list
NAME USED AVAIL REFER MOUNTPOINT
tank 10.2M 148M 28.4K /tank
tank/home 10.0M 148M 28.4K /tank/home
tank/home/user1 26.9K 9.97M 26.9K /tank/home/user1


Compression

Der Name sagt es schon. Filesysteme lassen sich transparent komprimieren. Es gibt unterschiedliche Algorithmen wir nehmen hier gzip als Beispiel.

[root@itzkoatl:tank]> zfs set compression=gzip tank/home/user1
[root@itzkoatl:tank]> zfs get compression tank/home/user1
NAME PROPERTY VALUE SOURCE
tank/home/user1 compression gzip local

Hier sollte man daran denken das nur Dateien komprimiert werden die nachträglich im Filesystem erstellt werden. Auch zeigt ls nicht die komprimierte sondern die reale Größe der Datei an.

NFS

Besonders praktisch ist NFS Sharing. Ich werde hier nur die einfachste Form zeigen, aber anstatt on lassen sich die normalen NFS Optionen für das Filesystem angeben. Unter Solaris wird hier alles automatisch eingerichtet und gestartet so das das eingeben einer einzige Zeile reicht um Filesysteme zu sharen (keine Ahnung wie das unter anderem Systemen ist).

[root@itzkoatl:tank]> zfs set sharenfs=on tank/home/user1


Das sind nur ein paar der vielen Attribute die ZFS bietet, alle zu zeigen würden den Rahmen sprengen ;)

Snapshots

Kommen wir zu einem meiner Lieblingsfeatures: Snapshots. Mit Snapshots lassen sich Filesysteme zu einem bestimmten Zeitpunkt einfrieren und auch wieder zurückspielen (und das innerhalb von ein paar Sekunden und ohne das es extra Plattenplatz belegt). Es ist ebenfalls jederzeit möglich in angelegt Snapshots reinzugucken. Wir werden jetzt einfach mal folgendes machen: Wie legen eine Datei mit dem Text "Das ist ein Test" an, danach erstellen wir einen Snapshot und werden die Datei verändern.

[root@itzkoatl:user1]> echo "Das ist ein Test" > text
[root@itzkoatl:user1]> ls
text
[root@itzkoatl:user1]> cat text
Das ist ein Test
[root@itzkoatl:user1]> zfs snapshot tank/home/user1@kleinertest

Ok wir haben den Zustand unseres Filesystems jetzt unter dem Snapshot mit dem Namen kleinertest gesichert. Nun wollen wir unsere Datei mal kaputtmachen und alles wieder herstellen.
[root@itzkoatl:user1]> echo "Ich mach alles kaputt!" >| text 
[root@itzkoatl:user1]> cat text
Ich mach alles kaputt!
[root@itzkoatl:user1]> cat .zfs/snapshot/kleinertest/text
Das ist ein Test
[root@itzkoatl:user1]> zfs rollback tank/home/user1@kleinertest
[root@itzkoatl:user1]> cat text
Das ist ein Test

Wie man sieht existiert ein versteckter Ordner .zfs, dieser wird nicht von ls -a angezeigt (Es sei denn man setzt ein bestimmtes Attribut) sondern praktisch on-the-fly erstellt wenn man explizit auf ihn zugreift. Mit zfs rollback spulen wir das Filesystem wieder zu dem Zeitpunkt zurück an dem wir den Snapshot kleinertest erstellt haben (der Snapshot selber existiert weiter). Snapshot sind nicht beschreibbar aber es lassen sich mit zfs clone schreibbare Filesysteme aus einem Snapshot erstellen.

Serialisieren

Ein Filesystem läßt sich in eine einzelne Datei ausgeben die sich dann verschicken läßt und woanders wieder in ein Filesystem umwandeln läßt (sehr praktisch für Backups). Dazu brauchen wir erst einmal einen Snapshot, dieser läßt sich mit zfs send serialisieren und mit zfs receive wieder "entpacken".

[root@itzkoatl:user1]> zfs send tank/home/user1@kleinertest > /tank/dump
[root@itzkoatl:user1]> ls -l /tank/dump
-rw-r--r-- 1 root root 15680 Nov 1 17:29 /tank/dump
[root@itzkoatl:user1]> zfs receive tank/home/user2 < /tank/dump
[root@itzkoatl:user1]> cat /tank/home/user2/text
Das ist ein Test
[root@itzkoatl:user1]> zfs list
NAME USED AVAIL REFER MOUNTPOINT
tank 10.2M 148M 45.6K /tank
tank/home 10.1M 148M 31.4K /tank/home
tank/home/user1 29.1K 9.97M 29.1K /tank/home/user1
tank/home/user2 27.6K 148M 27.6K /tank/home/user2

Wir haben also nun aus der dump-datei einfach ein neues Userverzeichnis erstellt welches den Zeitpunkt wiederspiegelt an dem wir kleinertest erstellt haben. Snapshots lassen sich auch separat mit zfs list -t snapshot anzeigen

[root@itzkoatl:user1]> zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
tank/home/user1@kleinertest 0 - 29.1K -
tank/home/user2@kleinertest 0 - 27.6K -

Wie man sieht waren in unserem dump sogar alle Snapshots des Filesystems erhalten (user2 hat ebenfalls einen Snapshot kleinertest)

Import und Export

Filesysteme müssen manchmal mobil sein, z.b. wenn sie auf USB-Sticks liegen. Hierzu kann man zpools einfach exportieren. Exportierte zpools sind ohne das man sie wieder importiert nicht benutzbar (sie werden auch automatisch ausgehängt etc). Steckt man z.b. einen USB-Stick mit einem zpool in das System ein, reicht unter Solaris ein zpool import und alle exportierten Ports werden angezeigt. Ohne Paramter durchsucht dieser Befehl automatisch alle Datenträger nach exportierten zpools im /dev Filesystem.
Da unsere disk Dateien jetzt aber keine echten Devices sind müssen wir den Ort an dem zpool import suchen soll explizit angeben.

[root@itzkoatl:~]> zpool export tank
[root@itzkoatl:~]> zpool import -d ./zfsdemo
pool: tank
id: 14691414290482700440
state: ONLINE
action: The pool can be imported using its name or numeric identifier.
config:

tank ONLINE
raidz2 ONLINE
/export/home/raichoo/zfsdemo/disk1 ONLINE
/export/home/raichoo/zfsdemo/disk2 ONLINE
/export/home/raichoo/zfsdemo/disk3 ONLINE
/export/home/raichoo/zfsdemo/disk4 ONLINE
[root@itzkoatl:~]> zpool import -d ./zfsdemo tank


Das war ein kleiner aber recht umfangreicher Ausflug in die Welt von ZFS. Und vielen dürfte jetzt klar sein das ZFS mehr ist als nur Volumemanager und Filesystem in einem, es ist ein Storage Verwaltungstools. ZFS ist inzwischen neben Solaris auf FreeBSD, MacOSX und Linux (nur über FUSE) verfügbar. An weiteren Ports wird gearbeitet.

Sonntag, 3. August 2008

Dtrace überall

In den letzten Jahren hat dtrace, das dynamische Tracingtool von OpenSolaris, für eine Menge aufsehen gesorgt und inzwischen findet es auf immer mehr Plattformen ein zuhause. Ports existieren bereits für Mac OS X und QNX. Derzeit werden auch vom FreeBSD (man munkelt auch über einen NetBSD Port) Team Anstrengungen unternommen es zu portieren und vor einigen Monaten wurde der erste Code in den CURRENT Zweig commited.
Unter Linux gab es allerdings Probleme da die CDDL-Lizenz, unter der dtrace steht, nicht kompatibel zur GPL ist. Es wurden zwar mit systemtap Ansätze unternommen dtrace zu kopieren, doch ist es in keiner Weise vergleichbar da es unter anderem nicht in der Lage ist Userspace Prozesse zu tracen und die Stabilität des Systems beeinträchtigt da unter anderem das "Skripten" welches fast C ähnlich ist, völlig über das Ziel hinausschiesst und gefährlichen Code ermöglicht. Inzwischen ist das ftrace-Framework im Gespräch welches aber im Gegensatz zu dtrace und systemtap nicht skriptbar ist und damit extrem an Flexibilität einbüßt. Alles in allem eher spärliche Aussichten. Für ein Licht am Ende des Tunnels sorgt Paul Fox der sich daran gemacht hat dtrace auf Linux zu portieren. Ob es letztendlich möglich sein wird Linux Distributionen mit dtrace auszuliefern kann ich derzeit leider nicht sagen (da mir der ganze Lizenzkram langsam eh zu undurchschaubar wird), aber es bleibt die Hoffnung das es wenigstens ein Patchset geben wird das dieses unglaublich mächtige Tool in die Linuxwelt bringen wird.

Mittwoch, 23. Juli 2008

KDE4 unter FreeBSD

Letzte Woche war es soweit: Für all die, denen kompilieren immer zu mühseelig ist, gibt es seit Donnerstag KDE4 Pakete für FreeBSD. Das Ganze dient derzeit noch zum testen, läuft aber bis auf einige Kleinigkeiten ziemlich rund. Die Porter rufen derzeit zur regen Bugjagd auf um KDE4 für FreeBSD fit zu machen.



Vielen Dank an Miwi fürs portieren und die Starthilfe ;)

Dienstag, 8. Juli 2008

Freie Betriebssysteme: Ein Vergleich

Ich habe mich in den letzten Monaten mal etwas mehr mit dem befasst was der Markt an freien Betriebssystemen alles so hergibt. Deswegen habe ich mich hier mit den Alternativen FreeBSD und OpenSolaris befasst. Sicherlich bin ich nicht so weit in die unterschiedlichen Systeme eingetaucht das ich einen wirklich allumfassenden Bericht abliefern könnte aber ich hoffe trotzdem einen kleinen Einblick geben zu können.
Ich werde im folgenden einfach mal einen Vergleich zwischen den 3 Systemen anstellen die ich hier hauptsächlich laufen habe: Kubuntu 8.04.1, FreeBSD 7.0-RELEASE-p2 und OpenSolaris 2008.05 snv_91.

Packaging System


Kubuntu:

Hier kommt das weitverbreitete APT System aus der Debianwelt zum Zuge. Zusammen mit einer fast unerschöpflichen Auswahl an Paketen ist es sicher absolut ungeschlagen wenn es um eine Kollektion freier Software geht. Es ist schnell und leicht in der Anwendung und durch zusätzliche Repos flexibel und erweiterbar. Ein Nachteil den ich persönlich empfinde ist, das das selber packen ziemlich umständlich ist im Vergleich zu anderen Systemen. Es gibt mehrere Skriptverfahren zur Auswahl mit denen man seine Software verschnüren kann und zusätzlich noch Prä- und Postinstallationsskripte welche sich darum kümmern die Software einzurichten.
Fazit: +

FreeBSD:
Hier scheiden sich bei mir die Geister. Sicherlich ist das Ports-System von FreeBSD sehr mächtig und steht mit einer Auswahl von 18.000+ Paketen sicherlich nicht schlechter da als viele andere Systeme, doch ist die Handhabung meiner Meinung nach alles andere als zeitgemäß. Es gibt einen ganzen Berg an Tools für den Umgang mit diesem System und viele davon machen das gleiche... nur anders. Die pkg_* Familie (die jetzt nicht direkt was mit den Ports zu tun hat, sondern dafür zuständig ist vorkompilierte Pakete zu verwalten), dazu portsnap, portmaster, portupgrade, portaudit und vermutlich noch andere die ich vergessen oder noch nie gesehen habe. Es ist allerdings sehr einfach seine Software selbst zu kompilieren und gegebenenfalls auf seine Ansprüche zuzuschneiden. Dennoch:
Fazit: --

OpenSolaris:
Ian Murdock, Vater der Debian Distribution und inzwischen Mitarbeiter von Sun hat für OpenSolaris das IPS System entwickelt. Es ist komplett in Python geschrieben und versucht die Vorteile vieler Packagesysteme zu vereinigen. Besonders interessant ist das IPS vor jedem Update einen Snapshot des Systems anlegt, was dem Benutzer ermöglicht zurückzuspringen wenn z.B. das Update nicht geglückt ist. Auch lässt sich das System "branchen" so das man unterschiedliche Instanzen seines Systems gleichzeitig auf der Festplatte haben kann (alle bootbar). Gespeichert werden lediglich die Unterschiede zueinander und das völlig transparent und performant. All diese Optionen lassen sich mit wenigen einfachen Befehlen steuern. Auch hier gibt es Repos die das System flexibeler machen (auch ist das Aufsetzten eines eigenen Repos kinderleicht). Selbst Pakete bauen ist ebenfalls einfach und bequem realisiert, da sie ähnlich wie die Handhabung eines SVN abläuft.
Fazit:++

Filesystem

Kubuntu:
Ext3. Der Fels in der Brandung und leider auch genauso aktuell. Sicherlich zeichnet es sich durch hervorragende Stabilität aus dennoch sind die immer wiederkommenden Filesystem-Checks bei immer größer werdenden Festplatte einfach nur noch zeitaufwendig und lästig. Ebenso ist das System nach dem Aufsetzen starr und lässt sich nur bei einem vorher aufgesetztem LVM halbwegs elegant erweitern. Derzeit befindet sich ext4 in der Entwicklung, aber auf einen produktiven Einsatz wird man wohl noch lange warten müssen.
Fazit:-

FreeBSD:
Vorteilhaft ist hier das der Filesystemcheck bei UFS2 im Hintergrund abläuft. Das spart Zeit und Nerven (vor allem bei großen Platten welche heutzutage einfach Standard sind). Leider habe ich mich nicht besonders mit dem GEOM System befasst welches ein sehr starkes Konzept zu seinen scheint. Darum kann ich hierzu leider nicht viel sagen.
Fazit:+

OpenSolaris:
The Last Word in Filesystems. Damit preist Sun sein Filesystem ZFS an. Nicht ganz zu unrecht. Scheint es doch nichts zu geben was ZFS nicht bewerkstelligen kann: Softwareraids, Mirroring, Striping, dynamisch wachsenden Partitionen, Snapshots, Clones, inkrementelle Backups die sich über SSH verschicken lassen, transparente Kompression und sogar Selbstheilung. ZFS ist wie viele sagen eine eierlegende Wollmilchsau. Jetzt mag man glauben das sich ein solches Filesystem kaum handhaben lässt und ungemein kompliziert ist. In Wirklichkeit lassen sich alle diese Funktionen mit nur 2 einfachen Befehlen steuern ohne dabei irgendetwas von ihrer Mächtigkeit zu verlieren. Alles in allem: Ein hochmodernes einfach handzuhabendes Filesystem welches einem völlig neue Möglichkeiten eröffnet.
Fazit: ++

Kernel und Userland

Kubuntu:

Hier wird wie die meisten sicher wissen der weit verbreitete Linuxkernel verwendet. Er verfügt über eine große Anzahl an Treibern und ist relativ stabil. Als Userland wird das GNU-Userland verwendet welches vom Linuxkernel eigentlich unabhängig ist. Dies führt dazu das sich beides hin und wieder nicht im Einklang befindet, sprich das neue Features des Kernels sich nicht unbedingt auf das Userland auswirken. Auf großen Systemen wird allerdings immer wieder bemängelt das der Linux Kernel schlecht skaliert (ab 4 oder 8 CPUs geht die Performance bergab) Dies kann ich selber nicht bestätigen sondern muss mich hier auf das Wort von Experten verlassen.
Fazit: +

FreeBSD:

Wie bei allen anderen BSDs auch kommt hier alles aus einem Guss. Userland sowie Kernel werden zusammen entwickelt und dementsprechend lässt sich das System erstklassig darüber bedienen. Im Gegensatz zum Linuxkernel handelt es sich beim FreeBSD Kernel um einen echten Nachkommen von BSD Unix. Derzeit werden viele neue Fähigkeiten die ihren Ursprung in Solaris in den FreeBSD Kernel integriert wie z.b. ZFS und dtrace (beides ist unter Linux derzeit aus Lizenzgründen nicht möglich). Das System soll sich durch extreme Stabilität auszeichnen. Dennoch habe ich es geschafft durch vermutlich etwas dämlichen Einsatz zum UnionFS das System zu einer Panic zu bringen. Auch skaliert das System durch den neuen ULE Scheduler (welcher auch in den nächsten Mac OS X Kernel aufgenommen werden soll) sehr gut.
Wie Linux auch verfügt FreeBSD über eine Vielzahl von Treibern und auch NVidia liefern einen Treiber für ihre Grafikkarten (allerdings nur als 32-Bit Version) aus.
Fazit:++

OpenSolaris:
Auch hier ist alles aus einem Guss und durch dtraceprobes lässt sich dem System so ziemlich alles an Informationen entlocken die man zum administrieren und entwickeln so braucht oder immer schon mal haben wollte. Da das Geschäft von Sun große Rechner sind, verwundert es nicht das Solaris extrem gut skaliert und auch noch auf Systemen mit vielen CPUs (angeblich bis zu 64 Stück) ohne Performanceverlust arbeitet. Solaris verfügt über eine Vielzahl einzigartiger und mächtiger Tools und Features (ZFS, dtrace, SMF, Zones etc) welche sowohl auf dem Desktop als auch auf dem Server neue und spannende Anwendungen eröffnen. Um Treiber ist es im Moment etwas schlecht bestellt, dennoch werden alle paar Wochen neue Treiber zum System hinzugefügt. Auch hier bieten NVidia Treiber für ihre Grafikkarten an. Solaris stammt ebenfalls von BSD ab und ist somit ein echtes Unix.
Fazit:++

Oberfläche

Kubuntu:
Wird standardmäßig mit KDE ausgeliefert, ebenso existiert eine KDE4 Version welche
jedoch eher für Entwickler und nicht für den Endanwender gedacht ist.
Fazit:++

FreeBSD:
Kommt ohne installierte GUI und läßt sich somit frei einrichten. Derzeit wird noch an einer Portierung von KDE4 gearbeitet die nach Aussage von Martin Wilke inzwischen kompiliert und läuft.
Fazit:+

OpenSolaris:
Ist derzeit nur mit Gnome erhältlich, dennoch wird auch hier KDE4 portiert. Experimentelle Tarballs sind bereits unter www.bionicmutton.org/solaris/ erhältlich. Ab der kommenden Version von OpenSolaris soll es möglich sein auf die Installation einer GUI zu verzichten.
Fazit:+

Dokumentation

Linux:
Eine wirklich gute Anlaufstelle für Dokumentation gibt es für Linux leider nirgends. Es gibt zwar viele Wikis von denen sehr viele veraltet sind. Oft muss man sich passende Howtos per Google raussuchen welche auch selten über Grundwissen hinausgehen. Auch macht es einem die Menge an unterschiedlichen Distributionen welche Probleme oft sehr unterschiedlich behandeln alles andere als leicht.
Fazit:--

FreeBSD:
FreeBSD bietet auf seiner Seite ein umfangreiches Handbuch an welches so ziemlich jedes Thema abdeckt auf das man beim benutzen und administrieren seines Systems stoßen kann. Alles ist umfassend erklärt und in unterschiedlichen Sprachen erhältlich.
Fazit:+

OpenSolaris:
Besonders angetan hat er mir der Dokumentationsserver von Sun. docs.sun.com bietet so ziemlich die ausführlichste Datenbank an Informationen die man zu einem System erhalten kann. Alles als PDF herunterladbar, sowie in mehreren Sprachen verfügbar. Alles auf dem neusten Stand versteht sich. Absolut vorbildlich!
Fazit:++

Wenn es um Paketvielfalt und Einfachheit geht, hat hier Kubuntu ganz klar das Rennen gemacht. Dennoch halte ich OpenSolaris für einen extrem vielversprechenden Kandidaten (vor allem da das System in dieser Form erst seit 3 Monaten erhältlich ist). Mit mehr Paketen würde es sich hier definitiv um eine ernstzunehmende Alternative handeln. FreeBSD taugt für mich leider gar nicht für den Desktop (Ok, der Vergleich ist schon etwas unfair da es eher für Server gedacht ist ;). PC-BSD soll hier allerdings Abhilfe schaffen.

Das war ein kleiner Einblick in das von mir Erlebte zu den unterschiedlichen Systemen. Sicherlich wird das ein oder andere Urteil etwas sehr subjektiv ausgefallen sein, aber naja. Ich hoffe es war trotzdem aufschlussreich :).

Informationen zu den unterschiedlichen Systemen wie z.B. ausgewählte Artikel findet man übrigens auch bei Distrowatch.