Туулайн нүхнээс унах нь: Нэг лак дахин ачаалсны түүх - 1-р хэсэг

хий үзэгдэлАмьдрал нь үүнээс шалтгаалах юм шиг өмнөх 20 минутын турш товчлуурыг дарж байснаа над руу хагас зэрлэг харцаар харж, зальтай инээвхийлэн "Найз минь, би үүнийг авсан гэж бодож байна."

"Энд хар даа" гэж тэр дэлгэцэн дээрх тэмдэгтүүдийн аль нэг рүү заан, "Хэрэв миний илгээсэн зүйлийг энд нэмбэл улаан малгайтайгаа мөрийцье" гэж кодын өөр хэсэг рүү зааж, "алдаа гарахаа болино. харуулах болно."

Бага зэрэг эргэлзэж, ядарсан тул би хэсэг хугацаанд ажиллаж байсан sed илэрхийлэлийг өөрчилж, файлаа хадгалаад ажиллуулна. systemctl varnish reload. Алдааны мэдэгдэл алга болсон ...

"Нэр дэвшигчтэй солилцсон цахим шуудан" гэж миний хамтран зүтгэгч яриагаа үргэлжлүүлж, инээмсэглэл нь жинхэнэ баяр баясгалантай инээмсэглэл болон хувирч, "Энэ бол яг адилхан асуудал юм шиг санагдлаа!"

Энэ бүхэн хэрхэн эхэлсэн

Энэхүү нийтлэл нь bash, awk, sed болон systemd хэрхэн ажилладаг талаар ойлголттой болно. Лакны талаархи мэдлэгийг илүүд үздэг боловч шаардлагагүй.
Хэсэг дэх цагийн тэмдэглэгээг өөрчилсөн.
-тай хамт бичсэн хий үзэгдэл.
Энэ текст нь хоёр долоо хоногийн өмнө англи хэл дээр хэвлэгдсэн эхийн орчуулга юм; орчуулга бойкоден.

Намрын бас нэгэн дулаахан өглөөний нарны туяа цонхоор тусч, аяга кофеиноор баялаг шинэхэн бэлтгэсэн ундаа гарнаас хол байх, таны дуртай дуу авианы симфони чихэвчэнд эгшиглэж, механик гарны чимээг дарж, анхны оруулга. Канбаны самбар дээрх хоцрогдсон тасалбаруудын жагсаалтад "Varnishreload-ыг судлах" sh: echo: I/O error in staging" гэсэн хувь заяаны гарчигтайгаар гялалзаж байна (Investigate "varnishreload sh: echo: I/O error" in staging). Лакны тухайд гэвэл энэ тохиолдол шиг ямар ч асуудал үүсгэхгүй байсан ч алдаа гаргах зай байхгүй, байж ч болохгүй.

Танихгүй хүмүүст зориулав лак дахин ачаалах, энэ нь тохиргоог дахин ачаалахад ашигладаг энгийн бүрхүүлийн скрипт юм лак - VCL гэж бас нэрлэдэг.

Тасалбарын гарчигаас харахад алдаа нь тайзан дээрх серверүүдийн аль нэгэнд гарсан бөгөөд тайзан дээрх лакны чиглүүлэлт зөв ажиллаж байгаа гэдэгт итгэлтэй байсан тул энэ нь бага зэргийн алдаа байх болно гэж би бодсон. Тэгэхээр, зүгээр л аль хэдийн хаалттай гаралтын урсгалд дууссан мессеж. Би тасалбараа 30 минут хүрэхгүй хугацаанд бэлэн гэж тэмдэглээд, өөр нэг хог хаягдлаас цэвэрлэж, илүү чухал зүйл рүүгээ буцаж ирнэ гэдэгтээ бүрэн итгэлтэй байна.

200 км/цагийн хурдтай хана мөргөж байна

Файлыг нээж байна varnishreload, Debian Stretch ажиллуулж байгаа серверүүдийн нэг дээр би 200 мөрээс бага урттай бүрхүүлийн скриптийг харсан.

Скриптийг уншсаны дараа би үүнийг терминалаас шууд олон удаа ажиллуулахад асуудал үүсгэж болзошгүй зүйлийг анзаарсангүй.

