De vegades més és menys. Quan es redueix la càrrega, augmenta la latència

Com a la majoria de publicacions, hi ha un problema amb un servei distribuït, anomenem aquest servei Alvin. Aquesta vegada no vaig descobrir el problema jo mateix, em van informar els nois de la part del client.

Un dia em vaig despertar amb un correu electrònic descontent a causa dels llargs retards amb Alvin, que teníem previst llançar en un futur proper. Concretament, el client va experimentar una latència del percentil 99 en la regió de 50 ms, molt per sobre del nostre pressupost de latència. Això va ser sorprenent, ja que vaig provar el servei àmpliament, especialment en la latència, que és una queixa habitual.

Abans de posar l'Alvin en proves, vaig fer molts experiments amb 40 consultes per segon (QPS), tots mostrant una latència de menys de 10 ms. Estava disposat a declarar que no estava d'acord amb els seus resultats. Però fent una altra ullada a la carta, em vaig adonar d'alguna cosa nova: no havia provat exactament les condicions que van esmentar, el seu QPS era molt inferior al meu. Vaig provar a 40k QPS, però només a 1k. Vaig fer un altre experiment, aquesta vegada amb un QPS més baix, només per apaivagar-los.

Com que estic blogueant sobre això, probablement ja heu descobert que els seus números eren correctes. Vaig provar el meu client virtual una i altra vegada, amb el mateix resultat: un nombre baix de peticions no només augmenta la latència, sinó que augmenta el nombre de peticions amb una latència de més de 10 ms. En altres paraules, si a 40k QPS unes 50 sol·licituds per segon superaven els 50 ms, aleshores a 1k QPS hi havia 100 peticions per sobre de 50 ms cada segon. Paradoxa!

De vegades més és menys. Quan es redueix la càrrega, augmenta la latència

Reduint la cerca

Quan s'enfronta a un problema de latència en un sistema distribuït amb molts components, el primer pas és crear una llista curta de sospitosos. Aprofundim una mica més en l'arquitectura d'Alvin:

De vegades més és menys. Quan es redueix la càrrega, augmenta la latència

Un bon punt de partida és una llista de transicions d'E/S completades (trucades de xarxa/cerques de disc, etc.). Intentem esbrinar on és el retard. A més de l'evident E/S amb el client, l'Alvin fa un pas addicional: accedeix al magatzem de dades. No obstant això, aquest emmagatzematge funciona al mateix clúster que Alvin, de manera que la latència hauria de ser inferior a la del client. Així doncs, la llista de sospitosos:

  1. Trucada de xarxa del client a Alvin.
  2. Trucada de xarxa d'Alvin al magatzem de dades.
  3. Cerca al disc al magatzem de dades.
  4. Trucada de xarxa des del magatzem de dades a l'Alvin.
  5. Trucada de xarxa d'Alvin a un client.

Intentem esborrar alguns punts.

L'emmagatzematge de dades no hi té res a veure

El primer que vaig fer va ser convertir l'Alvin en un servidor de ping-ping que no processa sol·licituds. Quan rep una sol·licitud, retorna una resposta buida. Si la latència disminueix, un error a la implementació d'Alvin o del magatzem de dades no és gens inaudit. En el primer experiment obtenim el següent gràfic:

De vegades més és menys. Quan es redueix la càrrega, augmenta la latència

Com podeu veure, no hi ha cap millora en utilitzar el servidor ping-ping. Això vol dir que el magatzem de dades no augmenta la latència i la llista de sospitosos es redueix a la meitat:

  1. Trucada de xarxa del client a Alvin.
  2. Trucada de xarxa d'Alvin a un client.

Genial! La llista s'està reduint ràpidament. Vaig pensar que gairebé havia descobert el motiu.

gRPC

Ara és el moment de presentar-vos un nou jugador: gRPC. Aquesta és una biblioteca de codi obert de Google per a la comunicació en procés RPC. encara que gRPC ben optimitzat i àmpliament utilitzat, aquesta era la primera vegada que l'utilitzava en un sistema d'aquesta mida i esperava que la meva implementació fos subòptima, com a mínim.

disponibilitat gRPC a la pila va donar lloc a una nova pregunta: potser és la meva implementació o jo mateix gRPC causant problemes de latència? Afegeix un nou sospitós a la llista:

  1. El client truca a la biblioteca gRPC
  2. Biblioteca gRPC fa una trucada de xarxa a la biblioteca del client gRPC al servidor
  3. Biblioteca gRPC contacte amb Alvin (sense operació en cas de servidor de ping-pong)

Per fer-vos una idea de com és el codi, la meva implementació client/Alvin no és gaire diferent de la de client-servidor exemples asincrònics.

Nota: La llista anterior està una mica simplificada perquè gRPC fa possible utilitzar el vostre propi model de fils (plantilla?), en el qual la pila d'execució està entrellaçada gRPC i implementació dels usuaris. Per simplificar, ens cenyim a aquest model.

El perfil ho solucionarà tot

Després d'haver ratllat els magatzems de dades, vaig pensar que gairebé havia acabat: "Ara és fàcil! Apliquem el perfil i esbrineu on es produeix el retard". jo gran fan del perfil de precisió, perquè les CPU són molt ràpides i sovint no són el coll d'ampolla. La majoria dels retards es produeixen quan el processador ha d'aturar el processament per fer alguna cosa més. El perfil precís de la CPU fa exactament això: ho registra tot amb precisió canvis de context i deixa clar on es produeixen retards.

Vaig agafar quatre perfils: amb QPS alt (baixa latència) i amb un servidor de ping-pong amb QPS baix (alta latència), tant al costat del client com al costat del servidor. I per si de cas, també vaig agafar un perfil de processador de mostra. En comparar perfils, acostumo a buscar una pila de trucades anòmala. Per exemple, al costat dolent amb una alta latència hi ha molts més canvis de context (10 vegades o més). Però en el meu cas, el nombre de canvis de context era gairebé el mateix. Per al meu horror, no hi havia res significatiu allà.

Depuració addicional

Estava desesperat. No sabia quines altres eines podia utilitzar, i el meu següent pla era essencialment repetir els experiments amb diferents variacions en lloc de diagnosticar clarament el problema.

Què passa si

Des del principi, em preocupava la latència específica de 50 ms. Aquest és un moment molt gran. Vaig decidir que retallaria trossos del codi fins que pogués esbrinar exactament quina part estava causant aquest error. Després va venir un experiment que va funcionar.

Com és habitual, en retrospectiva sembla que tot era evident. Vaig col·locar el client a la mateixa màquina que l'Alvin i vaig enviar una sol·licitud a localhost. I l'augment de la latència ha desaparegut!

De vegades més és menys. Quan es redueix la càrrega, augmenta la latència

Alguna cosa no funcionava amb la xarxa.

Aprendre habilitats d'enginyer de xarxes

He de reconèixer: el meu coneixement de les tecnologies de xarxa és terrible, sobretot tenint en compte que treballo amb elles cada dia. Però la xarxa era el principal sospitós i necessitava aprendre a depurar-la.

Afortunadament, Internet estima els que volen aprendre. La combinació de ping i tracert semblava un bon començament per depurar problemes de transport de xarxa.

En primer lloc, vaig llançar PsPing al port TCP d'Alvin. Vaig utilitzar la configuració predeterminada, res especial. De més de mil pings, cap va superar els 10 ms, a excepció del primer d'escalfament. Això és contrari a l'augment observat de la latència de 50 ms al percentil 99: allà, per cada 100 peticions, hauríem d'haver vist aproximadament una sol·licitud amb una latència de 50 ms.

Després ho vaig intentar traç: Pot haver-hi un problema en un dels nodes de la ruta entre l'Alvin i el client. Però el traçador també va tornar amb les mans buides.

Per tant, no era el meu codi, la implementació de gRPC o la xarxa que estava causant el retard. Començava a preocupar-me que no ho entendria mai.

Ara en quin sistema operatiu estem

gRPC molt utilitzat a Linux, però exòtic a Windows. Vaig decidir provar un experiment que va funcionar: vaig crear una màquina virtual Linux, vaig compilar Alvin per a Linux i la vaig desplegar.

De vegades més és menys. Quan es redueix la càrrega, augmenta la latència

I això és el que va passar: el servidor de ping-pong de Linux no va tenir els mateixos retards que un amfitrió similar de Windows, tot i que la font de dades no va ser diferent. Resulta que el problema està en la implementació de gRPC per a Windows.

algorisme de Nagle

Durant tot aquest temps vaig pensar que em faltava una bandera gRPC. Ara entenc què és realment gRPC Falta la bandera de Windows. Vaig trobar una biblioteca RPC interna que estava segur que funcionaria bé per a tots els indicadors establerts Winsock. Llavors vaig afegir totes aquestes banderes a gRPC i vaig desplegar Alvin a Windows, en un servidor de ping-pong de Windows pegat!

De vegades més és menys. Quan es redueix la càrrega, augmenta la latència

Gairebé Fet: vaig començar a eliminar els indicadors afegits un a un fins que va tornar la regressió per poder identificar-ne la causa. Va ser infame TCP_NODELAY, interruptor d'algoritme de Nagle.

algorisme de Nagle intenta reduir el nombre de paquets enviats per una xarxa retardant la transmissió de missatges fins que la mida del paquet superi un nombre determinat de bytes. Tot i que això pot ser agradable per a l'usuari mitjà, és destructiu per als servidors en temps real, ja que el sistema operatiu retardarà alguns missatges, provocant retards en QPS baix. U gRPC aquesta marca es va establir a la implementació de Linux per a sockets TCP, però no a Windows. Sóc això corregit.

Conclusió

La latència més alta a QPS baix va ser causada per l'optimització del sistema operatiu. En retrospectiva, l'elaboració de perfils no va detectar la latència perquè es va fer en mode de nucli en lloc de fer-ho en mode d'usuari. No sé si l'algoritme de Nagle es pot observar mitjançant captures ETW, però seria interessant.

Pel que fa a l'experiment localhost, probablement no va tocar el codi de xarxa real i l'algoritme de Nagle no es va executar, de manera que els problemes de latència van desaparèixer quan el client va arribar a Alvin a través de localhost.

La propera vegada que vegeu un augment de la latència a mesura que disminueix el nombre de sol·licituds per segon, l'algoritme de Nagle hauria d'estar a la vostra llista de sospitosos.

Font: www.habr.com

Afegeix comentari