zram – ratunek na drogi RAM

W połowie poprzedniego roku chodził mi po głowie pomysł, żeby w prywatnym desktopie wymienić pamięć z 32 GiB na 64 GiB albo nawet 128 GiB, nie dlatego żebym tego potrzebował, raczej na zapas. Przy obecnych cenach RAM-u taki zakup mocno odbił by się na kieszeni, więc mam nadzieję, że nie będę do niego zmuszony.

Być może ratunkiem na drogi RAM jest zram czyli moduł jądra Linux, który pozwala tworzyć urządzenia blokowe w RAM-ie, których zawartość jest kompresowana w locie. Jednym z zastosowań takiego rozwiązania jest utworzenie skompresowanej przestrzeni wymiany w RAM-ie. Sens tego jest taki, że w momencie gdy system zaczyna swapować to używa do tego szybkiego RAM-u, ale dzięki kompresji potrzebuje go wyraźnie mniej.

Od początku grudnia testuję zram na trzech komputerach (dwa razy Debian, jedno Ubuntu). Póki co jestem pod wrażeniem tego rozwiązania, bo odczuwalnie przesuwa granicę wykorzystania pamięci RAM, przy którym używanie komputera jest komfortowe. Jednocześnie jak dotąd nie zauważyłem żadnych problemów wynikających z używania zram.

Przykładowo, na służbowym laptopie z 32 GiB RAM -u po przekroczeniu 26 GiB system zaczynał zrzucać pamięć na dysk, ale bez odczuwalnego spowolnienia, a powyżej 30 GiB cały system stawał się mniej responsywny. Po włączeniu zram nawet przy wykorzystaniu 35 GiB pamięci system wciąż działa płynnie.

Stopień kompresji przy użyciu algorytmu lz4 oscyluje w okolicach 3:1, zazwyczaj nieco powyżej, a czasami trochę mniej. Poniżej przykładowy wynik polecenia zramctl, które pokazuje aktualne statystyki:

NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram0 lz4          12,4G   6G  1,8G    2G      12 [SWAP]

Jak widać, aktualnie w przestrzeni wymiany jest 6 GiB danych, ale zajmują one tylko 1,8 GiB.

Póki co nie włączyłem zram na serwerach z Proxmoxem, bo doszukałem się informacji o potencjalnych problemach, a na szczęście do serwerów kupiłem RAM ze sporym zapasem kiedy był tani.

Mellanox ConnectX-3 nie działa z Debianem?

Oczywiście, że działa i to bez żadnych kombinacji. Poniżej opiszę dlaczego u mnie nie zadziałało i jak to naprawić.

Tytułem wprowadzenia, robię przymiarki do przyspieszenia sieci domowej do 10 Gb/s. Do komputera stacjonarnego kupiłem kartę Mellanox ConnectX-3 (MCX311A-XCAT) na PCI Express. Jakież było moje zdziwienie, kiedy po zainstalowaniu karty w komputerze i uruchomieniu Debiana po karcie nie było ani śladu. Nie to, że nie została rozpoznana czy nie został załadowany moduł jądra. Po prostu pustka, ani lspci ani dmesg nie pokazały żadnej informacji związanej z kartą. Oczywiście przeszedłem standardową procedurę od wyjęcia i ponownego włożenia karty do grzebanie w opcjach UEFI — na próżno.

Przełomem okazał się ten wątek na forum STH, a konkretnie informacja o zależności pomiędzy gniazdami M2 i slotami PCI Express. Sprawdziłem instrukcję do mojej płyty głównej MSI MAG B550 Tomahawk, a tam jak byk stoi, że w wypadku obsadzenia obu gniazd M2 trzeci slot PCI Express jest nieaktywny.

Po wyjęciu dysku z drugiego gniazda M2 i uruchomieniu Debiana wszystko było na swoim miejscu. Polecenie lspci -k pokazało:

04:00.0 Ethernet controller: Mellanox Technologies MT27500 Family [ConnectX-3]
	Subsystem: Mellanox Technologies ConnectX-3 10 GbE Single Port SFP+ Adapter
	Kernel driver in use: mlx4_core
	Kernel modules: mlx4_core