Эцсийн эцэст энэ бол тайз, эвдэрсэн ч хэн ч гомдоллохгүй, за ... хэтэрхий их биш. Би скриптийг ажиллуулж, терминал дээр юу бичихийг харах боловч алдаанууд харагдахаа больсон.

Би ямар ч нэмэлт хүчин чармайлтгүйгээр алдааг дахин гаргаж чадахгүй байгаа эсэхийг шалгахын тулд хэд хэдэн удаа гүйж байгаа бөгөөд би энэ скриптийг хэрхэн өөрчилж, алдаа гаргасаар байх талаар бодож эхэлж байна.

Скрипт нь STDOUT-г дарж чадах уу ( > &-)? Эсвэл STDERR? Эцсийн эцэст эдгээрийн аль нь ч ажилласангүй.

Systemd нь эхлүүлэх орчныг ямар нэгэн байдлаар өөрчилдөг бололтой, гэхдээ яаж, яагаад?
Би vim-г нээж засварлана varnishreload, нэмэх set -x яг shebang дор, скриптийн дибаг хийх гаралт нь гэрэл гэгээ тусгах болно гэж найдаж байна.

Файлыг зассан тул би лакыг дахин ачаалж, өөрчлөлт нь бүх зүйлийг бүрэн эвдсэн болохыг олж харлаа ... Яндан нь бүрэн эмх замбараагүй бөгөөд олон тонн C-тэй төстэй кодууд байдаг. Терминал дээр гүйлгэх нь хаанаас эхэлж байгааг олоход хангалтгүй юм. Би бүрэн андуурч байна. Дибаг хийх горим нь скрипт дээр эхлүүлсэн програмуудын ажиллагаанд нөлөөлж чадах уу? Үгүй ээ, дэмий юм. Бүрхүүлд алдаа байна уу? Хэд хэдэн боломжит хувилбарууд миний толгойд янз бүрийн чиглэлд жоом шиг уралдаж байна. Кофейнтэй ундааны аяга тэр дороо хоосорч, нөөцөө дүүргэхийн тулд гал тогооны өрөөнд хурдан очиж, бид явлаа. Би скриптийг нээж, shebang-ийг сайтар харлаа: #!/bin/sh.

/bin/sh - энэ бол зүгээр л bash-ийн симбол, тиймээс скриптийг POSIX нийцтэй горимд тайлбарладаг, тийм үү? Тийм ч! Debian дээрх анхдагч бүрхүүл нь зураас бөгөөд яг ийм харагдаж байна. хэлдэг /bin/sh.

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

Туршилтын хувьд би shebang-г өөрчилсөн #!/bin/bash, устгасан set -x мөн дахин оролдсон. Эцэст нь, лакыг дараа нь дахин ачаалсны дараа гаралт дээр зөвшөөрөгдөх алдаа гарч ирэв.

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

124-р мөр, энд байна!

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 }

Гэвч 124-р мөр нэлээн хоосон бөгөөд ямар ч сонирхолгүй байна. Алдаа 116-р мөрөнд эхэлсэн олон мөрт мөрний нэг хэсэг болсон гэж би таамаглаж байсан.
Хувьсагчид эцэст нь юу бичих вэ? VCL_FILE дээрх дэд бүрхүүлийг гүйцэтгэсний үр дүнд?

Эхэндээ хувьсагчийн агуулгыг илгээдэг VLC_SHOW, хоолойгоор дамжуулан тушаалын дагуу 115-р мөрөнд үүсгэсэн. Тэгээд тэнд юу болдог вэ?

Нэгдүгээрт, үүнийг тэнд ашигладаг varnishadmлак суурилуулах багцын нэг хэсэг болох лакыг дахин эхлүүлэхгүйгээр тохируулах зориулалттай.

Дэд баг vcl.show -v -д заасан VCL тохиргоог бүхэлд нь гаргахад ашигладаг ${VCL_NAME}, STDOUT руу.

Одоогийн идэвхтэй VCL тохиргоо, мөн санах ойд байгаа лакны чиглүүлэлтийн хэд хэдэн өмнөх хувилбаруудыг харуулахын тулд та тушаалыг ашиглаж болно. varnishadm vcl.list, гаралт нь дараахтай төстэй байх болно.

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

