poniedziałek, 24 maja 2010

rwące potoki

Każdy elementarz UNIX-a opisuje mechanizm potoków. Przypomnijmy, że potokiem łączymy 2 strumienie: standardowe wyjście stdout jednego programu ze standardowym wejściem stdin drugiego. Standardowe wyjście błędów stderr domyślnie nie trafia do potoku, co można zaobserwować w niektórych programach robiąc program --help | more i klnąc, że 3 strony pomocy przeleciały nam przez ekran niepowstrzymane. ;)

Istnieje kilka narzędzi, które można wykorzystać do zmierzenia i wizualizacji wolumenu danych płynących potokiem, a nawet do ograniczenia natężenia:
Są one często dostępne w standardowym repozytorium pakietów oprogramowania.

Przy ich pomocy można "zobaczyć", jak szybko przetwarzane są dane np. podczas obliczania sumy kontrolnej pliku. Można też zobaczyć na bieżąco, jak dane na wejściu kompresują się po przejściu przez archiwizer. Można wreszcie spowolnić przesyłanie danych, aby zmniejszyć wykorzystanie zasobów systemu (np. sieci, jeśli w potoku uczestniczy program sieciowy) lub... po prostu wyświetlać animację w ASCII. ;)

Przykłady? Dla testu wyślę do potoku dane pobrane dd z generatora liczb pseudolosowych urandom (o nieco niższej jakości, ale za to nieblokującego po wyczerpaniu entropii). Następnie spróbuję ograniczyć prędkość, z jaką pobieram pseudolosowe dane.


$ dd if=/dev/urandom bs=1M count=10 | pipebench > /dev/null
10+0 records in  9.37 MB    6.25 MB/second (Sun May 23 13:24:40 2010)
10+0 records out
10485760 bytes (10 MB) copied, 1,52052 s, 6,9 MB/s
Summary:
Piped   10.00 MB in 00h00m01.52s:    6.55 MB/second



$ dd if=/dev/urandom bs=512k count=1 | cpipe -vr -vt -vw -ngr -s 100 > /dev/null
in:  96.327ms at    1.3MB/s (   1.3MB/s avg)  128.0kB
out:   0.002ms at   61.0GB/s (  61.0GB/s avg)  128.0kB
thru: 1256.614ms at  101.9kB/s ( 101.9kB/s avg)  128.0kB
in:   0.266ms at  469.9MB/s (   2.6MB/s avg)  256.0kB
out:   0.002ms at   61.0GB/s (  61.0GB/s avg)  256.0kB
thru: 1257.576ms at  101.8kB/s ( 101.8kB/s avg)  256.0kB
in:   0.220ms at  568.2MB/s (   3.9MB/s avg)  384.0kB
out:   0.003ms at   40.7GB/s (  52.3GB/s avg)  384.0kB
thru: 1260.403ms at  101.6kB/s ( 101.7kB/s avg)  384.0kB
1+0 records in
1+0 records out
524288 bytes (524 kB) copied, 3,77087 s, 139 kB/s
in:   0.985ms at  126.9MB/s (   5.1MB/s avg)  512.0kB
out:   0.003ms at   40.7GB/s (  48.8GB/s avg)  512.0kB
thru: 1262.864ms at  101.4kB/s ( 101.6kB/s avg)  512.0kB
in:   0.005ms at       0B/s (   5.1MB/s avg)  512.0kB   (bsize=0)
out:   0.001ms at       0B/s (  44.4GB/s avg)  512.0kB
thru:   0.055ms at       0B/s ( 101.6kB/s avg)  512.0kB



$ dd if=/dev/urandom bs=1M count=1 | pv -L 100K > /dev/null
90kB 0:00:03 [ 101kB/s] [ <=> ]


Potoki mogą też być nazwane - widnieją wówczas w systemie plików jako plik typu FIFO i możemy do nich zapisywać dane jak do każdego innego pliku. Różnica jest taka, że zapis będzie blokujący tzn. będzie czekał, aż "z drugiej strony" do potoku nie podłączy się konsument.


$ mkfifo pipe1 pipe2
$ ls -las pipe*
0 prw-r--r-- 1 blog blog 0 maj 24 22:33 pipe1
0 prw-r--r-- 1 blog blog 0 maj 24 22:33 pipe2



$ echo "zapis do potoku w tle" > pipe1 &
[1] 2834
$ cat pipe1
zapis do potoku w tle
[1]+  Done                    echo "zapis do potoku w tle" > pipe1

