Cwympo i Lawr y Twll Cwningen: Stori Methiant Ail-lwytho Un Farnais - Rhan 1

ysbrydinushanka, ar ôl bod yn morthwylio’r botymau am yr 20 munud blaenorol fel petai ei fywyd yn dibynnu arno, yn troi ataf gyda golwg lled-wyllt yn ei lygaid a gwên slei – “Dude, I think I got it.”

“Edrychwch yma,” meddai, gan bwyntio at un o'r symbolau ar y sgrin, “Fe wnes i fetio fy het goch, os ydyn ni'n ychwanegu yma yr hyn rydw i newydd ei anfon atoch chi,” gan bwyntio at adran arall o'r cod, “ni fydd y gwall bellach. yn cael ei arddangos."

Ychydig yn ddryslyd ac wedi blino, rwy'n addasu'r mynegiant sed rydyn ni wedi bod yn gweithio arno ers tro, cadw'r ffeil a rhedeg systemctl varnish reload. Mae'r neges gwall wedi diflannu...

“Y negeseuon e-bost y gwnes i eu cyfnewid â’r ymgeisydd,” parhaodd fy nghydweithiwr, wrth i’w wên dyfu’n wên o lawenydd gwirioneddol, “Gwawriodd arnaf yn sydyn mai’r un broblem yn union yw hon!”

Sut y dechreuodd y cyfan

Mae'r erthygl yn rhagdybio dealltwriaeth o sut mae bash, awk, sed a systemd yn gweithio. Mae gwybodaeth am farnais yn well, ond nid yw'n ofynnol.
Mae stampiau amser mewn pytiau wedi'u newid.
Ysgrifennwyd gyda ysbrydinushanka.
Mae'r testun hwn yn gyfieithiad o'r gwreiddiol a gyhoeddwyd yn Saesneg bythefnos yn ôl; cyfieithiad boicoden.

Mae'r haul yn tywynnu trwy'r ffenestri panoramig ar fore hydref cynnes arall, paned o ddiod llawn caffein wedi'i baratoi'n ffres yn gorffwys i ffwrdd o'r bysellfwrdd, mae'ch hoff symffoni o symffoni yn swnio yn eich clustffonau, yn boddi siffrwd allweddellau mecanyddol, a'r cofnod cyntaf yn y rhestr o docynnau ôl-groniad ar fwrdd Kanban yn disgleirio’n chwareus gyda’r teitl tyngedfennol “Ymchwilio i varnishreload” sh: adlais: gwall I/O wrth lwyfannu” (Archwiliwch “varnishreload sh: adlais: gwall I/O” yn y llwyfannu). O ran farnais, mae ac ni all fod unrhyw le i wallau, hyd yn oed os nad ydynt yn arwain at unrhyw broblemau fel yn yr achos hwn.

Ar gyfer y rhai nad ydynt yn gyfarwydd â varnishreload, mae hwn yn sgript cragen syml a ddefnyddir i ail-lwytho'r ffurfweddiad farnais - a elwir hefyd yn VCL.

Fel y mae teitl y tocyn yn ei awgrymu, digwyddodd y gwall ar un o'r gweinyddwyr ar y llwyfan, a chan fy mod yn siŵr bod y llwybriad farnais ar y llwyfan yn gweithio'n iawn, cymerais mai camgymeriad bach fyddai hwn. Felly, dim ond neges a ddaeth i ben mewn ffrwd allbwn sydd eisoes wedi'i chau. Cymeraf y tocyn i mi fy hun, yn gwbl hyderus y byddaf yn ei farcio'n barod mewn llai na 30 munud, yn rhoi fy hun ar y cefn i glirio'r bwrdd o sbwriel arall eto ac yn dychwelyd at faterion pwysicach.

Chwalu i mewn i wal ar 200 km/h

Wrth agor y ffeil varnishreload, ar un o'r gweinyddwyr sy'n rhedeg Debian Stretch, gwelais sgript cragen yn llai na 200 llinell o hyd.

Ar ôl mynd trwy'r sgript, ni sylwais ar unrhyw beth a allai arwain at broblemau wrth ei redeg sawl gwaith yn uniongyrchol o'r derfynell.

Wedi'r cyfan, mae hwn yn gam, hyd yn oed os yw'n torri, ni fydd neb yn cwyno, wel ... dim gormod. Rwy'n rhedeg y sgript ac yn gweld beth fydd yn cael ei ysgrifennu i'r derfynell, ond nid yw'r gwallau bellach yn weladwy.

Mae cwpl arall yn rhedeg i sicrhau na allaf atgynhyrchu'r gwall heb unrhyw ymdrech ychwanegol, ac rwy'n dechrau darganfod sut i newid y sgript hon a'i gwneud yn dal i daflu gwall.

A all y sgript ddiystyru STDOUT (gan ddefnyddio > &-)? Neu STDERR? Ni weithiodd yr un o'r rhain yn y diwedd.

Mae'n debyg bod systemd rhywsut yn addasu'r amgylchedd cychwyn, ond sut, a pham?
Rwy'n agor vim ac yn golygu varnishreload, gan ychwanegu set -x reit o dan y shebang, gan obeithio y bydd allbwn dadfygio'r sgript yn taflu rhywfaint o oleuni.

Mae'r ffeil wedi'i chywiro, felly rwy'n ail-lwytho farnais a gweld bod y newid wedi torri popeth yn llwyr... Mae'r gwacáu yn llanast llwyr, lle mae tunnell o god tebyg i C. Nid yw hyd yn oed sgrolio yn y derfynell yn ddigon i ddod o hyd i ble mae'n dechrau. Dwi wedi drysu'n llwyr. A all modd dadfygio effeithio ar weithrediad rhaglenni a lansiwyd mewn sgript? Na, mae'n nonsens. Byg yn y plisgyn? Mae sawl senario posib yn rasio trwy fy mhen fel chwilod duon i gyfeiriadau gwahanol. Mae cwpan y ddiod â chaffein yn cael ei wagio ar unwaith, taith gyflym i'r gegin i ailgyflenwi'r stoc a... bant â ni. Rwy'n agor y sgript ac yn edrych yn agosach ar y shebang: #!/bin/sh.

/bin/sh - dim ond symlink i bash yw hwn, felly dehonglir y sgript yn y modd sy'n gydnaws â POSIX, iawn? Nid felly! Y gragen rhagosodedig ar Debian yw dash, a dyna'n union sut olwg sydd arno. yn cyfeirio /bin/sh.

# ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 24  2017 /bin/sh -> dash

Fel prawf, newidiais y shebang i #!/bin/bash, dileu set -x a cheisio eto. Yn olaf, ar ôl ailgychwyn farnais wedi hynny, ymddangosodd gwall goddefadwy yn yr allbwn:

Jan 01 12:00:00 hostname varnishreload[32604]: /usr/sbin/varnishreload: line 124: echo: write error: Broken pipe
Jan 01 12:00:00 hostname varnishreload[32604]: VCL 'reload_20190101_120000_32604' compiled

Llinell 124, dyma fe!

114 find_vcl_file() {
115         VCL_SHOW=$(varnishadm vcl.show -v "$VCL_NAME" 2>&1) || :
116         VCL_FILE=$(
117                 echo "$VCL_SHOW" |
118                 awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}' | {
119                         # all this ceremony to handle blanks in FILE
120                         read -r DELIM VCL_SHOW INDEX SIZE FILE
121                         echo "$FILE"
122                 }
123         ) || :
124
125         if [ -z "$VCL_FILE" ]
126         then
127                 echo "$VCL_SHOW" >&2
128                 fail "failed to get the VCL file name"
129         fi
130
131         echo "$VCL_FILE"
132 }

Ond fel mae'n digwydd, mae llinell 124 yn eithaf gwag ac o ddim diddordeb. Ni allwn ond tybio bod y gwall wedi digwydd fel rhan o linyn aml-linell yn dechrau ar linell 116.
Beth sydd wedi'i ysgrifennu i'r newidyn yn y pen draw? VCL_FILE o ganlyniad i weithredu'r is-gragen uchod?

Ar y dechrau, mae'n anfon cynnwys y newidyn VLC_SHOW, a grëwyd ar linell 115, yn dilyn y gorchymyn trwy'r bibell. Ac yna beth sy'n digwydd yno?

Yn gyntaf, fe'i defnyddir yno varnishadm, sy'n rhan o'r pecyn gosod farnais, ar gyfer gosod farnais heb ailgychwyn.

Is-dîm vcl.show -v a ddefnyddir i allbynnu'r ffurfweddiad VCL cyfan a nodir yn ${VCL_NAME}, i STDOUT.

I arddangos y ffurfweddiad VCL gweithredol cyfredol, yn ogystal â sawl fersiwn blaenorol o ffurfweddiadau llwybro farnais sy'n dal yn y cof, gallwch ddefnyddio'r gorchymyn varnishadm vcl.list, y bydd ei allbwn yn debyg i'r un isod:

discarded   cold/busy       1 reload_20190101_120000_11903
discarded   cold/busy       2 reload_20190101_120000_12068
discarded   cold/busy       16 reload_20190101_120000_12259
discarded   cold/busy       16 reload_20190101_120000_12299
discarded   cold/busy       28 reload_20190101_120000_12357
active      auto/warm       32 reload_20190101_120000_12397
available   auto/warm       0 reload_20190101_120000_12587

Gwerth amrywiol ${VCL_NAME} wedi'i osod mewn rhan arall o'r sgript varnishreload i enw'r VCL sy'n weithredol ar hyn o bryd, os oes un. Yn yr achos hwn bydd yn “ail-lwytho_20190101_120000_12397”.

Gwych, amrywiol ${VCL_SHOW} yn cynnwys cyfluniad cyflawn ar gyfer farnais, yn glir am y tro. Nawr rwy'n deall o'r diwedd pam mae'r allbwn dash set -x troi allan i fod mor doredig - roedd yn cynnwys cynnwys y cyfluniad canlyniadol.

Mae'n bwysig deall y gellir cyfuno ffurfweddiad VCL cyflawn yn aml o sawl ffeil. Defnyddir sylwadau arddull C i nodi lle mae rhai ffeiliau cyfluniad wedi'u cynnwys mewn eraill, a dyna hanfod y llinell cod ganlynol.
Mae'r gystrawen ar gyfer sylwadau sy'n disgrifio'r ffeiliau sydd wedi'u cynnwys yn y fformat a ganlyn:

// VCL.SHOW <NUM> <NUM> <FILENAME>

Nid yw'r niferoedd yn bwysig yn y cyd-destun hwn, mae gennym ddiddordeb yn enw'r ffeil.

Beth sy'n digwydd yn y pen draw yn y gors o orchmynion sy'n dechrau ar linell 116?
Gadewch i ni chyfrif i maes.
Mae’r tîm yn cynnwys pedair rhan:

  1. Syml echo, sy'n argraffu gwerth y newidyn ${VCL_SHOW}
    echo "$VCL_SHOW"
  2. awk, sy’n edrych am linell (record) lle mae’r maes cyntaf, ar ôl torri’r testun, yn “//”, a’r ail yn “VCL.SHOW”.
    Bydd Awk yn ysgrifennu'r llinell gyntaf sy'n cyfateb i'r patrymau hyn ac yna'n rhoi'r gorau i brosesu ar unwaith.

    awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}'
  3. Bloc o god sy'n storio gwerthoedd maes yn bum newidyn, wedi'u gwahanu gan fylchau. Mae'r pumed newidyn FFEIL yn derbyn gweddill y llinell. Yn olaf, mae'r adlais olaf yn ysgrifennu cynnwys y newidyn ${FILE}.
    { read -r DELIM VCL_SHOW INDEX SIZE FILE; echo "$FILE" }
  4. Gan fod pob cam 1 i 3 wedi'i amgáu mewn is-blisgyn, gan allbynnu'r gwerth $FILE yn cael ei ysgrifennu i newidyn VCL_FILE.

Fel y mae'r sylw ar linell 119 yn ei awgrymu, dyma'r unig ddiben o drin achosion yn ddibynadwy lle bydd VCL yn cyfeirio at ffeiliau gyda bylchau yn eu henwau.

Rwyf wedi nodi'r rhesymeg brosesu wreiddiol ar gyfer ${VCL_FILE} a cheisiodd newid y dilyniant gorchymyn, ond nid oedd yn arwain at unrhyw beth. Gweithiodd popeth yn iawn i mi, ond pan ddechreuais y gwasanaeth roedd yn rhoi gwall.

Mae'n ymddangos nad yw'r gwall yn atgynhyrchadwy wrth redeg y sgript â llaw, tra bod y 30 munud tybiedig eisoes wedi dod i ben chwe gwaith ac, yn ogystal, mae tasg â blaenoriaeth uwch wedi ymddangos, gan wthio materion eraill o'r neilltu. Roedd gweddill yr wythnos yn llawn amrywiaeth o dasgau a dim ond ychydig yn llai gwanedig oedd adroddiad ar sed a chyfweliad ag ymgeisydd. Problem gyda gwall yn varnishreload a gollwyd yn anadferadwy yn nhywod amser.

Eich hyn a elwir yn sed-fu... mewn gwirionedd... sbwriel

Yr wythnos nesaf fe ges i un diwrnod gweddol rydd, felly penderfynais daclo'r tocyn yma eto. Roeddwn yn gobeithio yn fy ymennydd, bod rhywfaint o broses gefndir wedi bod yn chwilio am ateb i'r broblem hon drwy'r amser hwn, a'r tro hwn byddwn yn bendant yn deall beth oedd yn digwydd.

Gan nad oedd newid y cod yn helpu y tro diwethaf, penderfynais ei ailysgrifennu gan ddechrau o linell 116. Beth bynnag, roedd y cod presennol yn dwp. Ac nid oes angen ei ddefnyddio o gwbl read.

Edrych ar y gwall eto:
sh: echo: broken pipe — mae adlais yn ymddangos mewn dau le yn y gorchymyn hwn, ond yr wyf yn amau ​​​​mai'r cyntaf yw'r troseddwr mwyaf tebygol (neu o leiaf yn gyd-droseddwr). Nid yw awk yn ennyn hyder chwaith. A rhag ofn ei fod mewn gwirionedd awk | {read; echo} mae'r dyluniad yn arwain at yr holl broblemau hyn, beth am ei ddisodli? Nid yw'r gorchymyn un-llinell hwn yn defnyddio holl nodweddion awk, a hyd yn oed yr un ychwanegol hwn read yn ychwanegol.

Ers yr wythnos diwethaf cafwyd adroddiad ar sed, Roeddwn i eisiau rhoi cynnig ar fy sgiliau newydd a symleiddio echo | awk | { read; echo} i mewn i fwy dealladwy echo | sed. Er nad dyma'r ffordd orau o adnabod y byg yn bendant, meddyliais y byddwn o leiaf yn rhoi cynnig ar fy sed-fu ac efallai yn dysgu rhywbeth newydd am y broblem. Ar hyd y ffordd, gofynnais i fy nghydweithiwr, awdur y sgwrs sed, fy helpu i lunio sgript sed fwy effeithlon.

Gollyngais y cynnwys varnishadm vcl.show -v "$VCL_NAME" i ffeil, felly gallwn ganolbwyntio ar ysgrifennu'r sgript sed heb unrhyw drafferth o reboots gwasanaeth.

Disgrifiad byr o sut yn union y gellir dod o hyd i fewnbwn prosesau sed ei lawlyfr GNU. Yn y ffynonellau sed y symbol n a nodir yn benodol fel gwahanydd llinell.

Mewn sawl pas a chydag argymhellion fy nghyd-Aelod, fe wnaethom ysgrifennu sgript sed a roddodd yr un canlyniad â’r llinell wreiddiol gyfan 116.

Isod mae ffeil sampl gyda data mewnbwn:

> cat vcl-example.vcl
Text
// VCL.SHOW 0 1578 file with 3 spaces.vcl
More text
// VCL.SHOW 0 1578 file.vcl
Even more text
// VCL.SHOW 0 1578 file with TWOspaces.vcl
Final text

Efallai nad yw hyn yn amlwg o'r disgrifiad uchod, ond dim ond y sylw cyntaf sydd gennym ni // VCL.SHOW, ac efallai y bydd nifer ohonynt yn y data mewnbwn. Dyma pam mae'r llecyn gwreiddiol yn dod i ben ar ôl y gêm gyntaf.

# шаг первый, вывести только строки с комментариями
# используя возможности sed, определяется символ-разделитель с помощью конструкции '#' вместо обычно используемого '/', за счёт этого не придётся экранировать косые в искомом комментарии
# определяется регулярное выражение “// VCL.SHOW”, для поиска строк с определенным шаблоном
# флаг -n позаботится о том, чтобы sed не выводил все входные данные, как он это делает по умолчанию (см. ссылку выше)
# -E позволяет использовать расширенные регулярные выражения
> cat vcl-processor-1.sed
#// VCL.SHOW#p
> sed -En -f vcl-processor-1.sed vcl-example.vcl
// VCL.SHOW 0 1578 file with 3 spaces.vcl
// VCL.SHOW 0 1578 file.vcl
// VCL.SHOW 0 1578 file with TWOspaces.vcl

# шаг второй, вывести только имя файла
# используя команду “substitute”, с группами внутри регулярных выражений, отображается только нужная группa
# и это делается только для совпадений, ранее описанного поиска
> cat vcl-processor-2.sed
#// VCL.SHOW# {
    s#.* [0-9]+ [0-9]+ (.*)$#1#
    p
}
> sed -En -f vcl-processor-2.sed vcl-example.vcl
file with 3 spaces.vcl
file.vcl
file with TWOspaces.vcl

# шаг третий, получить только первый из результатов
# как и в случае с awk, добавляется немедленное завершения после печати первого найденного совпадения
> cat vcl-processor-3.sed
#// VCL.SHOW# {
    s#.* [0-9]+ [0-9]+ (.*)$#1#
    p
    q
}
> sed -En -f vcl-processor-3.sed vcl-example.vcl
file with 3 spaces.vcl

# шаг четвертый, схлопнуть всё в однострочник, используя двоеточия для разделения команд
> sed -En -e '#// VCL.SHOW#{s#.* [0-9]+ [0-9]+ (.*)$#1#p;q;}' vcl-example.vcl
file with 3 spaces.vcl

Felly, bydd cynnwys y sgript varnishreload yn edrych rhywbeth fel hyn:

VCL_FILE="$(echo "$VCL_SHOW" | sed -En '#// VCL.SHOW#{s#.*[0-9]+ [0-9]+ (.*)$#1#p;q;};')"

Gellir mynegi'r rhesymeg uchod yn fyr fel a ganlyn:
Os yw'r llinyn yn cyfateb i fynegiad rheolaidd // VCL.SHOW, yna yfwch yn farus y testyn sydd yn cynnwys y ddau rif yn y llinell hon, ac arbedwch bob peth sydd yn weddill ar ol y gweithrediad hwn. Allyrru'r gwerth sydd wedi'i storio a gorffen y rhaglen.

Syml, ynte?

Roeddem yn hapus gyda'r sgript sed a'r ffaith ei fod wedi disodli'r holl god gwreiddiol. Rhoddodd fy holl brofion y canlyniadau dymunol, felly newidiais y "varnishreload" ar y gweinydd a'i redeg eto systemctl reload varnish. Camgymeriad drwg echo: write error: Broken pipe chwerthin yn ein hwynebau eto. Roedd y cyrchwr wincio yn aros i orchymyn newydd gael ei nodi yng ngwacter tywyll y derfynell...

Ffynhonnell: hab.com

Ychwanegu sylw