Хувьсах утга ${VCL_NAME} скриптийн өөр хэсэгт суулгасан байна varnishreload Хэрэв байгаа бол одоо идэвхтэй байгаа VCL-ийн нэр. Энэ тохиолдолд "дахин ачаалах_20190101_120000_12397" байх болно.

Гайхалтай, хувьсагч ${VCL_SHOW} лакны бүрэн тохиргоог агуулсан, одоогоор тодорхой байна. Одоо би зураас яагаад гарсныг эцэст нь ойлголоо set -x маш эвдэрсэн болсон - энэ нь үүссэн тохиргооны агуулгыг багтаасан.

VCL-ийн бүрэн тохиргоог хэд хэдэн файлаас нэгтгэж болно гэдгийг ойлгох нь чухал. Зарим тохиргооны файлуудыг бусад файлд хаана оруулсан болохыг тодорхойлохын тулд C хэлбэрийн тайлбарыг ашигладаг бөгөөд дараах кодын хэсэг нь үүнд зориулагдсан болно.
Оруулсан файлуудыг тайлбарласан сэтгэгдлийн синтакс дараах форматтай байна:

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

Энэ нөхцөлд тоо чухал биш, бид файлын нэрийг сонирхож байна.

116-р мөрөнд эхэлсэн тушаалуудын намагт эцэст нь юу тохиолдох вэ?
Үүнийг үзье.
Баг нь дөрвөн хэсгээс бүрдэнэ.

  1. Энгийн echo, хувьсагчийн утгыг хэвлэдэг ${VCL_SHOW}
    echo "$VCL_SHOW"
  2. awk, текстийг эвдсэний дараа эхний талбар нь "//", хоёр дахь нь "VCL.SHOW" байх мөрийг (бичлэг) хайж байна.
    Awk эдгээр загварт тохирсон эхний мөрийг бичээд дараа нь боловсруулахаа шууд зогсооно.

    awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}'
  3. Талбайн утгыг хоосон зайгаар тусгаарласан таван хувьсагч болгон хадгалдаг кодын блок. Тав дахь FILE хувьсагч нь мөрийн үлдсэн хэсгийг хүлээн авдаг. Эцэст нь сүүлчийн цуурай нь хувьсагчийн агуулгыг бичдэг ${FILE}.
    { read -r DELIM VCL_SHOW INDEX SIZE FILE; echo "$FILE" }
  4. 1-ээс 3 хүртэлх бүх алхмууд нь дэд бүрхүүлд багтсан тул утгыг гаргана $FILE хувьсагч руу бичигдэх болно VCL_FILE.

119-р мөрийн тайлбарт дурдсанчлан энэ нь VCL нь нэрэндээ хоосон зайтай файлуудыг лавлах тохиолдолд найдвартай шийдвэрлэх цорын ганц зорилго юм.

Би анхны боловсруулалтын логикийг тайлбарласан ${VCL_FILE} мөн тушаалын дарааллыг өөрчлөхийг оролдсон боловч энэ нь юу ч хүргэсэнгүй. Миний хувьд бүх зүйл сайн байсан, гэхдээ би үйлчилгээг эхлүүлэхэд алдаа гарсан.

Скриптийг гараар ажиллуулах үед алдаа нь дахин давтагдах боломжгүй юм шиг санагдаж байгаа бол 30 минутын хугацаа аль хэдийн зургаан удаа дууссан бөгөөд үүнээс гадна илүү өндөр ач холбогдолтой ажил гарч ирснээр бусад асуудлыг хойш тавьжээ. Долоо хоногийн үлдсэн хэсэг нь янз бүрийн ажлуудаар дүүрэн байсан бөгөөд sed-ийн талаархи тайлан болон нэр дэвшигчтэй хийсэн ярилцлагаас бага зэрэг шингэлсэн. Алдаатай холбоотой асуудал varnishreload цаг хугацааны элсэнд эргэлт буцалтгүй төөрсөн.

Чиний сэд-фу гэгч... үнэндээ... хог юм

Дараагийн долоо хоногт би нэлээд чөлөөтэй нэг өдөртэй байсан тул би энэ тасалбарыг дахин шийдэхээр шийдсэн. Энэ бүх хугацаанд миний тархинд ямар нэгэн суурь процесс энэ асуудлын шийдлийг хайж байсан бөгөөд энэ удаад юу болоод байгааг ойлгох болно гэж найдаж байсан.