$ cat pipe1 &
[1] 2836
$ echo "zapis do potoku czytanego w tle" > pipe1
zapis do potoku czytanego w tle
[1]+  Done                    cat pipe1


Tak uzbrojeni możemy sięgnąć po narzędzie do rozszczepiania potoku, czyli tee. tee przepuszcza swoje wejście na wyjście, ale robi kopię danych i wysyła do wskazanego pliku.


$ echo DANE TESTOWE | tee kopia-strumienia
DANE TESTOWE
$ cat kopia-strumienia
DANE TESTOWE


Przy pomocy tee można np. kompresować plik i jednocześnie liczyć sobie sumę kontrolną pliku wynikowego "w trakcie".

W szczególności plik podany tee może być potokiem nazwanym, czyli strumień trafi do 2 potoków jednocześnie.


$ echo DANE TESTOWE | tee pipe1 | sed s/DANE/POTOCZYSCIE/ &
[1] 2932
$ cat pipe1
POTOCZYSCIE TESTOWE
DANE TESTOWE
[1]+  Done                    echo DANE TESTOWE | tee pipe1 | sed s/DANE/POTOCZYSCIE/


Świetnie, a czy da się np. zamienić miejscami strumień stdout i stderr? Albo czy da się otworzyć więcej niż te dwa standardowe strumienie? Oczywiście. :)

Dla przypomnienia: proces ma listę otwartych deskryptorów. Standardowo mamy otwarte:
  • deskryptor 0, czyli stdin
  • deskryptor 1, czyli stdout
  • deskryptor 2, czyli stderr
Możemy otworzyć kolejne. W przypadku powłoki bash, robimy to np. następująco (do czytania):


$ echo DANE > myfile
$ cat <&3
DANE


No to zamieńmy miejscami stdout i stderr:


$ echo DANE | grep -v DANE
$ echo DANE 3>&1 1>&2 2>&3 | grep -v DANE
DANE


A jeśli naotwieramy więcej deskryptorów, to czy da się jakoś operować więcej niż na parze z nich? Z pomocą przychodzi narzędzie multitee.


$ echo DANE1>plik1
$ echo DANE2>plik2
$ echo DANE3>plik3
$ exec 3wyjscie1
$ exec 7>wyjscie2
$ exec 8>>wyjscie3
$ echo WEJSCIOWE | multitee 0:6,7,8 3:8 4:8 5:6
$ cat wyjscie1
DANE3
WEJSCIOWE
$ cat wyjscie2
WEJSCIOWE
$ cat wyjscie3
DANE2
DANE1
WEJSCIOWE



Na koniec pozostaje pozamykać deskryptory:


$ exec 3>&-
itd.

środa, 19 maja 2010

Wydano OpenBSD 4.7

Wydano dziś wersję 4.7 systemu OpenBSD.

Miło jest patrzeć, jak ten niszowy system - zwany żartobliwie małym, kolczastym zjadaczem sprzętowych ruterów ;) - z wersji na wersję zyskuje kolejne interesujące funkcjonalności w zakresie obsługi sieci. Warto także zwrócić uwagę na dołączone OpenSSH 5.5.

Wielkim atutem OpenBSD jest to, że przychodzi jako nieduży, silnie zintegrowany, dobrze udokumentowany, spójny pakiet oprogramowania, pozwalający postawić zaawansowany firewall, ruter i koncentrator VPN-ów IPsec dosłownie w kilka minut po instalacji. I to wszystko z redundancją na wielu poziomach: agregacją portów Ethernet, redundancją adresu IP (CARP), synchronizacją stanów firewalla i kanałów IPsec. Sam firewall jest również bardzo przyjemny w konfiguracji, składnia pf pozwala na zwięzłe wyrażanie złożonych polityk oraz klasyfikowanie pakietów także po danych pobranych z tablicy rutingu, np. numerach systemów autonomicznych BGP - albowiem obsługa m.in. tego protokołu rutingu jest również zaimplementowana.

Być może w jednym z kolejnych wpisów poświęcę OpenBSD nieco więcej uwagi.

wtorek, 18 maja 2010

Open Source Day 2010

