12.1. Technická dokumentace
12.1.1. Instalace
Zdrojový kód je kompilován pomocí Apache Maven: mvn clean package -DskipTests
Zkompilovaná aplikace je zabalena v spustitelném archival-storage.jar souboru.
Závislosti:
PostgreSQL
Java 11+ (OpenJDK)
Spuštění aplikace z příkazové řádky
Restartování aplikace spuštěné přímo z příkazové řádky:
pomocí ps xw nalézt PID JAVA procesu archival-storage.jar
kill <PID>
nohup java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 archival-storage.jar $> arcstorage.log
agentlib:jdwp lze vypustit, slouží pro možnost remote debuggingu
pracovní adresář je automaticky adresář z nějž je aplikace spuštěna, lze změnit přepínačem -Duser.dir={cesta}
Spuštění aplikace jako služby
archival-storage.service - vzorový konfigurační soubor pro systemd službu
[Unit]
Description=Archival Storage
After=syslog.target
[Service]
Type=simple
User=ais
Group=ais
WorkingDirectory=/opt/ais/archival-storage
ExecStart=/opt/ais/archival-storage/archival-storage.jar
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
archival-storage.conf - konfigurační soubor systemd služby - vložit do pracovního adresáře aplikace
JAVA_OPTS="-XX:MaxMetaspaceSize=800M -Xmx4096M
12.1.2. Konfigurace
Logování
Logy se ukládají do složky {pracovní adresář}/../logs
Systém
Aplikace je konfigurovatelná skrze soubor application.yml který se nachází v pracovním adresáři. Konfigurační hodnoty v tomto souboru překrývají defaultní konfigurační hodnoty v souboru application.yml nacházejícím se ve složce src/main/resources. Po přepsání souboru je pro projevení změn nutné aplikaci restartovat. Při konfigurování atributů cest na souborovém systému lze zadat relativní cestu vzhledem k pracovnímu adresáři.
server:
port: 8081
tomcat:
# maximální počet aktivních vláken aplikačního serveru - počet HTTP požadavků které mohou být odbaveny paralelně
max-threads: 70
# velikost fronty aplikačního serveru - při vyčerpání aktivních vláken jsou požadavky řazeny do fronty, po naplnění fronty je každý další požadavek zamítnut, velikost fronty je součtem následujících dvou hodnot
accept-count: 1 # min 1
max-connections: 99 # min 1
spring: # databáze
datasource:
url: jdbc:postgresql://localhost:5432/{DB name}
username: {DB username}
password: {DB password}
tomcat:
# default = 100, hodnota musí být vhodně nastavena vzhledem k celkovému počtu vláken které v aplikaci mohou synchronně běžet a s ohledem na PostgreSQL max_conn
max-active: 100
# default = 10, aplikace si již při startu rezervuje 10 PostgreSQL spojení
initial-size: 10
mail: # mail
host: smtp.gmail.com
port: 465
username: {sender mail username}
password: {sender mail password}
protocol: smtp
properties.mail.smtp:
auth: true
starttls.enable: false
ssl.trust: smtp.gmail.com
ssl.enable: true
mail: # mail - konfigurovatelný obsah
sender:
email: {sender mail username}
name: Archival Storage
app:
name: Archival Storage
logo: logo.png
link: http://arclib.inqool.cz
url: http://arclib.inqool.cz
liquibase: # stejné db credentials jako v předchozí sekci
changeLog: classpath:/dbchangelog.arcstorage.xml
url: jdbc:postgresql://localhost:5432/{DB name}
user: {DB username}
password: {DB password}
arcstorage:
consistencyCheck:
# cron dle kterého budou probíhat periodické kontroly stavu balíků na úložišti
cron: "0 */30 * * * ?"
# počet AIP zkontrolovaných v rámci jedné periody kontroly, hodnotu je možné vynechat - v tom případě jsou v rámci periody zkontrolovány všechny dostupné AIPy
count: 10
storageStateCheck:
# cron dle kterého budou probíhat pravidelné reporty stavu logických úložišť
cron: "0 0 8 ? * 2"
threadPools:
# počet vláken aplikace rezervovaných pro asynchronní zpracování požadavků na uložení a mazání objektů
batchOps: 16
# počet vláken rezervovaných pro periodické procesy, např. kontrolu dostupnosti úložišť
scheduled: 2
# pracovní adresář aplikace do kterého jsou mimo jiné nahrávány objekty při cestě do úložiště a z úložiště
tmpFolder: tmp
# mez velikosti pracovního adresáře v MB, po jejímž dosažení přestane aplikace přijímat jakékoliv požadavky na uložení objektů
tmpFolderUploadSizeLimit: 500000
# timeout pro navázání spojení s vzdálenými logickými úložišti, v milisekundách
connectionTimeout: 5000
# timeout pro transakce při nichž se mění stav AIP, v sekundách
stateChangeTransactionTimeout: 5
# v případě požadavku na přípojení nového logického úložiště musí do tohoto timeoutu (sekundy) všechny rozpracované objekty změnit svůj stav, pokud se tak nestane, synchronizace nezačne
synchronizationInitTimeout: 15
# při nastavení true jsou při startu aplikace promazány/vyčištěny všechny objekty které nejsou v finálním požadovaném stavu
cleanUpAtApplicationStart: false
# cesta k adresáři do kterého jsou exportovány data pro zálohování
backupDirPath: backup
# cesta k privátnímu klíči kterým se archival storage autentizuje skrze SSH v případě logického úložiště na vzdáleném serveru
ssh:
authKey: arcstorage.ppk
userName: {username}
optionalFeatures:
# true pro zapnutí volitelné funkcionality Forget
forgetObject: false
# true pro zapnutí volitelné funkcionality Inkrementálního zálohování
incrementalBackup: false
# určení prostředí
env: production
Cron používaný aplikací musí být ve formátu: second, minute, hour, day of month, month, day(s) of week.
12.1.3. Databáze
Všechny entity používají UUID.
Tabulky jsou generovány při prvním spuštění aplikace.
Aplikačnímu serveru musí být povolen přístup k DB s přihlašováním typu “md5”
Systémové účty
Archival Storage je systémová komponenta - neautentizují se vůči ní běžní uživatelé ale systémy. Archival Storage může sloužit více systémům, kde každý má svůj dataspace a v něm separátně uložená data. V případě logických úložišť realizovaných souborovým systémem je dataspace reprezentován složkou. Hodnota dataspace by měla obsahovat pouze malá písmena ASCII tabulky (a-z).
Pro každý dataspace může existovat několik účtů, typicky jsou však právě dva, jeden pouze pro čtení a druhý pro čtení i zápis. Jedná se o účty s rolemi ROLE_READ a ROLE_READ_WRITE. Pro jeden systém musí mít oba účty stejnou hodnotu dataspace. Email u tohoto účtu není prozatím využíván, není povinný.
Třetí rolí v systému je ROLE_ADMIN - tento typ účtu je používán výlučně administrátorem, autorizuje ho především ke konfiguraci logických úložišť ale neautorizuje ho pro běžné požadavky na práci s objekty. Tento typ účtu nemusí mít přidělen dataspace, naopak je vhodné aby měl přidělen email, na který jsou zasílány notifikace o neočekávaných chybách apod.
Účty jsou uloženy v tabulce arcstorage_user. Systém se vůči Archival Storage autentizuje skrze Basic Auth. Heslo je v DB zašifrováno pomocí BCrypt (pro vygenerování za účely testu lze použít např. https://bcrypt-generator.com/).
Systém
Tabulka arcstorage_system_state obsahuje záznamy:
min_storage_count
hodnota je kontrolována při startu aplikace, v případě nedostatečného počtu logických úložišť jsou uživatelé s rolí ADMIN notifikování emailem, aplikace však běží dál
hodnota je také kontrolována při odebírání úložiště skrze API
read_only
při nastavení systém zamítá operace na uložení nebo úpravu stavu objektů
systém sám nastavuje readOnly=true na začátku a na konci synchronizace, v případě že v tabulce arcstorage_storage_sync_status existuje záznam s hodnotou phase rovnou INIT nebo POST_SYNC_CHECK, administátor by neměl atribut editovat
reachability_checkInterval_in_minutes
automaticky updatuje hodnotu reachable logických úložišť v tabulce arcstorage_storage
změna skrze API je propagována bez nutnosti restartu aplikace
last_reachability_check, last_verified_object_creation
řídící atributy, spravovány systémem
V tabulce se musí vždy nacházet právě jeden záznam. Při prvním spuštění aplikace je vyplněn záznam defaultní konfigurace:
min_storage_count=2
read_only=false
reachability_checkInterval_in_minutes=60
Logické úložiště
K systému může být připojeno jedno či více logických úložišť, čímž je zajištěna redundance na úrovni Archival Storage. K jednotlivým úložištím je přistupováno skrze Java rozhraní StorageService, které zajišťuje abstrakci od konkrétní technologie. V současnosti existují implementace pro obyčejný filesystém (FS), ZFS a Ceph. V případě FS/ZFS je navíc podporováno jak lokální úložiště (případně mapované např. skrze NFS) tak přístup přes SSH ke vzdálenému serveru.
Tabulka arcstorage_storage obsahuje záznam pro každé připojené logické úložiště.
host
pokud je při FS/ZFS nastaveno localhost nebo 127.0.0.1 je automaticky použita implementace pro lokální/mapovaný FS, v ostatních případech je použito SSH
port v případě lokálního FS/ZFS ignorován
priority
pro čtení se používá úložiště s nejvyšší prioritou, pokud je takových více, je jedno z nich náhodně vybráno
v současnosti není implementováno žádné automatické vyvažování, tedy hrozí že úložiště s nejvyšší prioritou bude při intenzivním čtení vytíženo
type (FS/ZFS/CEPH)
reachable
Nastavován automaticky při každém požadavku na úložiště (všechny logické úložiště jsou kontrolovány na dostupnost). Úložitě které nejsou dostupné nejsou použitelné pro čtení. Pokud je v systému alespoň jedno nedostupné úložiště, systém se chová jako by byl read-only. Dostupnost je také kontrolována periodicky dle intervalu nastaveném v application.yml
synchronizing
řídící atribut, spravován systémem
config JSON s atributy specifickými dle typu úložiště
Další tabulky
arcstorage_aip_sip - entita reprezentující datovou část AIP (zip)
arcstorage_aip_xml - entita AIP XML
arcstorage_object
Archival Storage je navrhnuto s myšlenkou nevázat se pouze na případ užití AIP ale umožnit i práci s objekty obecně. Tato podpora není doimplementovaná, tabulka zůstává prázdná.
arcstorage_object_audit
Operace DELETE, ROLLBACK, ARCHIVAL_RETRY, REMOVE a RENEW jsou zaznamenány do databáze a použity při synchronizaci nového úložiště a exportu dat do úložiště pro zálohování
arcstorage_storage_sync_status
Informace o probíhající/proběhlé synchronizaci nově přidaného úložiště
12.1.4. Konfigurace logických úložišť
Pro připojení úložiště je z administrátorského účtu volán endpoint POST /api/administration/storage s JSON konfiguračním souborem v těle requestu.
Lokální FS
Příkladový JSON
{
"id": "4fddaf00-43a9-485f-b81a-d3a4bcd6dd83",
"name": "local storage",
"host": "localhost",
"port": 0,
"priority": 10,
"storageType": "FS",
"note": null,
"config": "{\"rootDirPath\":\"d:\\\\arcstorage\"}",
"reachable": true
}
rootDirPath je cesta ke kořenovému adresáři pro ukládání souborů * v tomto adresáři je pro každého uživatele vytvořena složka pojmenovaná dle hodnoty dataspace * aplikace musí mít k této složce R/W přístup
Vzdálený FS
na vzdáleném serveru je třeba založit arcstorage uživatele a přidat jeho veřejný klíč
pokud se jedná o ZFS, arcstorage uživatel musí mít na serveru passwordless sudo oprávnění aby mohly být příkazy zfs list a zpool list volány skrze SSH
atribut port je nastaven na číslo SSH portu
ZFS
Defaultně může ZFS příkazy volat pouze root, pro povolení ostatním sudo uživatelům (arcstorage user) lze vytvořit zfs soubor v /etc/sudeoers.d, s následujícím obsahem:
Cmnd_Alias C_ZFS = \
/sbin/zfs "", /sbin/zfs help *, \
/sbin/zfs get, /sbin/zfs get *, \
/sbin/zfs list, /sbin/zfs list *, \
/sbin/zpool "", /sbin/zpool help *, \
/sbin/zpool iostat, /sbin/zpool iostat *, \
/sbin/zpool list, /sbin/zpool list *, \
/sbin/zpool status, /sbin/zpool status *, \
/sbin/zpool upgrade, /sbin/zpool upgrade -v
ALL ALL = (root) NOPASSWD: C_ZFS
Příkladový JSON
{
"id": "c7c1b592-d32f-4848-b28b-59edaaa4fbb7",
"name": "zfs",
"host": "176.74.145.50",
"port": 22,
"priority": 10,
"storageType": "ZFS",
"note": null,
"config": "{\"rootDirPath\":\"/opt/data/test\",\"poolName\":\"arcpool\"}",
"reachable": true
}
ZFS config obsahuje kromě rootDirPath i název ZFS poolu
Ceph
je nutné nainstalovat Ceph a RGW http://docs.ceph.com/docs/master/start/
instalace může zabrat několik hodin, vyžaduje infrastrukturu uzlů a administrátorský uzel z něhož jsou řízeny
dle CEPH RGW manuálu je vytvořen uživatel
Pro získání stavu Cephu musí RGW server umožnit SSH připojení aplikace (uživatel arcstorage, použit je stejný klíč jako v případě vzdáleného FS). Navíc musí mít tento uživatel na RGW serveru passwordless sudo práva, aby mohla aplikace skrze SSH zavolat příkazy ceph df a ceph -s
Příkladový JSON
{
"name": "ceph",
"host": "192.168.10.61",
"port": 7480,
"priority": 1,
"storageType": "CEPH",
"note": null,
"config": "{\"adapterType\":\"S3\", \"userKey\":\"SKGKKYQ50UU04XS4TA4O\",\"userSecret\":\"TrLjA3jdlzKcvyN1vWnGqiLGDwCB90bNF71rwA5D\",\"sshPort\":2226,\"https\":\"true\"}",
"reachable": true,
"virtualHost": false,
"id": "8c3f62c0-398c-4605-8090-15eb4712a0e3"
}
port je Ceph RADOS gateway port
config obsahuje
adapterType - v současnosti podpora pouze pro S3
userKey a userSecret - údaje použité pro přístup k Ceph S3 clusteru
sshPort ssh port na kterém RGW instance naslouchá
virtualHost true pokud mají být buckety na RGW instanci adresované skrze doménu místo cesty, viz https://docs.ceph.com/docs/mimic/radosgw/s3/commons/
https true/false
12.1.5. Lazení výkonu
Aplikační server
Požadavek na uložení má synchronní a asynchronní část. V synchronní části jsou vstupní soubory nahrány do workspace Archival Storage, zkontrolovány jejich kontrolní součty po přenosu a je zaznačen začátek zpracování. Následně je vlákno aplikačního serveru vráceno do poolu a požadavek je dále zpracováván asynchronně. Vlákna aplikačního serveru jsou konfigurovány v sekci server.tomcat. V případě že je počet vláken AS vyčerpán a fronty zaplněny, každý další požadavek končí chybou „Connection refused“.
Archival Storage
Archival storage zamítne požadavek na jakýkoliv datový i metadatový update pokud velikost jeho workspace přesáhne konfigurovaný limit (503). Cestu do workspace i limit je možné konfigurovat v souboru application.yml: arcstorage.tmpFolder, arcstorage.tmpFolderUploadSizeLimit Např. pokud je průměrná velikost balíku 0.5GB, parametr je nastaven na 5GB a zrovna jsou exportovány čtyři balíky (z čtyř dávek), zbývá 3 GB pro 6 nových zápisů (z 6 dávek) přičemž 7. už povolen není, i kdyby bylo dostupných X vláken.
Vhodným nastavením parametru lze počet právě probíhajících zápisů a tedy zátěž Archival Storage rozumně limitovat a takto lze zajistit dostatečný výpočetní výkon pro odbavování exportů a chodu systému. V případě že limit není nastaven vůbec, může se workspace zaplnit natolik že nebude fungovat např. při exportu. Pokud limit není nastaven, Archival Storage zamítne požadavek pouze v hraničním případě kdy dojde místo na disku workspace (500). Všechny požadavky na uložení které nejsou zamítnuty jsou frontovány a postupně zpracovány.
Poznámka: Hodnota volného místa ve workspace musí být minimálně dvojnásobek velikosti vkládaného objektu.
Postgres
Vzhledem k tomu že jeden databázový server může využívat více aplikací, může lehce dojít k tomu že defaultní počet connections které poskytuje PostgreSQL (100) nebude stačit.
Konfigurace by měla být taková že PGSQL max_conn musí být větší než součet hodnot spring.datasource.tomcat.max-active všech připojených aplikací, je vhodné navíc ponechat pár connections volných pro případné ostatní klienty. V opačném případě může tomcat JDBC pool vyhodit při pokusu o získání connection chybu FATAL: sorry, too many clients already
Dále by mělo platit že spring.datasource.tomcat.max-active je větší než definovaný počet paralelních vláken aplikace, tedy aby každé vlákno mělo zajištěno jedno spojení z poolu. Počet paralelních vláken aplikace není pouze součtem server.tomcat.max-threads (vlákna AS pro synchronní zpracování) se všemi programátorem definovanými pooly (arcstorage.threadPools), navíc si je totiž aplikace schopna tvořit vlákna pro asynchronní zpracování dle potřeby. Aplikace si takto tvoří vlákna v případech kdy není vhodné aby byla limitována, např. při synchronním uložením AIP XML skrze GUI, při automatické opravě v případě že je zjištěna chyba při namátkové kontrole, při exportu do adresáře pro zálohování nebo při synchronizaci nového úložiště, při čištění úložiště od nekompletních uploadů apod. Ve většině těchto případů se jedná o jednorázové operace, i přesto je však vhodné nechat pro tyto operace pár desítek connections v rezervě.
K stabilitě systému přispívá že transakční je pouze část operací vlákna, vlákno tedy nedrží spojení po celou dobu svého běhu, přesto je vhodné dodržet výše zmíněná opatření a snažit se udržet vztah počet dostupných spojení > maximální počet souběžně běžících vláken.
12.1.6. Zálohování a obnova
Postup pro zálohování
Pro zálohování úložiště je použit backup endpoint (GET /api/administration/backup) který provede export všech nových objektů a nových stavových souborů existujících objektů zaznamenaných v daném časovém intervalu do adresáře specifikovaném v application.yml (arcstorage.backupDirPath). Volání vyžaduje autorizační header uživatele s rolí ROLE_ADMIN (basic auth). Odpověď je vrácena ihned po kontrole možnosti zápisu/čtení do backup adresáře, samotný export poté probíhá asynchronně, průběh je zaznamenáván v logu. Administrátor ve větších časových intervalech provádí plnou zálohu, v menších intervalech provádí zálohu inkrementální. Za tímto účelem vytvoří na úrovni OS skript z který backup endpoint periodicky provolává. Časový interval je zadán jako query param (since,until) v formátu odpovídajícím ISO-8601 formátu (nelze však zadat jakýkoliv ISO-8601 formát, časová značka musí být v UTC formátu s přesností alespoň na sekundy, volitelně milisekundy). Příklad: /api/administration/backup?since=2019-10-27T:16:16:40.700Z&until=2019-10-27T17:16:40Z. Oba parametry jsou volitelné, v případě nevyplnění není výsledek časově zdola/shora omezen. Nevyplnění ani jednoho parametru zodpovídá plné záloze.
Zálohu databáze Archival Storage doporučujeme provádět společně s zálohováním databází ostatních modulů systému nativní PostgreSQL utilitou pg_dump, pro následnou obnovu do předvytvořené databáze lze použít pg_restore, příklad:
pg_dump -U postgres -W -F t {dbname} > backup.tar
pg_restore -U postgres –dbname={dbname} backup.tar
Postup při obnově
AIS očekává že v složce z které čte data k obnově jsou soubory uloženy přesně tak jak je v průběhu času exportoval do exportní složky. Takováto data jsou téměř zrcadlovým obrazem reálných dat zálohovaného logického úložiště. Při obnově je vytvořen v DB záznam pro FS/ZFS logické úložiště a rootDirPath je nastaven na složku obsahující všechna data k obnově.
Při obnově je potřebné vypnout script provádějící zálohování. Některé operace vyžadují systém v read-only režimu. Systém lze do režimu přepnout přímo editací tabulky arcstorage_system_state nebo skrze endpoint POST /api/administration/config
Níže jsou detailněji popsány způsoby obnovy dle situací které mohou nastat.
K dispozici je pouze záloha úložiště
1.1 Je spuštěna aplikace, čímž se vytvoří defaultní záznam konfigurace systému.
1.2) Je vytvořen záznam pro FS/ZFS logické úložiště, rootDirPath je nastaven na složku obsahující všechna data k obnově.
1.3) Do DB je vložen nový záznam ADMIN účtu (tabulka arcstorage_user).
1.4) Do DB je vložen nový záznam R/W účtu. Atribut dataspace se musí shodovat s atributem dataspace původního AIS systémového R/W účtu, respektive musí se shodovat s názvem kořenové složky exportované do exportní složky.
1.5) Je volán endpoint POST /api/administration/recover_db?storageId={UUID logického úložiště} (ADMIN, při volání musí úložiště běžet v read-only režimu)
K dispozici je záloha DB i záloha úložiště
2.1) DB je obnovena ze zálohy
2.2) Je zajištěno že všechna exportovaná data jsou zkopírována do lokace rootDirPath dříve existujícího logického FS/ZFS úložiště.
2.3) Je spuštěna aplikace, konfigurační hodnota arcstorage.cleanUpAtApplicationStart=false (application.yml)
2.4) Pokud je záloha DB starší než záloha úložiště, je volán endpoint POST /api/administration/recover_db?storageId={UUID logického úložiště}&override=true (ADMIN, při volání musí úložiště běžet v read-only režimu)
2.5) Je volán endpoint POST /api/administration/cleanup?all=true
2.6) Pokud je záloha DB novější než záloha úložiště, je nastavena periodická kontrola systému tak aby proběhla nad všemi objekty. Tímto způsobem administrátor zjistí která data jsou na úložišti v nekonzistentním stavu a manuálně zasáhne buď do úložiště nebo databáze. Alternativně lze pro rychlejší detekci inkonzistence použít POST /api/administration/recover_db?storageId={UUID logického úložiště}&override=false - proces na konci loguje veškeré konfliktní objekty a objekty které jsou uloženy v DB ale nejsou na úložišti. Narozdíl od předchozího způsobu však nekontroluje kontrolní součty objektů jež konfliktní nejsou.
K dispozici je záloha úložiště, DB je aktuální
DB je aktuální (není obnovena ze zálohy, nebyla ztracena). Provedou se akce 2.2, 2.3, 2.5, 2.6 z předchozího scénáře.
12.1.7. Instalace v kontextu AIS
Pro instalaci v AIS je pro Archival Storage dodán samostatný instalační balíček.
- Databáze je iniciována z DB dumpu arcstorageDump.bin který obsahuje:
záznamy AIP migrovaných archiválií (v tabulkách arcstorage_aip_sip a arcstorage_aip_xml)
defaultní hodnoty v tabulce arcstorage_system_state
jedno logické úložiště typu FS v tabulce arcstorage_storage (záznam v DB administrátor upraví aby odpovídal požadované lokaci migrovaných AIP, viz níže)
3 systémové účty s rolemi ROLE_READ, ROLE_READ_WRITE, ROLE_ADMIN (opět se předpokládá úprava v DB administrátorem)
Kromě DB dumpu je dodán také soubor local-storage-folder.zip obsahující kompletní obsah úložiště po již provedené migraci (obsahuje AIP zaznamenané v arcstorageDump.bin) - extrahovat do složky úložiště nakonfigurované v DB (v dodaném dumpu se jedná o složku local-storage-folder v pracovním adresáři aplikace).
Dále jsou dodány tyto přílohy:
archival-storage.jar - zkompilovaná aplikace
application.yml - konfigurační soubor překrývající defaultní konfiguraci - vložit do pracovního adresáře aplikace. Jedná se o vzorový soubor, jednotlivé konfigurační hodnoty může být nutné upravit dle konkrétního prostředí.
arcstorageInitDump.bin - iniciální Archival Storage DB dump s předkonfigurovaným úložištěm a účty který je možné použít v rámci procesu migrace mezivýstupu z DB PEVA II do DB AIS