Прича о недостајућим ДНС пакетима из техничке подршке Гоогле Цлоуд-а

Из Гоогле уређивача блогова: Да ли сте се икада запитали како инжењери Гоогле Цлоуд Тецхницал Солутионс (ТСЕ) обрађују ваше захтеве за подршку? ТСЕ инжењери техничке подршке су одговорни за идентификацију и исправљање извора проблема које су пријавили корисници. Неки од ових проблема су прилично једноставни, али понекад наиђете на карту која захтева пажњу неколико инжењера одједном. У овом чланку, један од запослених у ТСЕ-у ће нам испричати један веома тежак проблем из своје недавне праксе - случај да недостају ДНС пакети. У овој причи видећемо како су инжењери успели да реше ситуацију и шта су ново научили док су отклањали грешку. Надамо се да вас ова прича не само образује о дубоко укорењеној грешци, већ вам даје и увид у процесе који се односе на подношење захтева за подршку у Гоогле Цлоуд-у.

Прича о недостајућим ДНС пакетима из техничке подршке Гоогле Цлоуд-а

Решавање проблема је и наука и уметност. Све почиње изградњом хипотезе о разлогу нестандардног понашања система, након чега се тестира на снагу. Међутим, пре него што формулишемо хипотезу, морамо јасно дефинисати и прецизно формулисати проблем. Ако питање звучи превише нејасно, онда ћете морати све пажљиво анализирати; Ово је „уметност“ решавања проблема.

Под Гоогле Цлоуд-ом, такви процеси постају експоненцијално сложенији, јер Гоогле Цлоуд покушава да гарантује приватност својих корисника. Због тога, ТСЕ инжењери немају приступ да уређују ваше системе, нити могућност да виде конфигурације тако широко као корисници. Стога, да бисмо тестирали било коју од наших хипотеза, ми (инжењери) не можемо брзо модификовати систем.

Неки корисници верују да ћемо све поправити као механику у аутосервису, и једноставно нам послати ид виртуелне машине, док се у стварности процес одвија у конверзацијском формату: прикупљање информација, формирање и потврђивање (или побијање) хипотеза, и, на крају, проблеми одлучивања се заснивају на комуникацији са клијентом.

Проблем у питању

Данас имамо причу са добрим завршетком. Један од разлога за успешно решавање предложеног случаја је веома детаљан и тачан опис проблема. Испод можете видети копију прве карте (измењене да би се сакриле поверљиве информације):
Прича о недостајућим ДНС пакетима из техничке подршке Гоогле Цлоуд-а
Ова порука садржи много корисних информација за нас:

  • Специфичан ВМ је специфициран
  • Сам проблем је назначен - ДНС не ради
  • Назначено је где се проблем манифестује - ВМ и контејнер
  • Назначени су кораци које је корисник предузео да би идентификовао проблем.

Захтев је регистрован као „П1: Критичан утицај - услуга неупотребљива у производњи“, што подразумева стално праћење ситуације 24/7 по шеми „Прати сунце“ (више о приоритети корисничких захтева), са његовим трансфером из једног тима техничке подршке у други са сваким померањем временске зоне. У ствари, када је проблем стигао до нашег тима у Цириху, већ је обишао свет. До тог тренутка, корисник је предузео мере за ублажавање, али се плашио да се ситуација у производњи понови, јер основни узрок још није откривен.

Док је карта стигла у Цирих, већ смо имали следеће информације при руци:

  • Садржај /etc/hosts
  • Садржај /etc/resolv.conf
  • Излаз iptables-save
  • Саставио тим ngrep пцап фајл

Са овим подацима, били смо спремни да започнемо фазу „истраге“ и решавања проблема.

Наши први кораци

Пре свега, проверили смо евиденцију и статус сервера метаподатака и уверили се да ради исправно. Сервер метаподатака одговара на ИП адресу 169.254.169.254 и, између осталог, одговоран је за контролу имена домена. Такође смо двапут проверили да ли заштитни зид исправно ради са ВМ-ом и да не блокира пакете.

Био је то нека врста чудног проблема: нмап провера је оповргла нашу главну хипотезу о губитку УДП пакета, па смо ментално смислили још неколико опција и начина да их проверимо:

  • Да ли се пакети испуштају селективно? => Проверите иптаблес правила
  • Није ли премало? МТУ? => Проверите излаз ip a show
  • Да ли проблем утиче само на УДП пакете или ТЦП? => Одвезите се dig +tcp
  • Да ли се враћају диг генерисани пакети? => Одвезите се tcpdump
  • Да ли либднс ради исправно? => Одвезите се strace да провери пренос пакета у оба смера

Овде одлучујемо да позовемо корисника да директно реши проблеме.