Kilka dni temu miałem sposobność uczestniczyć w konferencji Open Source Day 2010. Tego typu imprezy służą oczywiście głównie promowaniu firm je organizujących. Liczba słuchaczy była całkiem duża (na pewno przekraczała 500), co może świadczyć o magnetyzmie:
  • darmowego obiadu,
  • osoby premiera Pawlaka, lub
  • rozwiązań open source dla biznesu.

Niewątpliwie w czasach kryzysu i napiętych budżetów rozwiązania open source zyskały więcej uwagi. Jesteśmy świadkami zderzenia dwóch odmiennych koncepcji biznesowych: gigantów wyrosłych na kosztownych, zamkniętych aplikacjach i podgryzających coraz śmielej ich kostki agresorów uzbrojonych w niskokosztowe, zwinne rozwiązania i wsparcie społeczności. Nie jest to zderzenie widowiskowe, przypomina raczej ruchy górotwórcze. Czas i procent składany robią jednak swoje. Jeszcze kilkanaście lat temu instalując hobbystycznie mego pierwszego Linuksa (Red Hat 3.0.3) dziwiłem się, że nie ma w tym systemie ograniczenia liczby jednocześnie pracujących użytkowników...

Po latach sukcesy na polu systemów operacyjnych są szczególnie widoczne. Jestem bardzo ciekaw, czy i jak szybko podobne sukcesy pojawią się w obszarze relacyjnych baz danych klasy enterprise. Jak sam stwierdził przedstawiciel EnterpriseDB, na tym polu jeszcze wiele do zrobienia. (Ale nazwę mają już dobrą;)).

Jak zauważył przedstawiciel Red Hata, firmy oferujące wsparcie dla rozwiązań open source mają silną motywację by dbać o jakość, bo koszt wyjścia jest w ich przypadku bardzo niski. (Wystarczy nie kupować komercyjnego wsparcia i korzystać z edycji wspieranych przez społeczność, np. CentOS).

Chciałbym zwrócić uwagę na jeszcze jeden aspekt wzrostu popularności wolnodostępnego oprogramowania: tworzenie oprogramowania często traci sens i podstawy ekonomiczne. Jeśli chcesz napisać jakąś aplikację, sprawdź najpierw, czy ktoś już nie zrobił tego wcześniej i nie wrzucił na sourceforge'a. ;) Spróbuj zrobić program do słuchania mp3, przeglądania obrazków, serwer WWW, klienta poczty albo edytor tekstu i go z sukcesem sprzedać. Wiem, że można. Ale kiedyś można było bardziej - bo nie było dobrej alternatywy. Dziś na moim komputerze osobistym nie ma ani jednej płatnej aplikacji (poza samym systemem). Antywirus, firewall, archiwizer, program do nagrywania płyt, pakiet biurowy, przeglądarka zdjęć, szyfrator dysku i klienty popularnych usług internetowych - wszystko za darmo, część w modelu open source.

wtorek, 11 maja 2010

knowledge sharing

Niektórzy specjaliści IT uważają się za niezastąpionych. Istotnie, niektórzy wybitnymi fachowcami.

Niestety, trudność z zastąpienia ich nie zawsze wynika li tylko z ich kompetencji, ale także z tego, że zazdrośnie strzegą swej wiedzy i nie dokumentują pracy.


Tego typu postawa może wynikać z różnych przyczyn. Chyba najbardziej typowe to:
  • Zazdrość, że sami ponieśli duży nakład pracy na naukę, a inni mieliby tę wiedzę otrzymać "na talerzu".
  • Chęć utrzymania uprzywilejowanej pozycji poprzez niedopuszczanie konkurencji.
  • Lenistwo - "po co to dokumentować, każdy może sobie przejrzeć listę procesów i przegrepować /etc", "to oczywiste" itd.

Nikt nie oczekuje, że ekspert podzieli się całą swoją wiedzą za darmo. Ale sytuację, w której tego typu postawy blokują upowszechnienie wiedzy w zakresie potrzebnym do pracy zespołu, uważam za szkodliwą.

Miałem kiedyś przyjemność kierować zespołem administratorów IT. Wiedza o utrzymywanych systemach była rozproszona w głowach różnych osób, w tym także byłych pracowników. :) Kilkugodzinny czas rozwiązania awarii z SLA był nie do utrzymania.

Jednym z moich pierwszych ruchów było wprowadzenie wiki i zachęcenie zespołu do dokumentowania utrzymywanych systemów: stanu obecnego (AS-IS) oraz Przypadków Użycia dotyczących tych systemów (np. cykliczne czynności administracyjne lub sposób rozwiązywania typowych zgłoszeń dotyczących danego systemu). Chodziło o osiągnięcie stanu, w którym każdego można zastąpić - przynajmniej krótkookresowo.