W ustawieniach systemu w zakładce Sieć pojawiło się nowe połączenie 10 000 Mb/s.

Podsumowując, karta sieciowa Mellanox ConnectX-3 działa z Debianem 12 bez żadnych kombinacji.

Zduplikowana nazwa grupy woluminów LVM

Podczas przenoszenia systemu na nowy dysk zafundowałem sobie mały problem: nazwałem grupę woluminów LVM tak samo jak na starym dysku. Kiedy do świeżo postawionego systemu podłączyłem stary dysk, żeby skopiować dane ów problem objawił się tak:

# vgscan
  Reading volume groups from cache.
  Found volume group "cherokee" using metadata type lvm2
  Found volume group "cherokee" using metadata type lvm2

Jak wiadomo, żeby aktywować LVM trzeba podać nazwę grupy woluminów, a skoro ta jest zduplikowana to jest to problem. Jego rozwiązaniem jest zmiana nazwy jednej z grup. Ja postanowiłem zmienić nazwę starej grupy.
Czytaj dalej „Zduplikowana nazwa grupy woluminów LVM”

Migracja repozytorium SVN do git

Młodsi stażem programiści pewnie tego nie pamiętają, ale kiedyś synonimem systemu kontroli wersji był Subversion. W dziewięciu na dziesięć przypadków podczas rozmowy kwalifikacyjnej należało się wykazać znajomością SVN-a.

Z tamtych czasów zostało mi kilka projektów w SVN-ie. Większość z nich już od dawna nie funkcjonuje, ale kilka wciąż żyje, np. acp czy ta strona. Raz na ruski rok coś w nich poprawiam, choć ze wstydem przyznaję, że robiłem to wprost na serwerze, bo przy wymianie domowego serwerka parę lat temu już nawet nie stawiałem serwera Subversion. Teraz jednak postanowiłem zrobić z tym porządek i przenieść kod do gita.

Czytaj dalej „Migracja repozytorium SVN do git”

Skype na Debianie

Swego czasu Skype na Linuksie (w tym na Debianie) był bardzo ułomny, dostępna była wyłącznie wersja 32-bitowa, a instalacja była upierdliwa. Między innymi dlatego starałem się unikać Skype’a.

Niedawno zostałem zmuszony do przeproszenia się ze Skype’em i ku memu zaskoczeniu okazało się, że Skype for Linux dojrzał. Ze strony można pobrać pakiet DEB, a instalacja sprowadza się do zwyczajowego:

dpkg -i /home/joe/Pobrane/skypeforlinux-64.deb

Instalator dodaje repozytorium do listy źródeł apta, ale nie pobiera klucza, więc po wykonaniu aptitude update pojawi się błąd:

W: Błąd GPG: https://repo.skype.com/deb stable InRelease: Następujące podpisy nie mogły zostać zweryfikowane z powodu braku klucza publicznego: NO_PUBKEY 1F3045A5DF7587C3
E: The repository 'https://repo.skype.com/deb stable InRelease' is not signed.
E: Failed to download some files
W: Nie udało się pobrać https://repo.skype.com/deb/dists/stable/InRelease: Następujące podpisy nie mogły zostać zweryfikowane z powodu braku klucza publicznego: NO_PUBKEY 1F3045A5DF7587C3
E: Nie udało się pobrać niektórych plików indeksu, zostały one zignorowane lub użyto ich starszej wersji.

Żeby go naprawić wystarczy pobrać klucz GPG:

curl https://repo.skype.com/data/SKYPE-GPG-KEY | apt-key add -

Sama aplikacja (w wersji 5.3.0.1) zdaje się działać poprawnie i stabilnie, niestety wciąż brakuje w niej niektórych funkcji, np. Udostępniania ekranu podczas rozmowy konferencyjnej.

Problem z repozytorium pakietów Opery

Przy próbie wykonania aktualizacji listy pakietów aptitude zakomunikował mi rzecz następującą:

E: The repository 'https://deb.opera.com/opera-stable stable Release' does no longer have a Release file.

Najwyraźniej w repozytorium Opery zaszły jakieś zmiany. Zajrzałem na adres repozytorium i faktycznie we wskazanym katalogu pliku Release nie było, ale za to w podkatalogu opera znajdowały się wszystkie niezbędne pliki. Wobec tego otworzyłem plik /etc/apt/sources.list.d/opera-stable.list i poniższą linijkę:

deb https://deb.opera.com/opera-stable/ stable non-free #Opera Browser (final releases)

zamieniłem na taką:

deb https://deb.opera.com/opera-stable/opera testing non-free

Po tym zabiegu aktualizacja przebiegła bez problemów.

Dodam, że korzystam z Debiana w wersji testing (obecnie stretch) i dlatego podałem taką dystrybucję.

PHP 7.0 na blogasku

Postanowiłem dać szansę PHP 7.0 na serwerze produkcyjnym, a konkretnie na WordPressie napędzającym tegoż blogaska. W końcu od premiery minęło jakieś dwa i pół miesiąca, w tym czasie bolączki wieku dziecięcego chyba powinny zostać wyeliminowane. Co więcej, próby na moich testowych maszynach wirtualnych nie wykazały żadnych problemów, za to pokazały wyraźne przyspieszenie.

Przesiadka jest łatwa i w pełni odwracalna, PHP 7.0 z dotdeb może działać równolegle do PHP 5.6 od Debiana, zatem wystarczy w konfiguracji vhosta zmienić ścieżkę do interpretera. Różnica w prędkości generowania stron jest wyraźnie odczuwalna organoleptycznie, ale jeśli do kogoś bardziej przemawiają liczby to poniżej wrzucam szybki test wykonany ab.

PHP 5.6

Server Hostname:        michal.durys.pl
Server Port:            80

Document Path:          /
Document Length:        65737 bytes

Concurrency Level:      4
Time taken for tests:   16.142 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      6594000 bytes
HTML transferred:       6573700 bytes
Requests per second:    6.20 [#/sec] (mean)
Time per request:       645.680 [ms] (mean)
Time per request:       161.420 [ms] (mean, across all concurrent requests)
Transfer rate:          398.93 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       11   11   0.6     11      17
Processing:   281  630 143.4    627    1083
Waiting:      111  287  77.4    288     674
Total:        292  641 143.5    638    1094

Percentage of the requests served within a certain time (ms)
  50%    638
  66%    706
  75%    767
  80%    780
  90%    804
  95%    824
  98%    879
  99%   1094
 100%   1094 (longest request)

PHP 7.0

Server Software:        nginx/1.8.1
Server Hostname:        michal.durys.pl
Server Port:            80

Document Path:          /
Document Length:        65737 bytes

Concurrency Level:      4
Time taken for tests:   6.343 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      6594000 bytes
HTML transferred:       6573700 bytes
Requests per second:    15.77 [#/sec] (mean)
Time per request:       253.721 [ms] (mean)
Time per request:       63.430 [ms] (mean, across all concurrent requests)
Transfer rate:          1015.20 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       11   11   0.2     11      12
Processing:    63  241  92.4    219     557
Waiting:       34  123  45.1    109     206
Total:         74  252  92.3    230     568

Percentage of the requests served within a certain time (ms)
  50%    230
  66%    288
  75%    307
  80%    320
  90%    365
  95%    411
  98%    501
  99%    568
 100%    568 (longest request)

Tak na oko, przyspieszenie jest blisko dwu i półkrotne, wszystko działa, w logach czysto, więc wygląda to obiecująca. Jeśli w najbliższych dniach nie wystąpią problemy dam szansę siódemce z Piwikiem, PrestaShop i Roundcube’em.

Testowe adresy email

Dzisiaj kilka słów o mailach w kontekście programowania (lub testowania) aplikacji internetowych. Najprościej rzecz ujmując, warto mieć pod ręką duuużo adresów email, co przydaje się przy np. testowaniu rejestracji albo mailingu. Skąd je wziąć?

W Internecie jest całe mnóstwo darmowych kont pocztowych, ale zakładanie dziesiątek kont, pamiętanie do nich haseł i logowanie się na każde z nich byłoby uciążliwe. Na szczęście Dobrzy Ludzie stworzyli różne usługi i narzędzia, które ten problem rozwiązują.

Tymczasowe konta

Najprostsze w użyciu są usługi w rodzaju niepodam.pl i migmail.pl. Wystarczy podać dowolny adres w domenie niepodam.pl albo migmail.pl, np. michal@niepodam.pl, a następnie wejść na taką stronę, wpisać wybrany login i już można czytać maile wysłane na ten adres.

migmail

Ponieważ takich adresów nie trzeba rejestrować można je równie dobrze generować automatycznie, co przydaje się np. przy testowaniu mailingu. Ja najczęściej korzystam z nich w środowiskach, które wysyłają „prawdziwe” maile np. UAT i produkcyjnym.

Wadą tych rozwiązań jest to, że wyświetlanie wiadomości w formacie HTML nie zawsze działa jak powinno, np. linki są obcięte albo nieklikalne, a elementy graficzne źle rozmieszczone. Dlatego słabo nadają się do testowania wyglądu maili.

Warto też pamiętać, że są to tymczasowe konta i wiadomości są usuwane automatycznie po kilku godzinach lub dniach.

GMail

Każde konto GMail ma dwie cechy, które przydają się przy mnożeniu aliasów:

  • Wszystkie występujące w nazwie użytkownika kropki są ignorowane.
  • Po nazwie użytkownika można postawić znak „plus” i wpisać dowolny tekst, który także zostanie zignorowany.

W efekcie dysponując kontem imienazwisko@gmail.com możemy generować unikalne adresy do woli, np. imie.nazwisko@gmail.com, i.m.i.e.nazwisko@gmail.com, imienazwisko+test1@gmail.com, imie.nazwisko+test2@gmail.com itd.

MailCatcher

MailCatcher to prosty demon SMTP, który całą korespondecję, która przez niego przechodzi pozwala przeglądać za pomocą prostego interfejsu webowego. Demon nie sprawdza poprawności adresów, więc można używać dowolnych loginów i domen, np. qwerty@aplikacja.dev. Najlepiej spisuje się w środowisku deweloperskim, które niekoniecznie ma wyjście do Internetu.

MailCatcher jest napisany w Ruby, więc o ile to środowisko uruchomieniowe tego języka nie jest zainstalowane na serwerze trzeba wykonać następujące polecenie:

aptitude install ruby ruby-dev libsqlite3-dev build-essential

Kiedy Ruby już działa to można zainstalować MailCatchera:

gem install mailcatcher

Uruchomienie MailCatchera z konsoli:

mailcatcher --foreground --http-ip=0.0.0.0

Domyślnie SMTP nasłuchuje na porcie 1025, a interfejs webowy jest dostępny na porcie 1080. Oczywiście takie niestandardowe parametry SMTP należy podać w konfiguracji PHP albo aplikacji.

W Symfony2 wystarczy dodać parametr port w konfiguracji SwiftMailera (w standardowej konfiguracji go nie ma). W pliku app/config/config.yml dodajemy:

swiftmailer:
    transport: "%mailer_transport%"
    host:      "%mailer_host%"
    username:  "%mailer_user%"
    password:  "%mailer_password%"
    port:      "%mailer_port%"

Zaś w app/config/parameters.yml:

parameters:
    # ...
    mailer_transport: smtp
    mailer_host: 127.0.0.1
    mailer_user: null
    mailer_password: null
    mailer_port: 1025
    # ...

Bezprzewodowe głośniki w Linuksie

Da się? Da się! Tak w skrócie można podsumować moje podejście do połączenia laptopa z Linuksem do głośników bez użycia kabli. Poszło łatwiej niż sądziłem, prawie plug & play.

W sumie wszystko co musiałem jest elegancko opisanie w debianowej wiki. Na początek należy się upewnić, że wymagane pakiety są zainstalowane:

aptitude install pulseaudio pulseaudio-module-bluetooth pavucontrol bluez-firmware

U mnie ich brakowało, ale mój system instalowałem z wersji minimalnej, nie lubię mieć w systemie rzeczy, których nie używam. Potem warto zrestartować usługę bluetooth i dźwięku:

service bluetooth restart
killall pulseaudio

Ostatnim krokiem jest sparowanie głośników z komputerem podobnie jak każdego innego urządzenia.

a2dp_connection

Gdy urządzenie jest sparowane wystarczy przełączyć wyjście na głośniki bluetooth.

a2dp_settings

Dzięki przenośnym głośnikom mogę cieszyć się dźwiękiem z laptopa nie tylko przez słuchawki (te wbudowane pierdziawki nie nadają się prawie do niczego). Wiem też, że mój następny amplituner powinien być wyposażony w bluetooth. Gdy go kupię dźwiękiem z mojego laptopa będą się również mogli cieszyć sąsiedzi. ;-)

Diagnozowanie i naprawianie problemu X-ami

Kiedy po aktualizacji pakietów system nie wstaje to wiedz, że coś się dzieje. W moim przypadku uruchamianie zdychało przy uruchamianiu powłoki graficznej. W tym wpisie pokażę jak można zdiagnozować przyczynę i skutecznie naprawić system w jednym z takich wypadków.

Pierwszym krokiem przy diagnozowaniu problemów z X-ami jest sprawdzenie logów.

# grep '(EE)' /var/log/Xorg.0.log

[    13.384] (EE) Failed to load /usr/lib/xorg/modules/extensions/libglx.so: libGL.so.1: cannot open shared object file: No such file or directory
[    13.384] (EE) Failed to load module "glx" (loader failed, 7)

Ewidentnie w systemie brakowało biblioteki libglx.so. Należy więc sprawdzić jej zależności.

# ldd /usr/lib/xorg/modules/extensions/libglx.so 
	linux-vdso.so.1 (0x00007fffad3fd000)
	libGL.so.1 => not found
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb41bf2f000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fb41bd2b000)
	libaudit.so.1 => /lib/x86_64-linux-gnu/libaudit.so.1 (0x00007fb41bb05000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb41b804000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb41b45b000)
	libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fb41b232000)
	libglapi.so.0 => /usr/lib/x86_64-linux-gnu/libglapi.so.0 (0x00007fb41b007000)
	libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007fb41adf5000)
	libXdamage.so.1 => /usr/lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007fb41abf2000)
	libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007fb41a9ec000)
	libX11-xcb.so.1 => /usr/lib/x86_64-linux-gnu/libX11-xcb.so.1 (0x00007fb41a7ea000)
	libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007fb41a4a7000)
	libxcb-glx.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-glx.so.0 (0x00007fb41a28e000)
	libxcb-dri2.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-dri2.so.0 (0x00007fb41a089000)
	libxcb-dri3.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-dri3.so.0 (0x00007fb419e86000)
	libxcb-present.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-present.so.0 (0x00007fb419c83000)
	libxcb-sync.so.1 => /usr/lib/x86_64-linux-gnu/libxcb-sync.so.1 (0x00007fb419a7c000)
	libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007fb41985a000)
	libxshmfence.so.1 => /usr/lib/x86_64-linux-gnu/libxshmfence.so.1 (0x00007fb419657000)
	libXxf86vm.so.1 => /usr/lib/x86_64-linux-gnu/libXxf86vm.so.1 (0x00007fb419451000)
	libdrm.so.2 => /usr/lib/x86_64-linux-gnu/libdrm.so.2 (0x00007fb419243000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fb41c62f000)
	libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007fb41903f000)
	libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007fb418e39000)

Dzięki ldd wiedziałem że brakuje pliku libGL.so.1. Sprawdziłem, że powinien znajdować się w pakiecie libgl1-mesa-glx, więc sensownym posunięciem wydaje się ponowna instalacja tego pakietu.

# aptitude reinstall libgl1-mesa-glx

Niestety, to nie pomogło. Archiwum z pakietem zawierało potrzebny plik, ale instalator z nieznanych mi względów go nie kopiował. Zrobiłem to za niego, skopiowałem z:

/var/cache/apt/archives/libgl1-mesa-glx_10.5.9-2_amd64.deb

do:

/usr/lib/x86_64-linux-gnu/libGL.so.1
/usr/lib/x86_64-linux-gnu/libGL.so.1.2.0