Überprüfung des Portals der regionalen öffentlichen Dienste unter Last durch Puppenspieler

Hallo Habr! Auch Sie beobachten neugierig das "Epos des amerikanischen Wilden Westens über die Verteilung von Grundstücken - gehen Sie zuerst und kleben Sie eine Flagge zum Abstecken" oder nehmen Sie vielleicht sogar daran teil. Genauer gesagt in seiner modernen Version - seien Sie der Erste, der öffentliche Dienste beantragt, um Geld für Kinder zu erhalten, oder erhalten Sie einen Pass, um das Haus zu verlassen. In Anbetracht dessen möchte ich die Erfahrungen unseres Teams beim Testen und bei der Vorbereitung eines regionalen Serviceportals für die Bereitstellung des Dienstes „First Class Record“ teilen . Es ist auch dem Habra-Effekt sehr ähnlich und war, glaube ich, dem nahe, was vor ein paar Tagen mit dem Bundesportal gosuslugi.ru passiert ist, aber auf regionaler Ebene.

Wir haben diese Herausforderung im Januar dieses Jahres in Chabarowsk bestanden und kürzlich an der Vorbereitung eines ähnlichen Dienstes für die Erteilung von Jagdgenehmigungen in einer anderen Region teilgenommen. Im Folgenden finden Sie eine kleine Erfahrung, die Ihnen die Möglichkeit gibt, das Thema der Vorbereitung der Arbeit regionaler Portale für öffentliche Dienste auf Spitzenzeiten aus einer anderen Perspektive zu betrachten.

Und für den Anfang - ein Foto eines schwarzen Busses, der drei Tage lang rund um die Uhr in der Schule Dienst hatte, auf dem der Autor dieser Zeilen vor drei Jahren seine Wendung unter den Eltern bestätigte. Zumindest sind unsere Eltern zusammengekommen. Im Winter in Chabarowsk bei -30 Grad zuzusehen, ist immer noch ein Vergnügen.

Bild

Bei der Vorbereitung auf die Spitzenaufnahme in der ersten Klasse arbeiteten mehrere Teams, weil Auf die eine oder andere Weise ist es daran beteiligt: ​​der Rechenzentrumsbetreiber, der Betreiber und der Entwickler des regionalen Portalinformationssystems, der Betreiber und der Entwickler des integrierten Bildungsinformationssystems, technische Unterstützung für die Benutzer des regionalen Portals. Wir bei iondv führen die letzte Aufgabe aus, indem wir den Zustand des Portals unabhängig überwachen und Benutzer unterstützen.

Unsere Rolle bei der Vorbereitung besteht darin, Tests und Empfehlungen zum Zwischenspeichern von Konfigurationen in Nginx zu organisieren. Außerdem haben wir Anweisungen für Benutzer mit dem empfohlenen „Verhalten“ vorbereitet.

Für diejenigen, die das Problem des Schreibens in der 1. Klasse nicht kennen
, . . , , - ( , — ), , - , , . , , , – , . .

1- , . 0:00 , 10:00 26 . , – . 10:00 , — , - .

. . 2017 . . , , . .

Ein Service für eine nachgefragte Ressource als technische Aufgabe


Das Problem bei Diensten wie „Schreiben in die 1. Klasse“ im Integralindikator für die Last (oder Wahrscheinlichkeit von Abfragen), die zur „Delta-Funktion“ (δ-Funktion, Dirac-Funktion) tendiert, ist in den Diagrammen in Form von Peaks deutlich sichtbar. In diesem Moment gibt es in kurzer Zeit eine mehrfache Zunahme von Anrufen.

δ-Funktions- und Peak-Abfragestatistik

Unsere Erfahrung zeigt, dass die Hauptaufgabe des Trainings nicht darin besteht, die Ressourcen zu erhöhen. Die Aufgabe besteht darin, die potenzielle Anzahl von Anforderungen pro Sekunde zu minimieren, sie für einige Zeit zu verlängern und das System auf die verbleibende Last vorzubereiten. In diesem Fall müssen Engpässe gefunden und beschleunigt werden - dies ergibt den größten Effekt gemäß den Prinzipien der Theorie der begrenzten Systeme (Goldratt-Prinzipien). Und sonst ist es der Engpass, der scheitern wird. Das ganze System sollte von ihm funktionieren: das Prinzip des "Trommel-Puffer-Seils".

Es ist physikalisch unmöglich, das gesamte Volumen in 10 Minuten Sanduhr in 1 Minute zu verschütten - es ist offensichtlich, dass sie zusammenbrechen werden. Ähnliches gilt für die Erbringung von Dienstleistungen. Es überrascht niemanden - wenn MFC und Skandale an der Reihe sind, Dienste zu erhalten, aber es überrascht alle -, warum das Portal zusammengebrochen ist.

Es gibt verschiedene Muster des Lasthandhabungsverhaltens gegenüber der Warteschlangentheorie :

  • Sie können Benutzer in die Warteschleife stellen, d. H. Erhöhen Sie die Warteschlange.
  • Sie können sich einfach weigern, diejenigen zu bedienen, die später gekommen sind, bis die vorherigen verarbeitet wurden.
  • Sie können versuchen, die Produktivität endlos zu steigern.

Zweckmäßigkeit liegt irgendwo dazwischen. In der Tat ist für einen Dienst mit einer begrenzten Ressource, die von einer Region oder einem Staat bereitgestellt wird, nicht nur die Geschwindigkeit wichtig, sondern vor allem die Wahrung der sozialen Gerechtigkeit - d. H. gleiche Bedingungen für alle. Gleichzeitig - wenn der Benutzer nicht das erhalten hat, was er benötigt, initiiert er eine neue Anfrage. In diesem Fall wachsen die Anforderungen in einer Lawine und bilden ein Angriffsmodell für den „ Dog-Pile-Effekt (Dog-Pile-Effekt, Cache-Stampede, Hit-Miss-Storm). Der Benutzer hat die Anforderung bereits abgebrochen und eine neue initiiert, während sich die vorherige noch in der zu verarbeitenden Warteschlange befindet.

Dieser Prozess verstärkt die Tatsache, dass ganze Familien an der Einreichung teilnehmen - Vater und Mutter füllen gleichzeitig Anträge aus und reichen Anträge häufig mehrmals aus Gründen der Zuverlässigkeit ein. Und außerdem oft auch in mehreren Registerkarten und mehreren Browsern. Daher ist es normalerweise sinnvoll, die erwartete Spitzenlast mit dem 2-3-fachen der Anzahl derjenigen zu multiplizieren, die sich tatsächlich für solche Dienste bewerben.

Rückzug der Gerechtigkeit
, «», . ? «» , . . — , . « ». . .

Organisation der Leistungserbringung


Wir haben die erwartete Anzahl der Bewerber anhand einer Kombination aus Daten zur Gesamtzahl der im letzten Jahr eingereichten Bewerbungen und Daten pro Minute für andere Regionen berechnet. In der Regel liegt der Spitzenwert der Anwendungen bei 5 bis 10 Minuten, auch weil die Portale in den ersten drei bis fünf Minuten fast nicht reagieren und spätere Benutzer das Formular 1 bis 5 Minuten ausfüllen (wundern Sie sich nicht, viele füllen das Telefon auch unter solchen „nervösen“ Bedingungen aus). .

Ein ungefähres Berechnungsmodell für die bedingten 1000 Anwendungen pro Stunde lautet wie folgt:

  • Spitzenzeit von 5 bis 10 Minuten ab dem Start und 80% der Anträge werden nach der Paretto-Regel eingereicht
  • Herkömmlicherweise planen wir 160 Anwendungen pro Minute oder 3 Anwendungen pro Sekunde.

Tatsächlich erfolgte die erste Einreichung nach einer Minute und 45 Sekunden, und die Spitze der Bewerbungen ging von 4 Minuten.

Um die Belastung von ESIA und des Systems durch das Generieren von Autorisierungssitzungen zu verringern, wurde in den Anweisungen empfohlen, dass sich Benutzer im Voraus anmelden und die Sitzungslebensdauer verlängern. Tatsächlich wurden 50% in 1 Stunde und ~ 90% in einer halben Stunde genehmigt. Wir haben bereits früher festgestellt, dass sich Benutzer 10 Minuten vor dem Start des Dienstes beim Portal anmelden - und die Autorisierung begann instabil zu funktionieren. Es ist schwer zu sagen warum. Vielleicht liegt der Grund darin, dass wir in Chabarowsk, wenn nachts technische Arbeiten in Moskau ausgeführt werden, erst den Beginn des Arbeitstages haben.

Rückzug über Unterricht und organisatorische Vorkehrungen
.

, « » . .. . , - ..

, , , . - . , , .

Es ist unmöglich, die "Delta-Funktion" zu entfernen, wenn das Formular um 00:00 Uhr neu geladen wird. Der springende Punkt dieses Verfahrens ist, dass der Dienst zu einem bestimmten Zeitpunkt angezeigt wird. Sie können jedoch versuchen, die Anzahl der Browseranforderungen auf allen erwarteten Benutzerrouten zu reduzieren und so das System nur von den erforderlichen zu belasten - Formular, dynamische Verzeichnisse und sendende Anwendungen.

Die Nginx-Einstellungen selbst sind ziemlich Standard. Hier ist es wichtiger, die Einschränkungen zu wählen, denen das System standhalten kann. Hebe sie auf - d.h. Starten Sie Warteschlangenanforderungen, wenn der Server voraussichtlich an seine Grenzen stößt.

Nun, und vor allem haben wir das Caching (proxy_cache) erzwungen und die Lebensdauer der "abgelaufenen" Daten in nginx für alle statischen Pfade und, soweit möglich, dynamischen Seiten, auf denen keine Sitzungen vorhanden sind, erhöht. Übrigens ist dies ein häufiger Fehler beim Caching - beim Schreiben in die Cache-Daten (manchmal sogar in statische Daten), in denen die Sitzung eines anderen gespeichert ist, werden diese Cookies normalerweise aus den Headern gelöscht, wenn der Server die Datentypen nicht trennen kann.

Im Browser für den Benutzer sieht es so aus, als würden Seiten aus Dateien aktualisiert, die von der Festplatte oder vom Speicher heruntergeladen wurden. Aber selbst wenn der Benutzer sie vom Server erhält, werden sie aus dem Nginx-Cache entnommen. Die Verzeichnisse selbst werden natürlich im System selbst zwischengespeichert.

Bild

Dies reduzierte die Anzahl potenzieller Anfragen von 89 Anfragen auf 14 und das Volumen von 2,1 MB (für 1000 Benutzer, die die Seite aktualisiert haben, ist dies ein potenzieller Spitzenwert von 4 bis 8 Gbit / s) auf 38 KB (wir alle erinnern uns an das Webpack, für Unternehmensplattformen jedoch nicht immer leicht zu machen). Nach den Ergebnissen der Passage war es weiterhin erforderlich, nicht nur im System, sondern auch in Nginx einige der Verzeichnisse aus den Form- und dynamischen Klassifizierern zwischenzuspeichern, die zum Spitzenzeitpunkt nicht verwendet wurden, und die Lebensdauer für sie zu erzwingen. Und mit zunehmender Last ist es im Allgemeinen sinnvoll, die vollständig statische Hauptseite aufzurufen, auf der Benutzer zum gewünschten Dienst weitergeleitet werden, oder eine separate Ressource für den Dienst zu erstellen.

Um die Belastung beim Senden zu verringern, wurden Entwürfe und das automatische Ausfüllen von Daten für das Kind deaktiviert. Alle Benutzer haben unterschiedliche Dateneingabegeschwindigkeiten, wodurch das Erscheinen eines Formulars, das vollständig zur Übermittlung bereit ist, entfällt und die Delta-Funktion zum Senden von Anträgen vermieden wird - alle 1000 in einer Minute. Gleichzeitig wird die soziale Gerechtigkeit gewahrt, obwohl natürlich Beschwerden auftreten.

Ich werde die Optimierung des Systems selbst nicht beschreiben - während der Lasttests wurden Engpässe festgestellt - hauptsächlich in DBMS-Abfragen und die Indizes und Abfragen selbst wurden optimiert.

Die wahrscheinlich wichtigste Optimierung ist die Vereinfachung des Formulars. Was beeinflusst die Geschwindigkeit am meisten, wenn es in einem Formular implementiert wird?

  • — , , . — 5-10 ( iPhone ) 5- 375 / (1 10 , application/x-www-form-urlencoded – 20 ), 100 625 /. 100/ — . , « ». — ? , . , ?
  • anspruchsvolle Führer. Die Last wird normalerweise mithilfe des FIAS- oder CLADR-Adressverzeichnisses erhöht. Die Probleme hier sind auf die Größe zurückzuführen - FIAS benötigt bis zu 40 GB in der Datenbank und die Suche dauert einige Zeit. Zehntelsekunden, aber multipliziert mit 1000 gleichzeitigen Anforderungen, laden jedes System. Ohne besondere Vorbereitung, möglicherweise in Form eines separaten Webdienstes und einer separaten Ressource, ist es schwierig, der Belastung standzuhalten. Daher verwenden sie häufig ein einfaches Textfeld für die Adresse.

Kommen wir zu den Tests.

Lasttest in Vorbereitung


Die Tests wurden über Puppenspieler durchgeführt - indem Benutzeraktionen im Crominium-Browser emuliert wurden. Yanedeks.tank und JMeter haben den Schutz vor Angriffen aufgehoben, weil sie viele der gleichen Arten von Anfragen generieren. Darüber hinaus stimmen diese Tests nur schwach mit dem Profil realer Abfragen überein, wenn das Verhalten des Systems unter Last geändert wird. Darüber hinaus zwischenspeichern die Server Anforderungen, und es ist schwierig, einen Teil der darin enthaltenen Prozesse zu reproduzieren (z. B. Autorisierung). Übrigens haben wir von einem der devDV- Seminare eine Präsentation mit einer Präsentation über die Verwendung von Puppenspielern zum Testen, einschließlich Laden, Link zum Video .

Zunächst haben wir ein Benutzerverhaltensprofil erstellt und die Prozedur in Schlüsselphasen unterteilt:

  1. Massengenehmigung in ESIA
  2. einmalige Aktualisierung des Serviceformulars,
  3. Massenfutter

Für jede Stufe haben wir einen eigenen Test durchgeführt.

Letztes Jahr gab es in der Zulassungsphase bei ESIA Schwierigkeiten, aber es ist schwierig, sie in vollem Umfang zu testen. Das System ist extern, der Schutz vor Angriffen und Autorisierungsverboten wird ausgelöst. Es ist jedoch möglich, ein Testprofil zu formulieren, um die Engpässe des zu testenden Systems genau zu testen. In der Regel ist dies die Anzahl gleichzeitig autorisierter Sitzungen und geplanter Autorisierungswerte pro Minute, die durch Empfehlungen geregelt werden können.
Im Test ist der Wrapper wichtig für die Organisation mehrerer Threads, wir verwenden den 'Puppenspieler-Cluster'. In der Regel ist es jedoch komplizierter, Ausnahmen zu behandeln und das Verhalten des Portals unter Last zu ändern. Oft werden Layoutelemente angezeigt, die zweimal angezeigt werden. Oder die Elemente werden nicht angezeigt, wenn einige Daten nicht wie erwartet geladen wurden. Dies sind alle Fehler, die Benutzer sehen und die Seite neu laden - was bedeutet, dass sie eine zusätzliche Last erstellen. Es gibt zwei Möglichkeiten: Implementieren der Ausnahmebehandlung im Test. Oder ändern Sie das Portal.

Der Test selbst ist einfach. Unten finden Sie ein Fragment vom Klicken auf die Schaltfläche "Anmelden" im Serviceportal bis zur Eingabe von Daten in ESIA.

await page.waitForSelector(AUTH_AVAIL,{timeout:OPT_ELEM_WAIT_TIME});
const needAuth = await page.$(ELEM_AUTH_IN);
if (!needAuth) throw (new Error(`  `));
        
await page.waitForSelector(AUTH_BUT, OPT_ELEMENT_VISIBLE);
await page.click(AUTH_BUT);
await waitNewUrl(page, 'https://esia.gosuslugi.ru/idp/rlogin?cc=bp', OPT_PAGE_WAIT_TIME);
await page.waitForSelector('#mobileOrEmail', OPT_ELEMENT_VISIBLE);
let text = await elemGetText(page, '#authnFrm > div.login-slils-box > div > div.detected > div.left > div.this-user');
if (text) 
   text = text.replace(/ -\(\)/g, '');        
if (text && text.indexOf(user) === -1) {
  await page.click('div.click-to-another > a');
  await page.waitForSelector('#authnFrm > div.login-slils-box > div >' +
                ' div.detected > div.left > div.this-user', OPT_ELEMENT_INVISIBLE);
}
await page.waitForSelector('#password', OPT_ELEMENT_VISIBLE);
await page.type('#mobileOrEmail', user);
await page.type('#password', pwd);
await page.click('#loginByPwdButton');

Überprüfung der Aktualisierung des Antragsformulars, bis Benutzer "den Datensatz öffnen". Der Neustarttest besteht im Wesentlichen aus einem Schritt. Es ist jedoch wichtig, die zurückgegebenen Fehlertypen zu überprüfen. Das Netzwerk ist ein Problem, ein Nginx-Fehler, ein Serverfehler und ob das Formular die Kriterien erfüllt. Die Schwierigkeit besteht darin, das maximale Anforderungsvolumen in kürzester Zeit zu generieren und nicht unter die Schutzbeschränkungen zu fallen (während der Tests kann es jedoch geändert werden, andererseits wird auch die Einstellung der Netzwerk- und Serverinfrastruktur und der WAF überprüft).

Solche Tests an Puppenspielern erfordern eine Menge Ressourcen, um zu arbeiten. De facto stellte sich heraus, dass Sie mindestens 2 Kerne gegen den 1. Kern des Front-End-Subsystems und einen sehr breiten Kanal benötigen. Aber wenn Sie sie in der Cloud mieten - das ist ziemlich erschwinglich. Wir haben Yandex.cloud verwendet.

Im Test wird die Autorisierung zunächst in ESIA für jeden Stream separat implementiert. Danach wird für jeden Thread ein separater Browser gestartet und im Rahmen einer Instanz eine bestimmte Anzahl von Updates durchgeführt. Danach wird die Instanz neu gestartet. Die Prüfung selbst kann einen typischen Pfad enthalten, z. B. die Hauptseite und die Form des Dienstes. In den meisten Fällen reicht es jedoch aus, nur den Dienst vollständig zu aktualisieren und das erforderliche Verzeichnis zu überprüfen, in dem der Dienst gesendet werden kann - alles wie in den Anweisungen für Benutzer.

Bild

Ein Fragment des Tests zum Öffnen der Haupt- und Aktualisierungsseite.

try {
  await page.setViewport(PUP_OPT);
  await page.goto(BASE_URL);
  await page.setCookie(...cookies[worker.id]);
  await page.goto(`${BASE_URL}/nd/lk/form/dnv.htm`);
  rdyRefresh++;
} catch (err) {
  console.error(`#       ${data}: ${err.message}`);
  getErr++;
  await page.screenshot({path: filename});
}
for (let i = 0; i < AMOUNT_REFRESH - 1; i++) {
  const filenameIter = path.join(BASE_DIR, PIC_DIR, `${data}-${i}.png`);
   try {
       await page.reload({waitUntil: ["networkidle0", "domcontentloaded"]});
        rdyRefresh++;
    } catch (err) {
        if (!err.message.includes('Navigation failed because browser')) {
           console.error(`#     ${data}-${i}: ${err.message}`);
           getErr++;
           await page.screenshot({path: filenameIter});
        }
   }
}

Für das Laden durch Senden von Anwendungen wurde der gesamte Überprüfungszyklus implementiert - mit einem erneuten Laden des Formulars und einer Überprüfung der Eingabe aller Daten.

Fragment.

for (let i = 0; i < AMOUNT_RESEND; i++) {
   const filename = path.join(BASE_DIR, PIC_DIR, `${data}-${i}.png`);
  try {
     await page.goto('https://uslugi27.ru/nd/lk/form/dnv.htm');
  } catch (err) {
      console.error(`#      1  ${data}-${i}: ${err.message}`);
      await page.screenshot({path: filename});
      getErr++;
      continue;
 }
 try {
     const FORM_PREF = '#createForm > div:nth-child(4) > ';
     await clickDelayed(page,`${FORM_PREF}fieldset.petgroup.ungroupped-attrs > div > div:nth-child(4) > div.col-md-9.attr-data`);
// <…>
     await page.type(`${FORM_PREF}fieldset:nth-child(2) > div > div:nth-child(1) > div.col-md-9.attr-data > input`, '');
// <…>
  } catch (err) {
      console.error(`#      ${data}-${i}: ${err.message}`);
      await page.screenshot({path: filename});
     continue;
  }
  try {
      await page.click('#createForm > div.col_100.controls > button.btn.btn-primary.pull-right.next');
      await clickDelayed(page,`#createForm > div:nth-child(5) > fieldset > div > div:nth-child(1) > div > div`);
       await page.click('#createForm > div:nth-child(5) > fieldset > div > div:nth-child(2) > div > div');
       await page.click('#createForm > div.col_100.controls > button.btn.btn-success.pull-right.submit');
  } catch (err) {
    console.error(`#     ${data}-${i}: ${err.message}`);
    await page.screenshot({path: filename});
    sendErr++;
    continue;
  }

Übrigens kann der Test beschleunigt werden, wenn Sie alle Daten, die nicht vom Puppenspieler stammen, über das Konstrukt "wait page.type" eingeben, diese Logik jedoch auf den Browser selbst übertragen. Aber dann nimmt die Komplexität des Abfangens von Fehlern zu. Wie so

document.querySelector('#createForm > div:nth-child(4) > fieldset.petgroup.ungroupped-attrs > div > div:nth-child(4) > div.col-md-9.attr-data').click();
 document.querySelector('#createForm > div:nth-child(4) > fieldset:nth-child(2) > div > div:nth-child(1) > div.col-md-9.attr-data > input').value = '';

Während der Tests haben wir mehrere tausend ESIA-Genehmigungen bereitgestellt und etwa 16.000 Anträge gesendet. Wie war die Wiederherstellung eines produktiven Bildungsinformationssystems nach einer solchen Anzahl von Aussagen - fragen Sie nicht einmal. Dies ist eine ganz andere Geschichte.

Das wichtigste sichtbare Ergebnis dieses Prozesses war, dass die lokalen Medien in den Tagen der Einschreibung in die erste Klasse gelangweilt waren. Der Dienst hat den Medienbereich verlassen.

Parallel dazu haben wir ein Dashboard zur Überwachung der Leistung des Formulars basierend auf Grafana erstellt: Anzahl der Anwendungen, Anzahl der Anrufe, Yandex-Metriken usw. Aber wir werden dieses Thema für das nächste Mal verlassen.

Nun, ich möchte allen gratulieren, die mit dem Thema der Verbesserung der Qualität der Erbringung staatlicher und kommunaler Dienstleistungen in elektronischer Form verbunden sind. Diese endlosen Vorarbeiten waren nicht umsonst - schließlich hat die Zahl der eingereichten Anträge im April und Mai deutlich zugenommen.

All Articles