Zalety wiki to m.in.
  • łatwość edycji dokumentów - klikasz "edytuj" i piszesz, nie myślisz o rozdziałach, czcionkach itd.
  • tworzenie sieci powiązanych dokumentów - wiki rośnie za "skojarzeniami", w miejscach gdzie są najbardziej palące braki
  • brak rygoru co do struktury i kompletności - dokument może mieć na początku kilka zdań i stopniowo się rozrastać
  • podążanie za zmianami w systemach - klasyczna dokumentacja projektowa jest bardzo obszerna i ma tendencję do utraty aktualności

Zebranie głównej wiedzy operacyjnej na wiki pozwoliło na jej upowszechnienie w świadomości administratorów i podniosło jakość usług świadczonych przez zespół. To z kolei umożliwiło swobodniejsze planowanie dyżurów oraz urlopów. Nie zagroziło zaś niczyjej pozycji zawodowej. :) Ułatwione było także wdrażanie nowych pracowników - zamiast pytać o wszystko bardziej doświadczonych kolegów, poszukiwania wiedzy rozpoczynali od wiki.

niedziela, 9 maja 2010

elastyczność nie zawsze jest atutem

Jednym z oczywistych atutów rozwiązań opartych o platformę PC i otwarty system operacyjy klasy UNIX jest ich niski koszt i elastyczność.

Potrzebujesz zrobić coś nietypowego? Masz rozwiązanie pudełkowe - masz problem. Masz Linuksa lub BSD? - wydziergasz sobie wszystko, choćby trzeba było zniżyć się do edycji poziomu kodu źródłowego.

Elastyczność stwarza jednak pokusę, by tworzyć rozwiązania nietypowe i skomplikowane. Pokusa ta jest silna zwłaszcza dla fanów tych systemów, który lubią udowadniać otoczeniu, że ich system może robić dosłownie wszystko.

Póki autor rozwiązania jest jedyną osobą skazaną na bezpośrednie obcowanie z nim, nie jest to wielki problem. Schody zaczynają się, gdy trzeba je później utrzymywać lub pielęgnować rękami innych pracowników.

Okazuje się, że wniesiona dodatkowa komplikacja może skutkować wzrostem nakładów czasu potrzebnych później do jej zrozumienia przez inne osoby, a koszt tego czasu może przekroczyć uzyskane wcześniej oszczędności.

Środowisko open source jest tego oczywiście świadome. Dlatego powstają rozwiązania specjalizowane, dystrybucje przeznaczone do użycia w ściśle określonej roli - zapory sieciowej, rutera, NAS-a itp. Celowo ograniczają one elastyczność systemów, na których je oparto. Użytkownik jest odcinany od powłoki, otrzymuje ograniczone CLI lub interfejs webowy. Sposób konfiguracji wzoruje się na rozwiązaniach pudełkowych. Wszystko po to, aby można się było skupić na prostym i szybkim dostarczeniu określonej funkcjonalności, bez wnikania, jak to jest zrobione "pod spodem". Nagle umniejszona elastyczność staje się nie wadą lecz atutem.


Podsumowując: wybór rozwiązań "ograniczonych" lub wręcz "drogich pudełek" dla wielu firm ma duży sens biznesowy, nawet jeśli z perspektywy fanboya systemu X nie zawsze da się go dostrzec.

sobota, 8 maja 2010

nasty filenames

Przyzwyczailiśmy się, że w nazwach plików występują głównie "normalne" znaki, z wyjątkiem ukośnika (separatora katalogów w ścieżce). Możliwe jest jednak wystąpienie innych znaków.

Stwórzmy katalog ze znakiem końca wiersza w środku jego nazwy. Dla odmiany po poprzednim wpisie użyjmy Perla.

linux$ perl -e 'mkdir("prefix\nsuffix")'


Co możemy powiedzieć o naszym dziele?

linux$ ls
prefix?suffix
linux$ ls | cat
prefix
suffix


Wygląda podejrzanie. Ma to pewne implikacje nie tylko dla mechanizmu autouzupełniania powłoki :) ale także dla innych aplikacji:

linux$ find . -type d -name 'prefix*' | xargs rmdir
rmdir: nie udało się usunąć `./prefix': Nie ma takiego pliku ani katalogu
rmdir: nie udało się usunąć `suffix': Nie ma takiego pliku ani katalogu


Po to właśnie wymyślono opcję użycia znaku NULL jako separatora wierszy:

linux$ find . -type d -name 'prefix*' | xargs printf "received [%s]\n"
received [./prefix]
received [suffix]
linux$ find . -type d -name 'prefix*' -print0 | xargs -0 printf "received [%s]\n"
received [./prefix
suffix]


Teraz już możemy bezpiecznie i skutecznie usunąć katalog.

linux$ find . -type d -name 'prefix*' -print0 | xargs -0 rmdir
linux$ ls
linux$


Na marginesie: spotkałem się kiedyś z komercyjnym UNIX-em, który zwyczajnie nie wspierał takich opcji w find i xargs. :)

Wniosek z tego płynie taki: jeśli przetwarzasz wynik dowolnych poleceń zwracających nazwy plików, lepiej nie polegaj na znaku końca wiersza jako faktycznym znaczniku końca linii. Możesz ryzykować nie tylko załamaniem procesu przetwarzania, ale także stworzyć zagrożenie.

Co by się stało, gdybyśmy tu mieli xargs rm -rf?

linux$ perl -e 'mkdir("prefix\n..")'
linux$ find . -type d -name 'prefix*' | xargs printf "received: [%s]\n"
received: [./prefix]
received: [..]


Potrzeba czujności nie dotyczy tylko skryptów powłoki, ale także np. logów. Wiele aplikacji prowadzi logi tekstowe, które parsuje się później wiersz po wierszu. Jeśli aplikacja wpisuje do loga nazwę pliku, może się okazać, że ten konkretny wpis został podzielony na wiele wierszy. Tego typu zachowanie zaobserwowałem kiedyś w logach serwera aplikacyjnego JEE: aplikacja przetwarzała pliki ze spoola i odkładała w logach ślad swojej pracy, w tym nazwę otwieranego pliku.

piątek, 7 maja 2010

unix time

Systemy uniksowe tradycyjnie reprezentują czas jako liczbę sekund, które upłynęły od czasu t0 równego 1970-01-01 00:00:00 UTC (tzw. Epoch).

Większość aplikacji formatuje znaczniki czasu do postaci strawnej dla człowieka. Czasem jednak pojawia się konieczność przeanalizowania danych bardziej niskopoziomowych, w których znajdziemy znacznik czasu w postaci surowej.

Jak szybko dokonać konwersji w jedną i drugą stronę? Choćby przy pomocy Perla. A bez Perla da się? Da się. Otóż można do tego celu użyć po prostu polecenia... date.

Implementacja date różni się między systemami. Zauważmy na przykład, że w GNU date czas sekundowy należy poprzedzić znakiem @ (nie ma tego w podręczniku ekranowym man, ale jest w info).


Konwersja czasu na format uniksowy:

freebsd$ date -j -f "%Y-%m-%d %H:%M:%S" "2010-05-07 02:34:59" "+%s"
1273192499

linux$ date -d "2010-05-07 02:34:59" +%s
1273192499

Konwersja czasu z formatu uniksowego:

freebsd$ date -j -f "%s" 1273192499
ptk 7 maj 02:34:59 2010 CEST

linux$ date -d @1273192499
pią, 7 maj 2010, 02:34:59 CEST

A gdybyśmy chcieli przetworzyć format sekundowy jako jeden z elementów wiersza podanego w potoku? Z pomocą może przyjść choćby GNU awk:

$ echo 1273192499 | gawk '{print strftime("%c", $1)}'
pią, 7 maj 2010, 02:34:59

Niestety, nie każdy system (i nie każda dystrybucja Linuksa) ma domyślnie zainstalowane GNU awk.

Na koniec warto wspomnieć o wygodnych podróżach w czasie, które umożliwia nam date na FreeBSD przy pomocy opcji -v.

Aby ustalić ostatni poniedziałek przyszłego miesiąca:
  1. ustawiamy się na pierwszym dniu obecnego miesiąca
  2. przeskakujemy o 2 miesiące do przodu
  3. cofamy się o jeden dzień (na ostatni dzień miesiąca poprzedniego)
  4. cofamy się, aż znajdziemy poniedziałek 
freebsd$ date -v1d -v+2m -v-1d -v-mon
pon 28 cze 17:06:13 2010 CEST




Więcej informacji: