Case: oma talo, osa 29: Oma levy vanhalle datalle — kaksi varmistuspaikkaa ja järjestelmälevy pidetään kevyenä

EnergyHub on pyörinyt Lenovon Tiny -koneella nyt noin puoli vuotta. Samalla koneella ovat Home Assistant, Node-RED, MQTT, InfluxDB ja Grafana, ja kaikki aktiivinen data sijaitsee nopealla NVMe-SSD:llä.

Ratkaisu on toiminut hyvin. Mutta mitä pidempään järjestelmä pyörii, sitä selvemmin esiin tulee ongelma, jota ensimmäisinä kuukausina ei juuri huomaa:

data ei lakkaa kertymästä.

InfluxDB tallentaa lämpöpumpun, aurinkosähkön, sähköauton latauksen ja muun energiajärjestelmän mittauksia sekunti- ja minuuttitasolla. Yksittäinen mittaus ei vie käytännössä mitään, mutta niitä syntyy jatkuvasti valtava määrä.

Suurin osa vanhasta datasta ei enää osallistu talon reaaliaikaiseen ohjaukseen. Silti en halua poistaa sitä. Juuri pitkän aikavälin historiasta voi myöhemmin nähdä esimerkiksi, miten lämmityksen optimointi oikeasti toimii, miten aurinkosähkön vuosituotanto muuttuu tai mitä eri sähkönhintajaksoilla tapahtui.

Järjestelmälevy ei kuitenkaan ole oikea paikka loputtomasti kasvavalle arkistolle.

Samaan aikaan varmistusjärjestelyssä oli toinen heikkous. EnergyHubista tehtiin jo age-salattu off-site-varmistus Google Driveen, mutta halusin sen rinnalle myös kokonaan erillisen paikallisen kopion.

Ratkaisuksi tuli hyvin arkinen laite:

5 teratavun USB-kiintolevy.

Mielenkiintoiseksi asia muuttui vasta siinä vaiheessa, kun piti päättää, miten levy liitetään EnergyHubiin niin, ettei uusi varmistus- ja arkistointiratkaisu itse synnytä uusia vikamahdollisuuksia.

Yksi iso levy, ei keinotekoisia lokeroita

Ensimmäinen päätös oli olla jakamatta levyä useaan partitioon.

Levylle tulee useita käyttötarkoituksia:

  • EnergyHubin paikalliset varmistukset
  • muu varmuuskopiointi
  • pitkäaikaisarkisto
  • myöhemmin vanha InfluxDB-data.

Olisi ollut helppo tehdä jokaiselle oma partitio. Se näyttää paperilla järjestelmälliseltä, mutta käytännössä siinä pitäisi arvata etukäteen, paljonko mikäkin käyttötarkoitus tarvitsee tilaa vuosien päästä.

Todennäköisesti arvaus olisi väärä.

Jos esimerkiksi varmistuspartitio täyttyisi samalla kun arkistopartitiolla olisi teratavu vapaana, tyhjä tila ei auttaisi mitään ilman myöhempää uudelleenjärjestelyä.

Eikä partitiointi suojaa varsinaiselta levyrikolta. Jos fyysinen levy hajoaa, kaikki sen partitiot häviävät samalla kertaa.

Siksi levyllä on yksi suuri ext4-tiedostojärjestelmä, jonka sisältö erotellaan tavallisilla hakemistoilla:

/srv/storage/
├── energyhub/
│   ├── daily/
│   ├── restore-bundles/
│   └── exports/
├── backup/
├── archive/
└── lost+found/

Tilankäyttöä hallitaan myöhemmin retention-säännöillä: tiedostoja voidaan poistaa tai siirtää niiden iän ja kokonaiskoon perusteella.

Levy alustettiin ext4:ksi ilman root-käyttäjälle normaalisti varattuja lohkoja. Järjestelmälevyllä varauksella on tarkoituksensa, mutta viiden teratavun puhtaalla datalevyllä viiden prosentin varaaminen tarkoittaisi jo huomattavaa määrää tilaa, jolle tässä käytössä ei ole tarvetta.

Tärkein sääntö: talon pitää toimia ilman levyä

USB-levystä ei tehty EnergyHubin aktiivista datalevyä.

Tämä oli koko toteutuksen tärkein päätös.

Home Assistant, Node-RED, MQTT, InfluxDB:n aktiivinen kanta ja Dockerin tarvitsemat tiedot pysyvät edelleen Lenovon sisäisellä NVMe-SSD:llä.

USB-levyllä säilytetään asioita, joiden hetkellinen puuttuminen ei saa estää talon toimintaa.

Tämä tarkoittaa myös sitä, että USB-levy saa hajota.

Jos levy irrotetaan, se menee lepotilaan väärällä hetkellä tai se hajoaa kokonaan, EnergyHubin pitää edelleen käynnistyä ja ohjata taloa normaalisti.

Levyn pysyvä liitos tehdään siksi /etc/fstab-tiedostossa UUID:n perusteella:

UUID=<levyn-uuid>  /srv/storage  ext4  defaults,nofail,x-systemd.device-timeout=10s  0  2

UUID:n käyttäminen estää sen, ettei järjestelmä vahingossa luota esimerkiksi /dev/sda-nimeen, joka voi muuttua uudelleenkäynnistyksessä tai USB-laitteiden järjestyksen vaihtuessa.

nofail puolestaan kertoo Linuxille, ettei levyn puuttuminen saa estää koneen käynnistymistä. Lyhyt aikakatkaisu estää buuttia jäämästä pitkäksi aikaa odottamaan levyä, jota ei ehkä ole edes kytketty.

Periaate on yksinkertainen:

EnergyHub nousee pystyyn, oli USB-levy paikalla tai ei.

Yksi yllättävän vaarallinen hakemisto

Toteutuksessa vastaan tuli asia, joka näyttää pieneltä mutta voisi pahimmillaan kumota koko levyn tarkoituksen.

Liitospiste /srv/storage on Linuxissa tavallinen hakemisto myös silloin, kun USB-levyä ei ole liitetty.

Jos jokin ohjelma siis yrittäisi kirjoittaa esimerkiksi polkuun

/srv/storage/energyhub/

levyn ollessa irti, kirjoitus voisi päätyä USB-levyn sijasta Lenovon omalle järjestelmälevylle.

Silloin varmistusjärjestelmä voisi ajan mittaan täyttää huomaamatta juuri sitä NVMe-levyä, jonka tilankäyttöä USB-levyllä alun perin yritettiin hallita.

Tätä vastaan tehtiin kaksi suojausta. Tavallisilta palvelukäyttäjiltä itse liitospiste tehdään ilman levyä kirjoituskelvottomaksi, ja root-oikeuksin toimivien kopiointien pitää lisäksi varmistaa erikseen, että oikea tiedostojärjestelmä on todella liitettynä:

sudo chown root:root /srv/storage
sudo chmod 0555 /srv/storage

Kun USB-levy on liitettynä, sen tiedostojärjestelmä peittää tämän hakemiston ja levylle voidaan kirjoittaa normaalisti.

Kun levy poistetaan, alta paljastuu root-käyttäjän omistama kirjoitussuojattu liitospiste:

root:root
dr-xr-xr-x

Tavallinen palvelukäyttäjä ei pysty kirjoittamaan sinne.

Levyn puuttuminen muuttuu siis hiljaisesta vaarasta näkyväksi virheeksi.

Ja tämä myös testattiin. Levy irrotettiin ohjelmallisesti, jolloin /srv/storage palautui tyhjäksi ja kirjoitussuojatuksi. Uudelleenliitoksen jälkeen oikeat hakemistot tulivat takaisin näkyviin.

Fail-safe, jota ei ole kokeiltu vikatilanteessa, on lähinnä oletus.

USB-levylle ei koskaan selväkielistä varmistusta

Levyn ensimmäinen varsinainen tehtävä on toimia toisena EnergyHub-varmistuksen kohteena Google Driven rinnalla.

Aktiivinen data on NVMe:llä. Paikallinen varmistuskopio on USB-levyllä. Toinen salattu kopio on kodin ulkopuolella Google Drivessa.

USB-levyllekään ei kuitenkaan tallenneta EnergyHubin varmistusta selväkielisenä.

Varmistuspaketti sisältää juuri niitä asetuksia ja tunnistetietoja, joita tarvitaan järjestelmän palauttamiseen. Ne eivät kuulu suojaamattomalle irrotettavalle levylle.

Siksi levy vastaanottaa vain valmiiksi age-salatun varmistusartefaktin ja sitä vastaavan SHA-256-tarkistussumman.

Selväkielinen väliversio käsitellään root-käyttäjän suojaamalla väliaikaisalueella. Vasta salattu tiedosto julkaistaan paikkaan, josta se voidaan kopioida Driveen ja USB-levylle.

Kopiointiskripti ei luota edes omaan levyynsä

USB-kopiointia tekevä skripti on tarkoituksella varsin epäluuloinen.

Se ei vain tarkista, että /srv/storage näyttää olevan olemassa.

Ensin tarkistetaan, että kyseessä todella on liitetty tiedostojärjestelmä. Sen jälkeen findmnt:llä varmistetaan levyn UUID.

Toisin sanoen skriptille ei riitä, että tässä kohdassa on jokin levy. Sen pitää olla juuri se levy, jonka tähän kuuluu olla liitettynä.

Tämän jälkeen skripti:

  • etsii vain riittävän tuoreen salatun varmistusartefaktin
  • vaatii mukaan sitä vastaavan SHA-256-tiedoston
  • tarkistaa lähdetiedoston eheyden ennen kopiointia
  • kopioi artefaktin ensin väliaikaiseen piilotiedostoon
  • asettaa tiedoston oikeudet
  • siirtää tiedoston atomisesti lopulliselle nimelle
  • tarkistaa myös USB:lle päätyneen tiedoston SHA-256-summan
  • poistaa yli 365 vuorokautta vanhat varmistusartefaktit.

Jos oikeaa levyä ei ole tai sopivaa tuoretta varmistusta ei löydy, ajo pysähtyy.

Mitään ei kirjoiteta väkisin.

Koko ketju ajettiin myös käytännössä läpi aidolla salatulla varmistusartefaktilla. Liitoksen varmennus, lähteen tarkistussumma, USB-kopion tarkistussumma ja retention menivät läpi, ja riippumaton SHA-256-tarkistus vahvisti kopion eheyden.

Kun parannus rikkoi watchdogin

Yksi tämän projektin kiinnostavimmista kohdista ei liittynyt varsinaisesti levyyn vaan siihen, kuinka helposti yhden asian parantaminen voi saada toisen osan näyttämään rikkinäiseltä.

EnergyHubissa oli jo varmistusten tuoreutta valvova watchdog.

Aiemmin se tarkkaili hakemistoon syntyvien selväkielisten varmistustiedostojen ikää.

Nyt niitä ei enää julkaistu sinne lainkaan.

Varmistukset siis toimivat entistä turvallisemmin, mutta watchdog olisi ilmoittanut niiden olevan rikki.

Ratkaisuksi tehtiin erillinen onnistumismarkeri.

Sen aikaleima päivittyy vasta, kun koko normaali varmistusketju on onnistunut: arkistointi, salaus, paikallinen tarkistussumma, siirto pilveen ja etäpään varmennus.

Jos jokin niistä epäonnistuu, markeri ei päivity.

Watchdog seuraa nyt tämän markerin ikää. Varoitus tulee 30 tunnin ja hälytys 72 tunnin kohdalla kuten ennenkin.

Tämä oli samalla hyvä muistutus EnergyHubin kaltaisesta kasvavasta järjestelmästä:

kun yhden komponentin toimintaa muuttaa, pitää etsiä myös kaikki ne komponentit, jotka ovat oppineet pitämään vanhaa toimintaa normaalina.

Arkisto ei saa joutua varmistamaan itseään

Levyn tuleva toinen tehtävä on pitkäaikaisarkisto.

Siinä oli yksi olennainen riski.

Jos päivittäinen EnergyHub-varmistus lähtisi vahingossa lukemaan myös /srv/storage/archive-hakemistoa, vanha data pakattaisiin joka päivä uuteen varmistukseen.

Sitten tämä kasvava varmistus kopioitaisiin takaisin samalle USB-levylle.

Se olisi varsin tehokas tapa käyttää viiden teratavun levy loppuun.

Ensimmäinen suojausyritys perustui tiedostopäätteisiin. Se toimi vähän liiankin hyvin.

Node-REDin node_modules-hakemistossa olevat tavalliset TypeScriptin .d.mts-määrittelytiedostot tulkittiin vahingossa arkistomediaksi ja varmistus keskeytyi.

Turvallinen epäonnistuminen oli hyvä asia, mutta sääntö oli väärä.

Lopullinen periaate vaihtui paljon selkeämmäksi:

turvallisuusraja perustuu polkuun, ei tiedostopäätteeseen.

Koko /srv/storage-alipuu jätetään varmistuksen ulkopuolelle. Myös symboliset linkit ratkaistaan ennen mukaan ottamista. Jos linkki johtaa USB-levylle, varmistuksen kokoaminen pysähtyy.

Näin esimerkiksi index.d.mts saa olla aivan rauhassa tavallinen TypeScript-tiedosto.

Mutta /srv/storage/archive ei päädy varmistukseen riippumatta siitä, mitä tiedostoja siellä tulevaisuudessa on.

Tässä yhteydessä väärä positiivinen on myös paljon parempi kuin väärä negatiivinen. Mieluummin varmistus pysähtyy näkyvästi kuin ottaa huomaamatta gigatavukaupalla arkistoa mukaansa.

Levyä pitää valvoa — mutta ei kiusata

Ulkoinen USB-kiintolevy on mekaaninen laite. Se tulee joskus hajoamaan.

Tavoitteena ei siis ole kuvitella siitä ikuista, vaan nähdä ongelmat mahdollisimman aikaisin.

Valvonta toteutettiin kahdella tasolla.

Kevyt tarkistus viiden minuutin välein

Ensimmäinen taso on noin viiden minuutin välein systemd-ajastimella ajettava kevyt tarkistus.

Se tarkistaa neljä asiaa:

  1. onko levy liitetty
  2. onko UUID oikea
  3. onko tiedostojärjestelmä kirjoitettavassa rw-tilassa
  4. onko vapaata tilaa riittävästi.

Alle kymmenen prosentin vapaa tila tulkitaan ongelmaksi.

SMART kertoo levyn omasta terveydestä

Toinen taso käyttää levyn SMART-tietoja.

Tässäkin oli yksi pieni mutta tärkeä suunnitteluperiaate: valvonta ei saa herättää nukkuvaa kiintolevyä jatkuvasti vain varmistaakseen, että se edelleen nukkuu kunnossa.

SMART-valvonta kunnioittaa siksi levyn standby-tilaa eikä herätä sitä turhaan pelkän tarkistuksen vuoksi.

Varsinaiset itsetestit tehdään harvemmin:

  • lyhyt SMART-testi kerran viikossa
  • pitkä SMART-testi kerran kuukaudessa.

Lisäksi erillisellä diagnostiikalla voidaan tarkistaa muun muassa uudelleenkohdennetut sektorit, odottavat sektorit, korjaamattomat virheet, siirtovirheet ja levyn lämpötila.

Lähtötilanteessa SMART-kokonaisarvio oli PASSED ja kriittiset sektorilaskurit nollassa.

Nyt on siis olemassa baseline, johon levyn tulevaa kuntoa voidaan verrata.

Kaikki ei ole vielä valmista

Tässä projektissa on myös tarkoituksella asioita, joita en väitä tehdyiksi ennen kuin ne oikeasti ovat tehtyjä.

Levyn tilavalvonta toimii, mutta hälytys menee tällä hetkellä vain järjestelmälokiin.

Se ei siis vielä välttämättä tavoita minua silloin, kun jotain tapahtuu.

Seuraava vaihe on tuoda levyn tila osaksi Home Assistantia ja EnergyHubin muuta observability-mallia niin, että ongelmasta tulee oikea käyttäjälle näkyvä ilmoitus.

Toinen vielä myöhemmin erikseen varmennettava kokonaisuus on palautus.

Varmistuksen olemassaolo ja tarkistussumman täsmääminen ovat tärkeitä asioita, mutta lopullinen testi on aina se, pystyykö sillä oikeasti palauttamaan järjestelmän.

Ja se alkuperäinen ongelma?

InfluxDB:n vanha historia on vielä NVMe:llä.

USB-levy on nyt valmis ottamaan sen vastaan, mutta itse arkistointia ei ole vielä toteutettu.

Tämä on tietoinen seuraava työvaihe.

Ajatus on pitää aktiivinen ja riittävän tuore aikasarjadata NVMe:llä, jossa Grafana ja muu järjestelmä voivat käyttää sitä nopeasti.

Vanhempi historia siirretään /srv/storage/archive-alueelle.

Se on edelleen tallessa esimerkiksi vuosien välisiä vertailuja varten, mutta sen ei tarvitse viedä tilaa järjestelmän aktiiviselta SSD:ltä.

Siitä tulee oma työvaiheensa, koska vanhan InfluxDB-datan arkistoinnissa kysymys ei ole vain tiedostojen siirtämisestä.

Pitää päättää ainakin:

  • kuinka pitkä historia pidetään aktiivisena
  • missä muodossa vanha data arkistoidaan
  • miten se palautetaan tarvittaessa analysoitavaksi
  • miten varmistetaan, ettei arkistoinnissa synny aukkoja
  • miten todetaan varmasti, että data on siirtynyt ennen kuin alkuperäistä poistetaan.

Siitä tulee vielä oma työvaiheensa.

Mitä tästä jäi käteen

Ulkoisen USB-levyn lisääminen kuulostaa helposti vartin työltä: levy kiinni, formatointi ja hakemisto valmiiksi.

EnergyHubin tapauksessa itse levy oli kuitenkin kokonaisuuden vähiten kiinnostava osa.

Oleellisempaa oli päättää, miten sen sallitaan hajota.

Nyt USB-levyn puuttuminen ei estä EnergyHubin käynnistymistä.

Palvelut eivät voi huomaamatta kirjoittaa sen liitospisteeseen järjestelmälevylle.

Varmistukseen hyväksytään vain salattu ja tarkistussummalla varmennettu artefakti.

Skripti tarkistaa myös, että kohteena on juuri oikea fyysinen levy.

Arkistolevy ei voi vahingossa joutua varmistamaan itseään.

Ja itse levyn kuntoa sekä vapaata tilaa seurataan.

Paikallinen USB-kopio täydentää Google Drivessa olevaa off-site-varmistusta, ja samalla EnergyHubilla on ensimmäistä kertaa kunnolla tilaa vuosien mittaiselle historialle.

Arkistointi saa kuitenkin odottaa hetken. Ennen kuin vanhaa dataa kannattaa käyttää pidemmälle menevään analyysiin, pitää varmistaa vielä yksi perustavampi asia: mitä tallennetut mittaukset oikeasti tarkoittavat.

Levy maksoi vähän. Sen tärkein ominaisuus on, että koko EnergyHub on suunniteltu pärjäämään ilman sitä.


Seuraavaksi: kun oikea numero voi tarkoittaa väärää asiaa

EnergyHubissa on nyt paikka, johon vuosien mittainen historia voidaan aikanaan säilyttää.

Mutta ennen kuin vanhasta datasta kannattaa rakentaa lämmitysmallia, vastaan tuli vielä perustavampi kysymys:

tiedämmekö varmasti, mitä kaikki tallentamamme numerot oikeasti tarkoittavat?

Thermian Modbusista löytyy paljon täysin järkevän näköistä dataa. Yksi mittaus kuitenkin herätti epäilyn siitä, että numero saattoi olla aivan oikein — mutta meidän sille antamamme merkitys väärä.

Se muutti työjärjestyksen.

Osassa 30 käyn läpi, miksi lämmityksen mallinnus pysähtyi ja miksi Thermian tärkeät Modbus-mittaukset päätettiin auditoida rekisteri rekisteriltä ennen kuin EnergyHub saa alkaa oppia talon käyttäytymisestä.