Eintrag von 2020-07-26
▶ RaspberryPi + mpd + pulseaudio + bluetooth = FOSS-Jukebox 2020
Im Laufe der Jahre habe ich schon einige "Jukeboxen" für mein Zuhause mithilfe des langgedienten Music Player Daemon (mpd) gebaut. Kürzlich hat es mich wieder einmal gereizt, einen Bluetooth-Lautsprecher auf diese Weise ans Heimnetzwerk zu bringen. Im Jahr 2020 gelingt das unter GNU/Linux nur noch via PulseAudio, da bluez (worüber Bluetooth-Peripherie aller Art angebunden wird) die direkte Unterstützung von ALSA vor einiger Zeit ad acta gelegt hat. Da sich der Gesamtaufbau aufgrund der recht komplexen Abhängigkeiten verschiedener Dienste und Technologien als nicht trivial erwiesen hat, will ich mein Setup hier öffentlich dokumentieren.
Plattform: RaspberryPi 3b + Arch Linux ARM
Bei vielen Bastlern fallen im Laufe der Jahre wohl überzählige RaspberryPi Single Board Computer der einen oder anderen Generation an - so auch bei mir. Das war der Hauptgrund, warum ich diese Plattform als Host für meine Jukebox gewählt habe. Als Zuckerl gibt es ein für den RPi vorkompiliertes Release meines Lieblingswebfrontends für mpd, ympd. Da mir die Raspbian-Images der RPi Foundation auch in der Minimalvariante immer noch etwas zu viel an für mich unnotwendiger Software mitbringen, greife ich auf dem RPi gerne zu Arch Linux ARM, das sich als gutes Pendant zu meiner bevorzugten Distribution für meinen Desktop erwiesen hat.
Da ich mit der Inbetriebnahme des im SoC integrierten Bluetooth-Adapters nicht auf Anhieb zum Erfolg gekommen bin, habe ich kurzerhand einen noch in einer Lade herumliegenden Digitus USB-Bluetooth-Adapter mit Support für Bluetooth 4.0 herangezogen, und sowohl WiFi- als auch BT-Interface des RPi per /boot/config.txt deaktiviert. Die Verbindung zum LAN stellt mein RPi folglich via Ethernet her, und dank systemd-networkd ist der DHCP-Support für IPv4 im Nu eingerichtet.
Bluetooth
Im ersten Schritt installieren wir die für die bluetooth-Kommunikation notwendigen Pakete: `pacman -S bluez-utils bluez`. Ist das erledigt und ist der bluetooth-Support kernelseitig korrekt initialisiert (wenn ja, existiert ein Directory namens /sys/class/bluetooth), kann man mit `systemctl enable --now bluetooth` sicherstellen, dass die zugehörigen Userspace-Komponenten verfügbar sind und bleiben. Mit dem so gestarteten bluetoothd interagiert man fortan via bluetoothctl, um BT-kompatible Geräte zu verbinden und zu verwalten. Damit das möglich wird, muss man den Adapter aber erst aus seinem initalen Dornröschenschlaf erwecken: `bluetoothctl power on && bluetoothctl scan` sorgt dafür, dass sich der Adapter auf seinem Frequenzband umzuhören beginnt, ob es paarungswillige Geräte in der Nachbarschaft gibt. Jetzt muss man dafür sorgen, dass die Peripherie - in meinem Fall ein Anker SoundCore 2-Lautsprecher - im Pairing Mode ist (Details dazu findet man im Handbuch des zu verbindenen Geräts), und irgendwann unter bekanntgabe seiner Hardware-Adresse im Output vorbeiscrollt.
Hat man die HWaddr gefunden, kann man das so identifizierte Gerät pairen und dieser Gegenstelle permanent vertrauen, was ein automatisches Wiederverbinden im Falle des Verbindungsabbruches ermöglicht. Das tut man (hier gezeigt anhand einer exemplarischen Beispieladresse) so: `bluetoothctl pair 00:00:5E:00:53:12 && bluetoothctl trust 00:00:5E:00:53:12`. Ein finales `bluetoothctl connect 00:00:5E:00:53:12` sollte nun dafür sorgen, dass über die Verbindung zur Gegenstelle tatsächlich eines der angebotenen Services beansprucht wird, die man via `bluetoothctl info 00:00:5E:00:53:12` enumerieren lassen kann. Bei meinem Lautspreche sieht die Ausgabe des obigen info-Aufrufes so aus:
[root@jukebox ~]# bluetoothctl info 00:00:5E:00:53:12 Device 00:00:5E:00:53:12 (public) Name: SoundCore 2 Alias: SoundCore 2 Class: 0x00240404 Icon: audio-card Paired: yes Trusted: yes Blocked: no Connected: yes LegacyPairing: no UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb) UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb) UUID: Advanced Audio Distribu.. (0000110d-0000-1000-8000-00805f9b34fb) UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb) UUID: Handsfree (0000111e-0000-1000-8000-00805f9b34fb) UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb) Modalias: usb:v099Ap0500d011B
Im künftigen Betrieb will man freilich nicht nach jedem Neustart des Hosts oder der BT-Peripherie dafür Sorge tragen, dass die beiden Stationen einander wiederfinden und Kontakt aufnehmen können - weswegen wir sicherstellen, dass der bluetoothd uns diese Arbeitsschritte abnehmen wird. Dafür erweitern wir die bluetooth.service-Unit um zwei ExecPost-Stanzas in einer Datei namens /etc/systemd/system/bluetooth.service.d/override.conf (via `systemctl edit bluetooth.service` wird diese Struktur automatisch angelegt):
[Service] ExecStartPost=/usr/bin/bluetoothctl power on ExecStartPost=/usr/bin/bluetoothctl agent on
Mit diesen Konfigurationsbausteinen an Ort und Stelle sollten Lautsprecher und RPi immer dann automatisch Kontakt zueinander aufnehmen, wenn beide eingeschaltet und der Lautsprecher nicht mit einem anderen Gerät verpaart ist.
PulseAudio
PulseAudio ist eine Technologie, die zumindest in den ersten Jahren ihrer Existenz sehr umstritten war. Ich möchte diesen flexiblen Soundserver am Desktop schon seit vielen Jahren nicht mehr missen, da ich Features wie das Umrouten von Audio-Quellen auf andere/gerade neu im System registrierte Audiogeräte sehr schätze und oft benutze. Auch auf einem System, das ohne graphische Session läuft, kann man PulseAudio einsetzen - aber es ist durchaus etwas mühsam, da viele sonst "automagisch" funktionierende Dinge bewusster und von Administratorhand eingerichtet werden müssen. PulseAudio selbst bemüht sich auch redlich, den Einsatz als "system-wide instance" in der Dokumentation unattraktiv zu machen. Wie auch immer - in diesem speziellen Fall bleiben keine wirklichen Alternativen, und technisch möglich ist es allemal.
Im ersten Schritt kümmern wir uns um die Installation des Pakets sowie darum, dass es die von PulseAudio stillschweigend erwarteten User und Gruppen gibt, um die Anforderungen des "system"-Modus zu befriedigen. Das erledigen die folgenden Kommandos: `pacman -S pulseaudio pulseaudio-bluetooth`, `useradd -M -c "pulseaudio system user" -d /var/run/pulse -r -s /bin/nologin pulse` und `groupadd -r pulse-access` (die Gruppe "pulse-access" ist in diesem Fall nur kosmetisch wichtig, aber ihr Vorhandensein spart uns ein Warning bei jedem Start von PulseAudio, was ich für einen akzeptablen Kuhhandel befinde).
Mit diesen neuen Accounts bewaffnet erstellen wir eine pulseaudio.service Unit für systemd, die in der Datei /etc/systemd/system/pulseaudio.service so aussieht:
[Unit] Description=PulseAudio system-wide sound server After=bluetooth.service Before=mpd.service [Service] Type=notify ExecStart=/usr/bin/pulseaudio --daemonize=no --system --realtime --log-target=journal --disallow-exit RuntimeDirectory=pulse [Install] WantedBy=multi-user.target
Aufmerksame Leser werden sich wundern, dass wir hier kein User=- bzw. Group=-Stanza finden können. Das liegt daran, dass ein als root gestarteter pulseaudio-Server im "system"-Modus automatisch via setuid() auf pulse zurückschraubt. Der Parameter RuntimeDirectory=pulse sorgt dafür, dass systemd vor dem Start des Soundservers das Verzeichnis /run/pulse anlegt, das durch einen Symlink (/var/run -> ../run) als Home Directory für den Service-User taugt. (PulseAudio hat in Version 13 immer noch "/var/run/" als Prefix hartkodiert, weswegen ich diesen Kompatibilitäts-Pfad bewusst gewählt habe.)
Das zuvor explizit installierte bluetooth-Modul für PulseAudio ist in den meisten Distributionen nicht im Basispaket enthalten, und will auch deshalb von Hand in die Konfiguration eingebunden bzw. geladen werden. Um das in der "system"-Instanz von PulseAudio zu erreichen, erweitern wir die Datei /etc/pulse/system.pa an ihrem Ende um das folgende Stanza:
### Enable bluetooth audio support via bluez .ifexists module-bluez5-discover load-module module-bluez5-discover .endif
Ein beherztes `systemctl daemon-reload && systemctl enable --now pulseaudio.service` sorgt nun dafür, dass unser Soundserver zum Leben erwacht. Haben wir alles richtig gemacht, präsentiert sich der Status des Services in etwa so:
# systemctl --no-pager -l status pulseaudio ● pulseaudio.service - PulseAudio system-wide sound server Loaded: loaded (/etc/systemd/system/pulseaudio.service; enabled; vendor preset: disabled) Active: active (running) since Sun 2020-07-26 12:37:25 UTC; 1h 30min ago Main PID: 334 (pulseaudio) Tasks: 2 (limit: 2155) CGroup: /system.slice/pulseaudio.service └─334 /usr/bin/pulseaudio --daemonize=no --system --realtime --log-target=journal --disallow-exit Jul 26 12:37:25 jukebox pulseaudio[334]: Running in system mode, forcibly disabling SHM mode. Jul 26 12:37:25 jukebox pulseaudio[334]: Running in system mode, forcibly disabling exit idle time. Jul 26 12:37:25 jukebox pulseaudio[334]: OK, so you are running PA in system mode. Please make sure that you actually do want to do that. Jul 26 12:37:25 jukebox pulseaudio[334]: Please read http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/WhatIsWrongWithSystemWide/ for an explanation why system mode is usually a bad idea. Jul 26 12:37:25 jukebox pulseaudio[334]: Failed to open cookie file '/var/run/pulse/.config/pulse/cookie': No such file or directory Jul 26 12:37:25 jukebox pulseaudio[334]: Failed to load authentication key '/var/run/pulse/.config/pulse/cookie': No such file or directory Jul 26 12:37:25 jukebox pulseaudio[334]: Failed to open cookie file '/var/run/pulse/.pulse-cookie': No such file or directory Jul 26 12:37:25 jukebox pulseaudio[334]: Failed to load authentication key '/var/run/pulse/.pulse-cookie': No such file or directory Jul 26 12:37:25 jukebox pulseaudio[334]: Failed to acquire org.pulseaudio.Server: org.freedesktop.DBus.Error.AccessDenied: Connection ":1.16" is not allowed to own the service "org.pulseaudio.Server" due to security policies in the configuration file Jul 26 12:37:25 jukebox systemd[1]: Started PulseAudio system-wide sound server.
Die Warnings wegen des "cookie files" und des "authentication key" zeugen davon, dass diese von PulseAudio beim Starten neu erzeugt worden sind, weil /var/run/pulse nur zur Laufzeit des Services existiert. Der DBus-Fehler rührt daher, dass es für die Unit keinen Session Bus (wie in einer Desktop-Session nach einem User-Login) gibt, in der sich PulseAudio registrieren könnte, was für unseren Einsatzzweck keine weitere Rolle spielt.
mpd
Die Konfiguration von mpd sowie die Interaktion mit dem Dienst über einen Client will ich hier nicht detailliert abhandeln - die Integration mit PulseAudio (der wiederum die Tonwiedergabe via Bluetooth für mpd transparent macht) aber schon. Zuerst müssen wir sicherstellen, dass der User mpd Mitglied der pulse-Gruppe ist, die beim Anlegen des pulse-Useraccounts automatisch erstellt wurde - andernfalls kann mpd nicht via Shared Memory mit pulseaudio kommunizieren. Dafür bietet sich das Editieren der group-Database z. B. via vigr an. Bei mir ist der mpd-User letztendlich wie folgt angelegt:
# id mpd uid=45(mpd) gid=45(mpd) groups=45(mpd),995(audio),975(pulse),974(pulse-access)
Zusammen mit einem entsprechenden (ggf. zusätzlichen) Output-Stanza in der /etc/mpd.conf genügt das auch schon, um mpd erfolgreich mit PulseAudio zu verdrahten:
### [...] audio_output { type "pulse" name "PulseAudio" } ### [...]
Startet man mpd.service nach dieser Aenderung bzw. Erweiterung der Konfigurationsdatei neu, findet dieser durch die PulseAudio-Client-Library automatisch zur systemweiten Instanz des Soundservers. Um zu verifizieren, dass mpd auch wirklich pulseaudio nutzt, können wir z. B. via lsof einen Blick in die geführten Dateideskriptoren werfen - was bei mir folgendes Bild ergibt:
[root@jukebox ~]# lsof -n -p $(pidof mpd) | grep pulseaudio mpd 285 mpd DEL REG 0,1 16985 /memfd:pulseaudio mpd 285 mpd mem REG 179,2 464332 662996 /usr/lib/pulseaudio/libpulsecommon-13.0.so mpd 285 mpd 18u REG 0,1 67108864 16985 /memfd:pulseaudio (deleted)
Diese Konstellation sollte dazu führen, dass mpd über den PulseAudio-spezifischen Output allen möglichen Lärm erzeugen kann, sobald ein Client ihn darum bittet.
direkter Link ▲Eintrag von 2020-03-23
▶ Lautloser und leistungsfähiger GNU/Linux-Desktop mit ECC-Speicher
Nach mehr als sechs Jahren war es kürzlich wieder soweit, und ich habe mir einen neuen Desktop-PC zusammengestellt. Die Zeichen der Zeit zeigen, zumindest für x86-kompatible Architekturen, klar in Richtung AMD Ryzen. Wenn man für so ein System das richtige Mainboard auswählt, kann man relativ kostengünstig ein energieeffizientes und trotzdem sehr leistungsfähiges Gesamtpaket samt Arbeitsspeicher mit ECC-Unterstützung schnüren.
Freilich sollte das nicht das einzige Kriterium bleiben, nach denen man einen PC zusammenstellt. Ich wollte für diese Iteration meines hauptsächlich genutzten Desktop-Systems eine Variante, die auf meinen Schreibtisch passt, und die auch eine USB-C-Schnittstelle an der Gehäusefront bietet. Trotzdem wollte ich bei der Geräuschkulisse keine faulen Kompromisse eingehen müssen - mein bisheriger Desktop (im Minitower-Format, wie er unter meinem Schreibtisch Platz gefunden hatte) war im tagtäglichen Betrieb unhörbar, und das wollte ich auch für seinen Nachfolger beibehalten. Im Endeffekt habe ich mich für eine Liste an Komponenten entschieden, die um die 750 Euro gekostet hat, und mir sicherlich auf Jahre hin ausreichend Leistung unter Erfüllung all meiner Wünsche und Anforderungen, sowie exzellenter GNU/Linux-Kompatibilität, bieten wird.
Die Auswahl mancher Komponenten möchte ich noch im Detail erläutern bzw. beleuchten, sowie einige hoffentlich sachdienliche Kommentare zum Einsatz der Hardware unter GNU/Linux festhalten.
CPU, Speicher, Mainboard
AMD ist seit 2017 und der Einführung der Zen-Architektur wieder konkurrenzfähig am CPU-Markt - derzeit sogar federführend. Die Kombination aus einer Zen 2-CPU sowie einem Board mit B450-Chipset (der durch den BIOS- bzw. Boardhersteller nicht seiner grundsätzlichen Unterstützung von ECC beschnitten wurde, was leider nur bei einigen wenigen Herstellern der Fall ist) erlaubt ein extrem leistungsfähiges und dabei - den richtigen CPU-Kühler vorausgesetzt - geräuscharmes System. Neuere AMD-Chipsets schneiden hier schlechter ab, weil sie durch kleine und schnelldrehende Lüfter aktiv gekühlt sind. Der wegfallende (offizielle) Support von PCIe 4.0 ist im Austausch dafür allemal verkraftbar. In Sachen Hauptspeicher ist die Auswahl an DDR4 UDIMM mit ECC nicht überwältigend, weswegen ich mit passenden und gut verfügbaren Kingston-Modulen das Auslangen finden muss und werde. Aufgrund der geringeren Taktfrequenz gegenüber kunterbuntem Gaming-Speicher lasse ich wohl ein paar Prozent Gesamtperformance liegen - aber das gute Gefühl, dass mein Speicher sicherlich fehlerfrei arbeitet, wiegt das für mich persönlich mehr als auf. ECC mit Zen 2 funktioniert ab Linux 5.4 wie erwartet; die UE- und CE-Counts sind wie auf anderen Architekturen auch übersichtlich im sysfs zu finden, bzw. über die edac-utils abrufbar:
$ edac-util -v mc0: 0 Uncorrected Errors with no DIMM info mc0: 0 Corrected Errors with no DIMM info mc0: csrow0: 0 Uncorrected Errors mc0: csrow0: mc#0csrow#0channel#0: 0 Corrected Errors mc0: csrow0: mc#0csrow#0channel#1: 0 Corrected Errors edac-util: No errors to report.
Da das von mir gewählte Gehäuse nur Mainboards im ITX-Formfaktor fassen kann, war ich bei der Wahl der infragekommenden Modelle stark eingeschränkt - konnte aber im ASRock Fatal1ty B450 Gaming-ITX/ac ein passendes Modell finden. Dieses Board ist etwas teurer als Konkurrenzmodelle und bietet einigen Schnickschnack, den ich weder brauche noch als wirklichen Vorteil begreife (das integrierte Intel 3168-Wifi+BT-Modul z. B. müsste ich nicht haben), aber die Liste der infragekommenden Alternativen ist sehr kurz. Im Endeffekt habe ich dem Kernel verboten, den Treiber für die WLAN-Hardware zu laden (das Device kann man unverständlicherweise nicht per UEFI-Setup deaktivieren), und das aktuelleste UEFI-ROM eingespielt, um einen reibungslosen Betrieb unter archlinux zu erreichen:
$ cat /etc/modprobe.d/blacklist.conf # Disable onboard WiFi module blacklist mac80211 blacklist iwlwifi
Der für mich nützliche Bluetooth-Support funktioniert auch dann, wenn man den WLAN-Teil des Kombio-Modul so stillegt - die Antennen muss man allerdings auch dann montiert haben, sonst reicht die Sendeleistung nur wenige Zentimeter weit. Es gibt mit Linux 5.5 leider noch keinen Treiber für die PWM-basierte Steuerung der Lüfter im System, was durch den exzellenten Support für die Feineinstellung der Regelung im UEFI-Setup aber in der Praxis nicht so stark ins Gewicht fällt. Etwas lästig ist es freilich, dass man das passende Lüfterdrehzahlprofil nur im bunten UEFI-Setup finden und einstellen kann, anstatt z. B. via fancontrol. Ansonsten arbeitet alles, was das Mainboard an Features bietet, unauffällig. Suspend to RAM funktioniert, sowie das Aufwachen aus diesem Zustand, absolut zuverlässig, und auch mein umschaltbarer USB-Hub, an dem meine Eingabegeräte hängen, macht hier keine Probleme - was beim Vorgängersystem lästigerweise nicht der Fall war, und ab und an die Komplettabschaltung des PCs erforderlich gemacht hat. Ich kann das Board also für den Betrieb unter GNU/Linux, zumindest mit dem bei mir geflashten BIOS-Release P3.70 (2019-11-18), vorbehaltlos empfehlen.
Gehäuse und Kühlung, Netzteil
Das Raijintek Metis Evo-Gehäuse im ungewöhnlichen, aber angenehm schreibtischtauglichen Beinahe-Würfel-Formfaktor ist ziemlich teuer, gefällt mir dafür auch tatsächlich. Der Komfort beim Einbau der Komponenten ist akzeptabel - mit einem ausgewachsenen Tower ärgert man sich aber natürlich weniger. Wer die Wahl hat, sollte ein Netzteil mit modularen Kabeln einsetzen, da dies viel Wirrwarr im Inneren sparen helfen kann. Sehr praktisch finde ich die beiden Front-Anschlüsse mit jeweils einer USB-A- und einer USB-C-Buchse mit SuperSpeed-Support, die bei meinem Exemplar auch elektrisch zuverlässig funktionieren. Deutlich weniger begeistert bin ich von der Verarbeitung des Korpus - die Außenhaut bzw. Hülle des Gehäuses passt nicht zu 100% auf das Innenleben des Chassis, was einiges an Kraftaufwand beim Verschrauben notwendig macht, und die filigranen Schrauben könnten gerne widerstandsfähiger schwarz eloxiert sein. Das ist für ein fast 150 Euro Straßenpreis eigentlich eine ziemlich peinliche Vorstellung.
Aber wo Schatten ist, gibt es auch Licht: Die Möglichkeit, das ganze System durch einen 200mm-Lüfter hoher Qualität zu kühlen, habe ich dankbar in Anspruch genommen. Ich habe hier bewusst nicht am falschen Ende gespart, und auf die meinem Empfinden nach eigentlich überzogen teuren Komponenten von Noctua gesetzt. Zuerst habe ich es mit Kühllösungen von Arctic Cooling, mit denen ich in der Vergangenheit schon oft sehr zufrieden war, versucht - musste dann aber augfrund minimal, aber doch nervig schleifender Lager umdisponieren. Mit der gegenwärtigen Konfiguration ist der kleine Würfel im Desktop-Betrieb akustisch nicht wahrnehmbar. Setzt man die zwölf Ryzen-Cores/Threads unter Stress, ändert sich das natürlich für eine Zeit lang; richtig störend wird die Geräuschkulisse aber eigentlich nie.
Beim Netzteil musste ich aufgrund der positiven Erfahrung mit dem zum Anschaffungszeitpunkt sehr teuren, dafür völlig passiv ausgelegten SilverStone NightJar mit absolut ausreichenden 400W Nennleistung nichts Neues kaufen. Vergleichbare Netzteile kosten immer noch über 100 Euro, für das System sind aber auch (per beiliegender Blende ebenfalls in das Gehäuse passende) SFX-Netzteile mit 250W Nennleistung mehr als ausreichend dimensioniert. Hier kann man also ggf. kostengünstige Komponenten einsetzen, wenn das Betriebsgeräusch entsprechend zurückhaltend ausfällt.
Grafikkarte
Mein bis dato verwendetes Intel-System bot eine für meine Zwecke ausreichend leistungsfähige, integrierte Grafikeinheit. Mit dieser Zielsetzung ist es ziemlich einfach, in Sachen Leistung adäquaten Ersatz in Form einer steckbaren PCIe-Karte zu finden. Am liebsten wäre mir eine passiv gekühle Grafiklösung von AMD gewesen, die AMD FreeSync unterstützt. Leider gibt es offenbar bis zum heutigen Tag keine Grafikkarte am Markt, die diese beiden Kriterien erfüllt, was mich zu einer Sapphire Pulse Radeon RX 550 mit etwas abgespeckten 2GB VRAM greifen ließ. Sapphire hat einen guten Ruf, was die Laufruhe der verwendeten Belüftungslösungen angeht, und die RX 550-Generation übererfüllt all meine Wünsche an Features einer GPU. Zudem wird das Modell mit einem "Zero-Fan"-Betriebsmodus - also semipassiver Kühlung, die nur bei Bedarf anspringt - beworben.
Diese Aussichten erwiesen sich als zu rosig, um auch wahr zu sein: Der amdgpu-Treiber ermöglicht zwar die Beeinflussung vieler Betriebsparameter der GPU und regelt z. B. auch die Taktraten von GPU und VRAM dynamisch nach Auslastung - allerdings tut er das nicht im selben Umfang bzw. so rigoros wie der Windows-Treiber sich das zutraut, und der semi-passive Betrieb wird mit dem Linux-Kernel nicht gewährleistet. Man kann die Lüfterdrehzahlsteuerung auch manuell übernehmen und somit den Geräuschpegel gut mitgestalten, aber vom Kriterium "unhörbar" kann trotzdem keine Rede sein. Da der verwendete Kühlkörper ein wahres Fliegengewicht und nicht gerade vertrauenserweckend ist, ist ein "Mitschwimmen" im Gehäuseluftstrom, mit ausgestecktem GPU-Lüfter, nicht drin. Letztendlich habe ich den von Sapphire gelieferten Kühlkörper durch den eines Arctic Accelero L2 Plus ersetzt, dessen Lüfter ich aber abmontiert habe. Zusätzlich - das wäre nicht absolut notwendig, hat sich in meinen Tests aber nicht als Nachteil für meinen 1x-WQHD-Desktop-Betrieb herausgestellt - regle ich die GPU-Performance über ihrem erreichbaren Maximum ab, was die Temperaturen auf stets unter 60°C und den Stromverbrauch der Grafikkarte auf unter 8W (beides abermals via sysfs exponiert und z. B. via lm-sensors komfortabel auslesbar) festzurrt. Das erreicht man durch das Ausführen dieser Kommandos (ggf. nach jedem Suspend/Resume-Zyklus; bei mir regelt das ein periodischer systemd-timer):
echo manual > '/sys/class/drm/card0/device/power_dpm_force_performance_level' echo "0 1 2" > '/sys/class/drm/card0/device/pp_dpm_sclk' echo "0 1" > '/sys/class/drm/card0/device/pp_dpm_mclk'
NVME
Sehr zufrieden bin ich - zumindest bis dato - mit der konkreten Wahl des Massenspeichers im m.2-Format. Das Corsair-Modul mit knapp 240GB ließ sich seinen vorkonfigurierten NVME-Namespace anstandslos im 4KiB-Format formatieren, und tut seitdem anstandslos und mit bis zu rund 3GiB/s Durchsatz seinen unscheinbaren Dienst. Es ist wirklich angenehm, wie reibungslos man unter GNU/Linux heute mit NVME-Devices interagieren kann - eine wirklich gelungene Integration, am Server wie am Desktop. Ich hoffe lediglich, dass Corsair auch noch beginnen wird, allfällige Firmware-Updates via Linux Vendor Fimware Service zu verteilen - bis dato sind solche Aktualisierungen leider nur über ein Windows-Dienstprogramm vorgesehen.
Fazit
Summa summarum bin ich mit meinem neuen Desktop so zufrieden wie mit keinem anderen PC vor ihm. Wer sich überlegt, ein ähnliches System anzuschaffen, trifft meiner Ansicht nach eine gute Entscheidung.
Anhänge und vielleicht Nützliches
- lspci-Output (Linux 5.5.13-arch1-1)
- dmesg-Output nach dem Booten (Linux 5.5.13-arch1-1)
- /proc/cpuinfo-Inhalt (Linux 5.5.13-arch1-1, core/amd-ucode 20200224.efcfa03-1)
Eintrag von 2017-09-11
▶ Kurztipp: 7 Tage Ö1 als m3u-Playlists
Wer ab und zu genötigt ist, mithilfe der offiziellen Ö1-App aus dem Play Store die sonst auch im Web verfügbaren Sendungsaufzeichnungen aus 7 Tage Ö1 zu hören, wird sich auch über die in den Rezensionen der App bemängelten, oftmaligen Wiedergabeunterbrechungen ärgern.
Da die App-Urheber es trotz des vielen negativen Feedbacks mit einer Behebung dieses Problems nicht gerade eilig zu haben scheinen, generiere ich nun täglich in den Morgenstunden eine m3u-Playlist aus den für den Vortag publizierten Sendungen, und stelle sie auf https://johannes.truschnigg.info/media/radio/ auch für die Öffentlichkeit zur Verfügung. Diese Playlists lassen sich bspw. in VLC für Android laden, der die MP3-Streams sehr komfortabel auswählbar macht und vor allem ohne ungewollte Unterbrechungen oder andere Schnitzer wiedergibt.
Bitte beachten: Der ORF depubliziert Streams alter Sendungen aktiv - die ältesten Playlists liefern daher oft nicht (mehr) die gewünschten Inhalte; in den Apps würden diese Sendungen einfach gar nicht mehr zur Auswahl angezeigt.
direkter Link ▲Eintrag von 2016-11-11
▶ pglogical: Starthilfe für Logical Replication mit PostgreSQL
Auf der pgconf Europe 2016 habe ich dieses Jahr einen sehr interessanten Vortrag über pglogical besucht - eine Extension für PostgreSQL ab Version 9.4, die "Logical Replication" erlaubt. Logical Replication ist ein naher Verwandter des seit Version 9.0 in Postgres vorhandenen, physischen Replikationsverfahrens: dem Log-Shipping. Während dabei das "Write-Ahead Log" in einer Art endlosem Strom blockweiser Binär-Diffs vom Quell- auf den Zieldatenbankcluster appliziert wird, verwendet pglogical ein Feature namens "Logical Decoding", das aus diesem Datenstrom wieder SQL-Statements errechnen kann.
Dadurch ergibt sich gegenüber dem physischen WAL-Replay eine erhöhte Flexibilität bzw. Granularität für die zu replizierenden Daten: Mit Logical Replication kann man einzelne Relationen bzw. auch nur gewisse Statements replizieren, und ist nicht auf ganze PostgreSQL-Cluster als kleinste Einheit der Replikation festgenagelt. Preis dafür ist eine gesteigerte Komplexität bei der Einrichtung - sowie einige Limitationen bei der Replikation von DDL-Statements, die aber voraussichtlich bis PostgreSQL 10.0 aus der Welt geschafft sein werden.
Logical Replication eignet sich aufgrund dieser Eigenschaften als Ersatzlösung für Trigger-basierte Ansätze zur selektiven Replikation wie etwa Londiste/pgq aus den SkyTools. Vorteil diesen gegenüber ist, dass keine zusätzliche Write-Load am Master anfällt, egal ob eine Mutation zu einer Replikation führt oder nicht - es muss nämlich nicht in einer oder mehreren Extra-Tabellen Buch darüber geführt werden, was an Daten genau wohin zu replizieren ist. Falls die Replikation einmal zwischenzeitlich ausfallen sollte, füllen sich auch nicht am Master durch Trigger befüllte Event-Queue-Tables innerhalb des PostgreSQL-Clusters, sondern es akkumulieren sich WAL-Segmente im Dateisystem des Master-Cluster-Hosts. Den Füllstand dieses Dateisystems sollte man aber ohnehin immer genau im Auge behalten, um Notfalls teildestruktiv (und wahrscheinlich die Verfügbarkeit des Masters sicherstellend) eingreifen zu können.
Beim praktischen Ausprobieren von pglogical bin ich auf einige kleine Stolpersteine gestoßen, die für Kopfkratzen und initiale Ratlosigkeit gesorgt haben. Deswegen will ich hier eine kurze, kommentierte Einführung in Form einer Anleitung bereitstellen, wie man zwei PostgreSQL 9.6-Cluster auf Debian Jessie per Hand passend für pglogical einrichtet, und eine Relation zwischen diesen beiden synchron hält. (Achtung: Sinnvollerweise folgt man dieser Anleitung in genau dieser Form nur auf einem Host, den man nach dem Experiment entsorgen kann! Unter dieser Annahme kümmere ich mich in Folge auch nicht um bspw. das Sicherstellen der Authentizität der GPG-Keys für die Paketmetadaten-Signatur, etc. Weiters sind diese Kommandos - sofern nicht anders angegeben - in einer root-Shell auszuführen.)
Als ersten Schritt müssen wir dazu zwei Repositories als Paketquellen für apt hinzufügen, und dem Schlüsselmaterial für deren Signaturen das Vertrauen des Paketmanagers schenken:
cat <<EOF > /etc/apt/sources.list.d/pgdg.list deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main EOF wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - cat <<EOF > /etc/apt/sources.list.d/2ndquadrant.list deb [arch=amd64] http://packages.2ndquadrant.com/pglogical/apt/ jessie-2ndquadrant main EOF wget --quiet -O - http://packages.2ndquadrant.com/pglogical/apt/AA7A6805.asc | apt-key add -
Nachdem dieser Schritt erfolgreich erledigt wurde, installieren wir die damit verfügbar gewordenen Pakete für PostgreSQL 9.6, und die zu dieser Version passende pglogical-Erweiterung von 2ndquadrant. Dann weisen wir das Debian-Tooling für PostgreSQL dazu an, zwei neue Cluster für unser Demo-Setup zu erstellen, die auf für postgres unüblichen Ports Listener errichten sollen:
apt-get update apt-get install -y postgresql-9.6 postgresql-9.6-pglogical pg_createcluster 9.6 demoMASTER -p 15432 pg_createcluster 9.6 demoRX0 -p 15433
Für eine grundsätzliche Funktionsdemonstration werden wir die durch pg_createcluster erstellten Cluster-Konfigurationen nicht weiter optimieren - was aber notwendig ist, ist die Aktivierung der pglogical-Extension, die für PostgreSQL 9.6 als Shared Object implementiert ist. Die folgenden Kommandos kümmern sich auch darum, dass beide neu erstellten Cluster diese Konfigurationsänderung erfahren:
cat <<EOF >/etc/postgresql/9.6/demoMASTER/postgresql_pglogical.conf wal_level = 'logical' max_worker_processes = 10 max_replication_slots = 10 max_wal_senders = 10 shared_preload_libraries = 'pglogical' track_commit_timestamp = on EOF cp -a /etc/postgresql/9.6/demoMASTER/postgresql_pglogical.conf /etc/postgresql/9.6/demoRX0/postgresql_pglogical.conf echo "include = 'postgresql_pglogical.conf'" >> /etc/postgresql/9.6/demoMASTER/postgresql.conf echo "include = 'postgresql_pglogical.conf'" >> /etc/postgresql/9.6/demoRX0/postgresql.conf
Was nun im designierten Master-Cluster noch fehlt, sind die Replikationsprivilegien für eine Verbindung des Replica-Clusters. Wir gehen davon aus, dass beide postgres-Server über das UNIX Domain Socket des Masters miteinander kommunizieren werden, was auf einem gemeinsamen Host sinnvoll ist. Dieses Szenario benötigt einen tauglichen Eintrag in der pg_hba.conf am Master:
echo 'local replication postgres peer' >> /etc/postgresql/9.6/demoMASTER/pg_hba.conf
Nun starten wir die postgresql-Service-Unit, was dazu führt, dass unsere zwei neu erstellten Cluster hochfahren und (zusätzlich zu etwaigen schon laufenden, anderen PostgreSQL-Clustern) benutzbar werden:
systemctl start postgresql
Alle übrigen Arbeitsschritte benötigen nicht mehr root-Privilegien, sondern stattdessen Superuser-Rechte in PostgreSQL. Um diese zu erlangen, wechseln wir unseren Nutzerkontext zu dem des Systembenutzers postgres:
su - postgres
Bevor wir mittels pglogical Relationen replizieren können, müssen gleichnamige Datenbanken in den beiden Clustern existieren. Dies erledigen wir mit einem Aufruf von createdb gegen beide Cluster:
createdb -p 15432 demodb createdb -p 15433 demodb
Nun gilt es, die pglogical-Extension in diesen frisch erstellten Datenbanken zu installieren, sodass die pglogical-Funktionen verfügbar werden:
psql -p 15432 demodb -c "CREATE EXTENSION pglogical" psql -p 15433 demodb -c "CREATE EXTENSION pglogical"
Ab nun unterscheiden sich die Aktionen, die wir gegen den Master bzw. den Slave ausführen, maßgeblich. Der Master-Node will für seine Verwendung mit pglogical folgendermaßen initialisiert werden:
psql -p 15432 demodb -c "SELECT pglogical.create_node(node_name := 'demoMASTER', dsn := 'port=15432 dbname=demodb')"
Der Slave braucht im Kontrast dazu über pglogical (und nicht etwa über die recovery.conf, wie bei Log-Shipping/Streaming Replication) den Auftrag, sich auf den WAL-Stream des eben erstellten Master-Nodes zu subscriben:
psql -p 15433 demodb -c "SELECT pglogical.create_node(node_name := 'demoRX0', dsn := 'port=15433 dbname=demodb')" psql -p 15433 demodb -c "SELECT pglogical.create_subscription(subscription_name := 'demo_rx0_from_master', provider_dsn := 'port=15432 dbname=demodb', synchronize_data := TRUE)"
Ab jetzt sollte der Master in seinen System-Views Informationen über seinen Replikations-Consumer bereitstellen können. Dies prüfen wir mithilfe der folgenden Abfrage:
psql -p 15432 -c "SELECT * FROM pg_stat_replication" | cat
Ist bis hierher nichts schiefgegangen, können wir die Datenbank am Master mit einer Relation füttern, die wir letztendlich replizieren wollen. Hierzu nutzen wir einen Wrapper aus dem Funktionsumfang von pglogical, um das DDL-Statement auch auf etwaige Subscriber-Nodes anzuwenden - so kommt die Tabelle auch auf unserem Slave-Cluster an:
psql -p 15432 demodb <<EOF SELECT pglogical.replicate_ddl_command('CREATE TABLE public.films ( code char(5) CONSTRAINT firstkey PRIMARY KEY, title varchar(40) NOT NULL, did integer NOT NULL, date_prod date, kind varchar(10), len interval hour to minute )'); EOF
Momentan haben wir auf Master und Slave also die gleiche, leere Tabelle, deren Schemata ident sind. Man könnte nun annehmen, dass ein INSERT am Master unmittelbar dazu führt, dass der so erzeugte Record gleichlautend am Slave aufscheint, sobald die Replikationslogik diese Transaktion erfolgreich zum Slave übertragen hat. Das ist allerdings etwas voreilig - pglogical kennt das Konzept von Replication Sets, die zum relationenspezifischen Opt-In für die Datensynchronisation dienen. Sozusagen "ab Werk" existiert auch schon ein Replication Set am Master; es heißt "default". Allerdings beinhaltet es noch keine Relationen - das können wir mit dem folgenden Statement nach unserem Wunsch ändern:
psql -p 15432 demodb -c "SELECT pglogical.replication_set_add_all_tables(set_name := 'default', schema_names := ARRAY['public'], synchronize_data := TRUE)"
Da Slaves dem "default"-Replication Set automatisch subscriben, führt dieses Statement dazu, dass ab der nächsten Transaktion Änderungen an der Tabelle am Master zu genau denselben Änderungen an der Tabelle am Slave führen. Über den optionalen Parameter synchronize_data entscheidet man, ob der momentane Ist-Zustand der Relationen im Replication Set auf den Slave übertragen werden soll, oder ob stattdessen nur zukünftige Modifikationen an den Daten den Weg von MASTER nach RX0 finden sollen. Dass das auch tatsächlich funktioniert zeigen wir, indem wir eine Hand voll Records in die Tabelle am Master eintragen, und sie dann am anderen Ende des Replikations-Setups wieder hervorzaubern:
psql -p 15432 demodb -c "INSERT INTO films VALUES ('LOTR1', 'The Fellowship of the Ring', 1, '2001-12-19'::date, 'Fantasy', '2h 58min'::interval)" psql -p 15432 demodb -c "INSERT INTO films VALUES ('LOTR2', 'The Two Towers', 2, '2002-12-19'::date, 'Adventure', '2h 59min'::interval)" psql -p 15432 demodb -c "INSERT INTO films VALUES ('LOTR3', 'The Return of the King', 3, '2003-12-17'::date, 'Drama', '3h 21min'::interval)" psql -p 15433 demodb -c "SELECT * FROM films"
Fertig!
direkter Link ▲Eintrag von 2015-12-07
▶ OpenWrt 15.05 "Chaos Calmer": A1 (AON / Telekom Austria) ADSL-Setup mit PPTP
WICHTIGES UPDATE: Diese Anleitung kann man auch für LEDE (getestet mit Release 17.01.4) verwenden, muss aber zusätzlich zu den im Blog-Eintrag erwähnten Paketen auch noch kmod-nf-nathelper-extra (darin sind die Kernel-Module nf_conntrack_pptp.ko und nf_nat_pptp.ko enthalten, die - falls vorhanden - beim Booten automatisch geladen werden) installieren. Tut man das nicht, bleibt die Kommunikation zwischen dem PPtP-Server auf dem A1-Modem und dem Client am LEDE-Gerät inmitten des PPtP-Calls stehen. Ich fand diesen Umstand noch nirgends im WWW dokumentiert, aber nach mehr als zwei Stunden Herumexperimentieren und fluchend tcpdump-Logs-Vergleichen bin ich nun endlich auch mit LEDE erfolgreich eingewählt.
In Österreich ist seit jeher alles sehr kompliziert - ist man hierzulande doch als Kunde des größten ADSL-Providers A1 (bzw. AON, vormals auch bekannt als Telekom Austria) an das archaische Point-to-Point Tunneling Protocol zur Herstellung der Internetverbindung gebunden. Andernorts verwendet man zumeist das modernere und für diesen Zweck viel tauglichere Point-to-Point Protocol over Ethernet (PPPoE). Sonst hat man es stellenweise noch in veralteten VPNs mit PPTP zu tun: Die damit verwendbaren Authentifizierungsmechanismen gelten heute aber als fundamental unsicher, und man sollte besser vorgestern als gestern auf eine modernere, sichere Technologie gewechselt haben.
Nicht zuletzt aus diesem Grund hat das OpenWrt-Projekt schon vor geraumer Zeit die Unterstützung für PPTP aus dem Standard-Installationsumfang entfernt - auf der Ziel-Hardware herrscht in vielen Fällen ohnehin ziemlicher Speicherplatzmangel, und den will man nicht durch das Mitschleppen vernünftigerweise nicht mehr zu verwendender Altlasten weiter verschlimmern. Für Kunden von "A1 Festnetz-Internet" (bzw. vormals jet2web, einstmals auch bekannt als AON Speed - wie eben auch immer das ADSL-Produkt der Telekom Austria A1 zur Stunde gerade nach intensivsten Strategiebesprechungen in der Marketingabteilung benamst ist) ist das freilich lästig: Sie müssen, aufgrund der technischen Unbeweglichkeit ihres ISPs, den gesamten PPTP-Support-Stack nachinstallieren, wenn sie hinter ihrem "Single User"-DSL-Modem ein vernünftiges Internetworking Device betreiben wollen.
Vor diese undankbare Aufgabe war ich kürzlich bei meinen Großeltern gestellt: Ein neuer Router bzw. Wireless Access-Point sollte dort eine schwer veraltete Buffalo Airstation G ersetzen. Viele Jahre hatte sie klag- und problemlos mit OpenWrt 0.9 "White Russian" (einer meiner erklärten Lieblingscocktails übrigens!) dort nach IEEE 802.11b/g in die nordsteirische Pampa gefunkt, um so u. a. einem Google Nexus 10, sowie den Wifi-tauglichen Geräten etwaiger Besucher, den Weg ins Internet zu weisen. Freilich ohne irgendwelchen modernen Firlefanz wie WPA2, oder Unterstützung des 5GHz-Bandes. Übernommen hat diese Aufgabe nun ein TP-Link TL-WDR4300 mit OpenWrt 15.05 "Chaos Calmer", der seinem Vorgängergerät freilich in allen technischen Belangen um Lichtjahre voraus ist.
Um nun OpenWrt 15.05 nach der Installation zur Zusammenarbeit mit ADSL von A1 zu überreden, muss man recht tief in der Trickkiste kramen. Da die notwendigen Schritte nicht wirklich dokumentiert zu sein scheinen, will ich sie hier (auch als Gedächtnisstütze für mich selbst, weil ich bestimmt noch öfters in die missliche Lage geraten werde, dieses Setup herstellen zu müssen) festhalten. Zuerst benötigt man mindestens die folgenden Pakete aus den OpenWrt-Repositories, inkl. aller Abhängigkeiten:
- kmod-gre
- kmod-lib-crc-ccitt
- kmod-mppe
- kmod-ppp
- kmod-pppox
- kmod-pptp
- kmod-slhc
- luci-proto-ppp
- ppp
- ppp-mod-pptp
- resolveip
- kmod-nf-nathelper-extra (für LEDE)
Freilich sollte man all diese Pakete besorgen, bevor man nur noch mit der OpenWrt-Basisinstallation auf dem Gerät dasteht - ohne sie bleibt die Internetverbindung über PPTP-ADSL nämlich düster. Im Zweifel, und um nichts vergessen zu können, mirrore ich mir deshalb vor der Installation eines Images stets den gesamten Paketbaum des zu installierenden OpenWrt-Releases (und zwar für die richtige Binärarchitektur! Mein WDR4300 benötigt jene für die Atheros 71xx-SoC-Familie.) auf ein System, das via Ethernet mit dem Router verbunden werden kann. Nach dem Flashen und initialen Setup des Routers kopiere ich dann alle so heruntergeladenen und benötigten Pakete via scp ins Dateisystem des OpenWrt-Geräts, logge mich via ssh dort ein, und installiere die Pakete via opkg nach.
Um danach einen A1-PPTP-WAN-Uplink in OpenWrt zu konfigurieren, ist noch etwas Konfigurations-Akrobatik notwendig: Zuerst braucht das von OpenWrt in der Default-Config mitgebrachte WAN-Interface eine statische IPv4-Konfiguration. Hier ist etwas Vorsicht geboten, denn je nach Router-Hardware (und damit OpenWrt-Installations-Image) kann das leicht unterschiedlich aussehen, vor allem im Hinblick auf den Interface-Namen. Beim TP-Link TL-WDR4300 liest sich die (bereits für den A1-Zugang angepasste) WAN-Konfiguration in /etc/config/network wie folgt:
config interface 'wan' option _orig_ifname 'eth1' option _orig_bridge 'false' option ifname 'eth1' option proto 'static' option ipaddr '10.0.0.140' option netmask '255.255.255.0' option gateway '10.0.0.138'
Ist das erledigt, braucht man noch ein zusätzliches, virtuelles Interface für das PPTP, ebenfalls in /etc/config/network. Nach dem Ersetzen der Dummy-Werte ("A1-ADSL-USERNAME", "A1-ADSL-PASSWORT") durch die tatsächlichen Benutzeridentifikationsdaten für die A1-ADSL-Verbindung kann dieser Abschnitt dann 1:1 wie hier übernommen werden:
config interface 'A1' option proto 'pptp' option server '10.0.0.138' option username 'A1-ADSL-USERNAME' option password 'A1-ADSL-PASSWORT' option peerdns '0' option dns '85.214.20.141 213.73.91.35 194.150.168.168' option keepalive '10 6' option mtu '1460'
Nach der Installation aller Laufzeitkomponenten und dem Einrichten der Interfaces muss man noch die Konfiguration des PPTP-Clients so zurechtbiegen, dass die von A1 benötigten Verbindungsparameter Anwendung finden. Dafür ersetzt man den gesamten Inhalt der Datei /etc/ppp/options.pptp mit dem folgenden:
noipdefault noauth nobsdcomp nodeflate idle 0 maxfail 0
Danach rebootet man das Gerät einfach. Ist es wieder hochgefahren, verbindet man sich wieder via ssh zu einer shell darauf, und wirft ein Auge auf den Output von logread - wenn sich der PPTP-Client hier nicht lautstark und wiederholt über Authentifizierungsprobleme beschwert, hat man alles richtig gemacht, und der WAN-Uplink wird nach wenigen Sekunden Initialisierungsarbeit den Internetzugang freigeben.
direkter Link ▲© 2007-2020 Johannes Truschnigg | valid xhmtl & css