Током позива у могућности смо да проверимо неколико ствари:

  • После неколико провера искључујемо иптаблес правила са листе разлога
  • Проверавамо мрежне интерфејсе и табеле рутирања и још једном проверавамо да ли је МТУ тачан
  • То откривамо dig +tcp google.com (ТЦП) ради како треба, али dig google.com (УДП) не ради
  • Одвезавши се tcpdump док ради dig, налазимо да се враћају УДП пакети
  • Одвеземо се strace dig google.com и видимо како диг исправно зове sendmsg() и recvms(), међутим, други је прекинут тимеоутом

Нажалост, долази крај смене и приморани смо да проблем ескалирамо на следећу временску зону. Захтев је, међутим, изазвао интересовање у нашем тиму, па колега предлаже креирање почетног ДНС пакета помоћу скрапи Питхон модула.

from scapy.all import *

answer = sr1(IP(dst="169.254.169.254")/UDP(dport=53)/DNS(rd=1,qd=DNSQR(qname="google.com")),verbose=0)
print ("169.254.169.254", answer[DNS].summary())

Овај фрагмент креира ДНС пакет и шаље захтев серверу метаподатака.

Корисник покреће код, враћа се ДНС одговор, а апликација га прима, потврђујући да нема проблема на нивоу мреже.

После још једног „путовања око света“, захтев се враћа нашем тиму, а ја га потпуно преносим на себе, мислећи да ће кориснику бити згодније ако захтев престане да кружи од места до места.

У међувремену, корисник љубазно пристаје да пружи снимак слике система. Ово је веома добра вест: могућност да сам тестирам систем чини решавање проблема много бржим, јер више не морам да тражим од корисника да покреће команде, шаље ми резултате и анализира их, све могу сам!

Колеге почињу помало да ми завиде. За ручком разговарамо о конверзији, али нико нема појма шта се дешава. На срећу, сам корисник је већ предузео мере за ублажавање последица и не жури, тако да имамо времена да сецирамо проблем. А пошто имамо слику, можемо да покренемо било које тестове који нас занимају. Велики!

Враћајући се корак уназад

Једно од најпопуларнијих питања за интервју за позиције системског инжењера је: „Шта се дешава када пингујете ввв.гоогле.цом? Питање је одлично, пошто кандидат треба да опише све од љуске до корисничког простора, до системског кернела и затим до мреже. Смејем се: понекад се питања за интервју испостави да су корисна у стварном животу...

Одлучујем да ово питање људских ресурса применим на тренутни проблем. Грубо говорећи, када покушате да одредите ДНС име, дешава се следеће:

  1. Апликација позива системску библиотеку као што је либднс
  2. либднс проверава конфигурацију система са којим ДНС сервером треба да контактира (на дијаграму је ово 169.254.169.254, сервер метаподатака)
  3. либднс користи системске позиве за креирање УДП утичнице (СОКЕТ_ДГРАМ) и слање УДП пакета са ДНС упитом у оба смера
  4. Преко сисцтл интерфејса можете да конфигуришете УДП стек на нивоу кернела
  5. Кернел је у интеракцији са хардвером за пренос пакета преко мреже преко мрежног интерфејса
  6. Хипервизор хвата и преноси пакет на сервер метаподатака након контакта са њим
  7. Сервер метаподатака, својом магијом, одређује ДНС име и враћа одговор користећи исти метод

Прича о недостајућим ДНС пакетима из техничке подршке Гоогле Цлоуд-а
Дозволите ми да вас подсетим које смо хипотезе већ разматрали:

Хипотеза: Покварене библиотеке

  • Тест 1: покрените страце у систему, проверите да ли диг позива исправне системске позиве
  • Резултат: Позивају се исправни системски позиви
  • Тест 2: користећи срапи да проверимо да ли можемо да одредимо имена заобилазећи системске библиотеке
  • Резултат: можемо
  • Тест 3: покрените рпм –В на либднс пакету и датотекама библиотеке мд5сум
  • Резултат: код библиотеке је потпуно идентичан коду у оперативном систему који ради
  • Тест 4: монтирајте слику роот система корисника на ВМ без овог понашања, покрените цхроот, погледајте да ли ДНС ради
  • Резултат: ДНС ради исправно

Закључак на основу тестова: проблем није у библиотекама

Хипотеза: Постоји грешка у подешавањима ДНС-а

  • Тест 1: проверите тцпдумп и видите да ли се ДНС пакети шаљу и враћају исправно након покретања диг
  • Резултат: пакети се преносе исправно
  • Тест 2: дупла провера на серверу /etc/nsswitch.conf и /etc/resolv.conf
  • Резултат: све је тачно

Закључак на основу тестова: проблем није у ДНС конфигурацији

Хипотеза: оштећено језгро

  • Тест: инсталирајте ново језгро, проверите потпис, рестартујте
  • Резултат: слично понашање

Закључак на основу тестова: језгро није оштећено

Хипотеза: нетачно понашање корисничке мреже (или мрежног интерфејса хипервизора)

  • Тест 1: Проверите подешавања заштитног зида
  • Резултат: заштитни зид прослеђује ДНС пакете и на хост и на ГЦП
  • Тест 2: пресретање саобраћаја и праћење исправности преноса и враћања ДНС захтева
  • Резултат: тцпдумп потврђује да је хост примио повратне пакете

Закључак на основу тестова: проблем није у мрежи

Хипотеза: сервер метаподатака не ради

  • Тест 1: проверите евиденцију сервера метаподатака да ли постоје аномалије
  • Резултат: нема аномалија у евиденцији
  • Тест 2: Заобиђите сервер метаподатака преко dig @8.8.8.8
  • Резултат: Резолуција је нарушена чак и без коришћења сервера метаподатака

Закључак на основу тестова: проблем није у серверу метаподатака

Доња линија: тестирали смо све подсистеме осим рунтиме сеттингс!

Заронити у поставке времена рада кернела

Да бисте конфигурисали окружење за извршавање кернела, можете користити опције командне линије (груб) или сисцтл интерфејс. Погледао сам унутра /etc/sysctl.conf и само помислите, открио сам неколико прилагођених подешавања. Осећајући се као да сам се ухватио за нешто, одбацио сам сва подешавања која нису мрежа или ТЦП, остајући при подешавањима планине net.core. Затим сам отишао до места где су дозволе хоста биле у ВМ-у и почео да примењујем подешавања једно по једно, једно за другим, са поквареним ВМ-ом, док нисам пронашао кривца:

net.core.rmem_default = 2147483647

Ево га, конфигурација за разбијање ДНС-а! Нашао сам оружје убиства. Али зашто се ово дешава? Још ми је био потребан мотив.

Основна величина бафера ДНС пакета се конфигурише преко net.core.rmem_default. Типична вредност је негде око 200КиБ, али ако ваш сервер прима много ДНС пакета, можда ћете желети да повећате величину бафера. Ако је бафер пун када стигне нови пакет, на пример зато што га апликација не обрађује довољно брзо, тада ћете почети да губите пакете. Наш клијент је исправно повећао величину бафера јер се плашио губитка података, пошто је користио апликацију за прикупљање метрике преко ДНС пакета. Вредност коју је поставио била је максимална могућа: 231-1 (ако је постављено на 231, кернел ће вратити „ИНВАЛИД АРГУМЕНТ”).

Одједном сам схватио зашто нмап и сцапи раде исправно: користили су необрађене утичнице! Сирови сокети се разликују од обичних утичница: заобилазе иптаблес и нису баферовани!

Али зашто „бафер превелики“ изазива проблеме? Очигледно не функционише како је замишљено.

У овом тренутку могао бих да репродукујем проблем на више језгара и више дистрибуција. Проблем се већ појавио на кернелу 3.к, а сада се појавио и на кернелу 5.к.

Заиста, након покретања

sysctl -w net.core.rmem_default=$((2**31-1))

ДНС је престао да ради.

Почео сам да тражим радне вредности кроз једноставан алгоритам бинарне претраге и открио сам да систем ради са 2147481343, али овај број је за мене био бесмислен скуп бројева. Предложио сам клијенту да проба овај број, а он је одговорио да систем ради са гоогле.цом, али је ипак дао грешку са другим доменима, па сам наставио истрагу.

Ја сам инсталирао дропватцх, алатка која је требало да се користи раније: показује где тачно у кернелу завршава пакет. Кривац је била функција udp_queue_rcv_skb. Преузео сам изворе кернела и додао неколико функције printk да прати где тачно пакет завршава. Брзо сам пронашао право стање if, и једноставно зурио у њега неко време, јер се тада коначно све спојило у једну целину: 231-1, бесмислен број, нерадни домен... Био је то део кода у __udp_enqueue_schedule_skb:

if (rmem > (size + sk->sk_rcvbuf))
		goto uncharge_drop;

Имајте на уму:

  • rmem је типа инт
  • size је типа у16 (непотписан шеснаестобитни инт) и чува величину пакета
  • sk->sk_rcybuf је типа инт и чува величину бафера која је, по дефиницији, једнака вредности у net.core.rmem_default

Када sk_rcvbuf приближава се 231, сабирање величине пакета може резултирати преливање целог броја. А пошто је инт, његова вредност постаје негативна, тако да услов постаје тачан када би требало да буде лажан (више о томе можете прочитати на веза).

Грешка се може исправити на тривијалан начин: ливењем unsigned int. Применио сам исправку и поново покренуо систем и ДНС је поново радио.

Укус победе

Проследио сам своје налазе клијенту и послао ЛКМЛ кернел патцх. Задовољан сам: сваки део слагалице се уклапа, могу тачно да објасним зашто смо приметили оно што смо приметили, и што је најважније, успели смо да пронађемо решење проблема захваљујући нашем тимском раду!

Вреди признати да се случај показао ретким, а на срећу ретко добијамо тако сложене захтеве корисника.

Прича о недостајућим ДНС пакетима из техничке подршке Гоогле Цлоуд-а


Извор: ввв.хабр.цом

Додај коментар