vdmfec + lbzip2 (Re: SMP tömörítő program Linux alatt)

Erre a hozzászólásra kezdtem reagálni, de annyira meghízott a válaszom, hogy inkább külön posztot csinálok belőle.

ha igazan biztonsagos tomorito kell, akkor bizony nagyon jo a rar.

Nem vitatom, a rar valóban nagyon jó, de azért a UNIX(R) filozófia szellemében ezt is össze lehet tenni több programból. Konkrétan a "vdmfec"-re gondolok.

Upstream, debian csomagok. (Azért a vdmfec az érdekes, mert az támogatja a pipe-okat is; ha csak simán disk image-eket kell kiegészíteni a Reed-Solomon hibajavító kóddal, akkor dvdisaster.)

A vdmfec-nek három paraméter kell (sajnos kicsomagoláskor is pontosan ugyanazokat kell megadni): (1) mekkora blokkmérettel dolgozzon, (2) hány db blokkot [K] (3) hány db blokkon [N] terítsen szét redundánsan. A hibátlan visszaolvasáshoz az kell (és az elegendő), ha bármely N-es kötegen belül bármely K db blokk hibátlan. A méretnövekedés aránya N/K (+ metadata).

A legjobb megoldásnak az tűnne, ha az egész kimenetet egyetlen irdatlan kötegnek tekintenénk (N), hogy ezen belül tetszőlegesen el tudjon oszolni a K. (Minél kisebb kötegméretet választunk azonos aránnyal, annál rövidebb abszolút adatmennyiségben az a helyi burst, amit túl tud élni a kódolás.) Így érdemes N-t maximalizálni. Azonban -- feltehetően -- minél nagyobb a köteg (N * blokkméret), annál több memória kell a feldolgozáshoz, illetve annál inkább lépcsősen fog jelentkezni a vdmfec CPU igénye. (Nagyobb buffer kell a tömörítő és a vdmfec közé.) Mivel a programban N korlátozva van 256-ra, aminek az előbb leírt CPU-lépcsőzési hatása és extra memóriaigénye valószínűleg észrevehetetlen, azért N-t rögzítsük is mindjárt 256-ra.

A blokkméretet szerintem minimalizálni érdemes, mert ez jobb felbontásúvá teszi a hibajavító kódot. Kisebb blokkmérettel a generált file-ban a metadata mennyisége növekszik. Ennek a jelentősége azonban elenyésző; itt egy mérés, 18/14-es default N/K aránnyal, 1K-tól 128K-ig terjedő blokkmérettel; az alapfile 1.1 GB-s:


1428350976 z.1k
1415282688 z.2k
1408868352 z.4k
1405698048 z.8k
1404076032 z.16k
1403781120 z.32k
1403781120 z.64k
1403781120 z.128k

Látható, hogy 32K fölé nem is érdemes menni (onnantól már semmit sem tudunk megtakarítani), ugyanakkor az 1K-s mód a 32K-s (legtakarékosabb) módhoz képest is csak ~ 1.75%-nyi plusz metaadatot generál. Így ezt egyszerűen állítsuk be a cél adathordozó szektorméretére és kész. (Egyébként valami ilyesmit ajánl a vdmfec manual-ja is.) Most legyen ez 2K (a CD/DVD adatszektor-méretből kiindulva.)

Mivel én redundanciának 20%-ot szoktam használni a dvdisaster-hez, ezzel meg is van minden adatunk:

  • N = 256,
  • N/K = 1.2 = 12/10 = 6/5; vagyis K = 5/6 * 256. Mivel így K nem volna egész szám, azért dönthetünk, hogy vagy N-t módosítjuk, vagy nem ragaszkodunk pontosan a 20%-os arányhoz. Én az N=256-hoz ragaszkodom, így az (5 * 256) / 6-ot "C aritmetikával" számolva 213-at kapunk. N/K = 256 / 213 ~= 1.2.
  • Blokkméret = 2 KB

Innentől be is drótozhatjuk egy "myvdmfec" script-be, hogy


exec vdmfec -b 2K -n 256 -k 213 "$@"

Na, akkor ezzel a script-tel mérjünk egyet! Összetaroltam a /usr/bin-t és a /usr/lib-et magamnál, a (tömörítetlen) archív mérete a fent már említett 1.1 GB. Mivel pipeline-ba fogjuk kötni a tömörítőt a vdmfec-cel, azért az utóbbi teljesítményét a tömörített állományon fogjuk vizsgálni, viszonyítva a bzip2 CPU igényéhez és kimeneti sebességéhez. (Elsőre a standard bzip2-t nézem meg, a saját gépemen.)


$ 'time' -p bzip2.orig -c testfile.tar 2>orig.time | pv >orig.bz2
 347MB 0:03:34 [1.62MB/s]

$ cat orig.time 
real 214.77
user 197.21
sys 1.15

(Úgy látszik, közben néha valami megfogta a diszket is egy kicsit.) Mindenesetre ezzel nem nehéz megbirkóznia a vdmfec-nek:


$ pv orig.bz2 | 'time' -p myvdmfec 2>orig.vdm.time >orig.bz2.vdm 
 347MB 0:00:18 [19.2MB/s]

$ cat orig.vdm.time 
real 18.11
user 17.24
sys 0.58

Úgy néz ki, hogy ha a bzip2 kimeneti sebességét 11-gyel megszorozzuk (11 worker thread), akkor még bele fogunk férni az egyszálú vdmfec input-feldolgozási sebességébe. Más szóval, valahol 11 és 12 szál között kell lefojtania egy párhuzamos bzip2 tömörítőt a vele össze-pipe-olt vdmfec-nek (ha van legalább 13 szabad mag -- egy mag a vdmfec-nek, a többi az lbzip2-nek (például)).

Na, akkor most nézzük meg egerész ko-hupper :) hpc2009 projektjének fejgépén (8 mag, HT off) a kettőt együtt :) Az input állomány hasonló összetételű, mérete 1.4 GB.


$ pv -c -N plain testfile.tar \
| 'time' -p lbzip2 2>lbzip2.time \
| pv -c -N compr \
| 'time' -p myvdmfec 2>vdmfec.time \
| pv -c -N vdm >testfile.tar.bz2.vdm

    plain:  1.3GB 0:00:36 [36.2MB/s]
    compr:  439MB 0:00:37 [11.7MB/s]
      vdm:  532MB 0:00:37 [14.2MB/s]

$ cat lbzip2.time
real 37.57
user 249.15
sys 2.41

$ cat vdmfec.time 
real 37.62
user 27.44
sys 0.48

A teljes CPU idő 279.48 másodperc; valós időnek 37.62 másodpercet tekintve a hányados kb. 7.43. Néztem közben a top-ot is, időnként voltak akár 10%-ot is elérő idle time-ok. Ezeket én betudom ütemezési anomáliának, ugyanis az lbzip2 önmagában felmegy 786%-ra ezen a file-on, a vdmfec önmagában pedig (természetesen) 100%-ra. De azért ez a 7.43 egy 8 magos gépen elég jó.

A dekódolás/ellenőrzés így néz ki:


$ pv -c -N vdm testfile.tar.bz2.vdm \
| 'time' -p myvdmfec -d 2>vdmfec-d.time \
| pv -c -N compr \
| 'time' -p lbzip2 -d 2>lbzip2-d.time \
| pv -c -N plain \
| cmp - testfile.tar

      vdm:  532MB 0:00:13 [40.2MB/s]
    compr:  439MB 0:00:13 [33.1MB/s]
    plain:  1.3GB 0:00:14 [94.3MB/s]

$ cat vdmfec-d.time 
real 13.32
user 2.00
sys 0.30

$ cat lbzip2-d.time 
real 14.25
user 105.77
sys 1.63

Teljes CPU idő 109.7 másodperc; valós időnek 14.25 mp-t tekintve a hányados ~7.7.

(Ha valakit érdekelne, az egyszálú, standard bzip2 kitömörítés ideje (real, user, sys): 68.45, 68.32, 0.12.)

Akinek ez a bejegyzés tetszett, az próbálja ki az lbzip2-t, ha még nem tette volna :)

/* shameless plug */

Hozzászólások

Hmm... Gyorsan rákerestem, hogy a "recovery volumes" funkcióra is alkottak-e valami open source programot.

És igen: par2 néven fut

Beírom ide, bár lehet másoknak nem újdonság...

par2

Így igaz. Ez volt az első, amit megnéztem, de ez nem dolgozik mással, csak reguláris file-okkal. (Belekukkantottam a Lenny csomag forrásába, más típusú file-okat élből elutasít.)

Böhöm archívok készítésekor elég fontos (szerintem), hogy menjen pipe-ból pipe-ba. Elvileg ilyenkor meg kell nézni (pipefail bash opcióval vagy a PIPESTATUS bash tömböt kurkászva), hogy a pipeline minden tagja sikeresen befejeződött-e. Ettől az archiválásnál esetleg el lehet tekinteni, mert az ember (pontosabban a script) amúgy is leellenőrzi, hogy a kiírt állomány teljes és helyes-e.

Ehhez egy jó módszer közvetlenül a tar után betenni egy ilyet a pipeline-ba (bash process subst):


$ tar -c ... \
| tee >(md5sum >archive.tar.md5) \
| lbzip2 \
| gpg -z0 ... \
| myvdmfec \
| ...

Az archiválás végén elég az md5-öt újraszámolni/ellenőrizni (md5sum -c).


$ ... \
| myvdmfec -d \
| gpg -d ... \
| lbzip2 -d \
| md5sum -c archive.tar.md5

Az md5 néhány dologra ma már nem jó, erre még nagyon is. A gpg természetesen titkosít és az integritást is védi, a fentinek azonban az a célja, hogy az archívum helyességét tartalmilag ellenőrizzük. Például ha az lbzip2 kimenetében valami hiba volna, az ellen a gpg már nem védene ("garbage in, garbage out").

Az igazi persze az

md5sum -c

helyett a

tar --compare

lenne, de az egyrészt túlzás, másrészt néha nem is megoldható.

Hm. Már csak azt nem tudom, hogy miért nincs ez FreeBSD-n portsban.