Өнгөрсөн удаад кодыг өөрчилсөн ч тус болоогүй тул 116-р мөрөөс эхлэн дахин бичихээр шийдлээ. Ямар ч байсан одоо байгаа код нь тэнэг байсан. Мөн үүнийг ашиглах шаардлагагүй read.

Алдааг дахин харвал:
sh: echo: broken pipe - цуурай нь энэ командын хоёр газарт гарч ирдэг, гэхдээ би эхнийх нь илүү магадлалтай буруутан (эсвэл ядаж хамсаатан) гэж сэжиглэж байна. Awk ч гэсэн өөртөө итгэх итгэлийг төрүүлдэггүй. Тэгээд үнэхээр байгаа тохиолдолд awk | {read; echo} загвар нь эдгээр бүх асуудалд хүргэдэг, яагаад үүнийг сольж болохгүй гэж? Энэ нэг мөрт тушаал нь awk-ийн бүх функцийг ашигладаггүй, тэр ч байтугай энэ нэмэлтийг ч ашигладаггүй read нэмж хэлэхэд.

Өнгөрсөн долоо хоногоос хойш тайлан гарсан sed, Би шинээр олж авсан ур чадвараа туршиж, хялбаршуулахыг хүссэн echo | awk | { read; echo} илүү ойлгомжтой болгох echo | sed. Хэдийгээр энэ нь алдааг тодорхойлох хамгийн сайн арга биш ч би ядаж сед-фуг туршиж үзээд асуудлын талаар шинэ зүйл суръя гэж бодсон. Замдаа би sed ярианы зохиогч хамтран ажилладаг хүнээсээ илүү үр дүнтэй sed скрипт гаргахад туслахыг хүссэн.

Би агуулгыг нь хаясан varnishadm vcl.show -v "$VCL_NAME" файл руу оруулснаар би үйлчилгээг дахин ачаалахад төвөг учруулахгүйгээр sed скрипт бичихэд анхаарлаа төвлөрүүлж чадна.

Sed нь оролтыг хэрхэн боловсруулдаг тухай товч тайлбарыг эндээс олж болно түүний GNU гарын авлага. Сэд эх сурвалжид тэмдэг n шугам тусгаарлагч гэж тодорхой заасан.

Хэд хэдэн дамжуулалтаар, миний хамтрагчийн зөвлөмжийн дагуу бид sed скрипт бичсэн бөгөөд энэ нь бүхэл бүтэн 116-р мөртэй ижил үр дүнг өгсөн.

Оруулсан өгөгдөл бүхий жишээ файлыг доор харуулав.

> 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

Дээрх тайлбараас харахад энэ нь тодорхойгүй байж болох ч бид зөвхөн эхний тайлбарыг сонирхож байна // VCL.SHOW, мөн оролтын өгөгдөлд тэдгээрийн хэд хэдэн байж болно. Тиймээс анхны awk эхний тоглолтын дараа дуусдаг.

# шаг первый, вывести только строки с комментариями
# используя возможности 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

Тиймээс, varnishreload скриптийн агуулга нь иймэрхүү харагдах болно.

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

Дээрх логикийг дараах байдлаар товч илэрхийлж болно.
Хэрэв мөр нь ердийн илэрхийлэлтэй таарч байвал // VCL.SHOW, дараа нь энэ мөрөнд хоёр тоог агуулсан текстийг шуналтайгаар залгиж, энэ үйлдлийн дараа үлдсэн бүх зүйлийг хадгал. Хадгалагдсан утгыг гаргаж, програмыг дуусгана.

Энгийн, тийм үү?

Бид sed скрипт болон бүх анхны кодыг орлуулсанд сэтгэл хангалуун байсан. Миний бүх туршилтууд хүссэн үр дүнгээ өгсөн тул би сервер дээрх "лак дахин ачаалах" -ыг сольж, дахин ажиллуулсан. systemctl reload varnish. Муу алдаа echo: write error: Broken pipe бидний нүүрэнд дахин инээв. Нүд ирмэх курсор терминалын харанхуй хоосон газарт шинэ тушаал оруулахыг хүлээж байв...

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх