Einschränkungen, gegen die verstoßen werden muss, oder wie wir Funktionstests dreimal beschleunigt haben

Bild

Funktionstests sind eine nützliche Sache. Anfangs brauchen sie nicht viel Zeit, aber das Projekt wächst und es werden immer mehr Tests benötigt. Wir hatten nicht vor, eine Verlangsamung der Liefergeschwindigkeit zu tolerieren, und haben die Funktionstests dreimal beschleunigt, um unsere Kräfte zu sammeln. In dem Artikel finden Sie universelle Tipps, Sie werden jedoch einen besonderen Effekt auf große Projekte bemerken.

Kurz über die Anwendung


Mein Team entwickelt eine öffentliche API, die 2GIS-Benutzern Daten zur Verfügung stellt. Wenn Sie zu 2gis.ru gehen und nach "Supermärkten" suchen, erhalten Sie eine Liste der Organisationen - dies sind die Daten aus unserer API. Bei unserem RPS über 2000 wird fast jedes Problem kritisch, wenn eine Funktionalität ausfällt.

Die Anwendung ist in Scala geschrieben, Tests sind in PHP geschrieben, die Datenbank ist PostgreSQL-9.4. Wir haben ungefähr 25.000 Funktionstests, die auf einer dedizierten virtuellen Maschine für die allgemeine Regression 30 Minuten dauern. Die Dauer der Tests hat uns nicht sonderlich gestört - wir waren daran gewöhnt, dass Tests mit dem alten Framework 60 Minuten dauern konnten.

Wie wir die sogenannten „Schnelltests“ beschleunigt haben


Alles begann zufällig. Wie immer. Wir haben eine Funktion nach der anderen unterstützt und gleichzeitig Tests bestanden. Ihre Zahl wuchs und auch die notwendige Zeit, um sie zu vollenden. Sobald die Tests begannen, die ihnen zugewiesenen Fristen zu überschreiten, wurde der Prozess ihrer Ausführung mit Gewalt beendet. Unvollständige Tests sind mit einem fehlenden Problem im Code behaftet.

Wir haben die Geschwindigkeit der Tests analysiert und die Aufgabe, sie stark zu beschleunigen, wurde relevant. So begann eine Studie mit dem Titel "Tests arbeiten langsam - beheben Sie sie."

Im Folgenden sind drei der großen Probleme aufgeführt, die wir bei den Tests festgestellt haben.

Problem 1: Missbrauchte jsQuery



Alle Daten, die wir haben, werden in der PostgreSQL-Datenbank gespeichert. Meistens in Form von json, daher verwenden wir jsQuery aktiv.

Hier ist ein Beispiel für eine Abfrage, die wir in der Datenbank durchgeführt haben, um die erforderlichen Daten abzurufen:

SELECT * FROM firm WHERE json_data @@ 'rubrics.@# > 0' AND json_data @@ 'address_name = *' AND json_data @@ 'contact_groups.#.contacts.#.type = “website”' ORDER BY RANDOM() LIMIT 1 

Es ist leicht zu bemerken, dass das Beispiel json_data mehrmals hintereinander verwendet, obwohl es richtig wäre, dies zu schreiben:

 SELECT * FROM firm WHERE json_data @@ 'rubrics.@# > 0 AND address_name = * AND contact_groups.#.contacts.#.type = “website”' ORDER BY RANDOM() LIMIT 1 

Solche Mängel waren nicht allzu auffällig, da wir in Tests nicht alle Abfragen mit unseren Händen schreiben, sondern QueryBuilder verwenden, die sie selbst nach Angabe der erforderlichen Funktionen zusammenstellen. Wir dachten nicht, dass dies die Geschwindigkeit der Abfrageausführung beeinflussen könnte. Dementsprechend sieht es im Code ungefähr so ​​aus:

 $qb = $this>createQueryBulder() ->selectAllBranchFields() ->fromBranchPartition() ->hasRubric() ->hasAddressName() ->hasWebsite() ->orderByRandom() ->setMaxResults(1); 

Wiederholen Sie unsere Fehler nicht : Wenn ein JSONB-Feld mehrere Bedingungen enthält, beschreiben Sie sie alle im Rahmen des einzelnen Operators '@@'. Nach dem Redid haben wir die Ausführungszeit jeder Anforderung zweimal beschleunigt. Früher dauerte die beschriebene Anforderung 7500 ms, jetzt dauert sie 3500 ms.

Problem 2: Zusätzliche Testdaten



Der Zugriff auf unsere API erfolgt über einen Schlüssel. Jeder Benutzer hat seine eigene API. Bisher war es in Tests häufig erforderlich, die Tasteneinstellungen zu ändern. Aus diesem Grund fielen die Tests.

Wir haben beschlossen, für jeden Regressionslauf mehrere Schlüssel mit den erforderlichen Einstellungen zu erstellen, um Kreuzungsprobleme zu vermeiden. Und da das Erstellen eines neuen Schlüssels die Funktionalität der gesamten Anwendung nicht beeinträchtigt, hat dieser Testansatz keine Auswirkungen. Sie lebten ungefähr ein Jahr unter solchen Bedingungen, bis sie anfingen, sich mit Produktivität zu befassen.

Es gibt nicht viele Schlüssel - 1000 Stück. Um die Anwendung zu beschleunigen, speichern wir sie im Speicher und aktualisieren sie alle paar Minuten oder bei Bedarf. Nach dem Speichern des nächsten Schlüssels starteten die Tests den Synchronisationsprozess, auf dessen Ende wir nicht gewartet haben. Wir erhielten die Antwort „504“, die in die Protokolle geschrieben wurde. Gleichzeitig signalisierte die Anwendung in keiner Weise ein Problem, und wir fanden, dass alles für uns großartig funktionierte. Der Regressionstestprozess selbst wurde fortgesetzt. Und am Ende stellte sich heraus, dass wir immer Glück hatten und unsere Schlüssel gerettet wurden.

Wir lebten in Unwissenheit, bis wir die Protokolle überprüften. Es stellte sich heraus, dass wir die Schlüssel erstellt, aber nach dem Ausführen der Tests nicht gelöscht haben. So haben wir 500.000 davon angesammelt.

Wiederholen Sie unsere Fehler nicht: Wenn Sie die Datenbank in den Tests irgendwie ändern, stellen Sie sicher, dass die Datenbank wieder in ihren ursprünglichen Zustand versetzt wird. Nachdem wir die Datenbank bereinigt hatten, wurde der Schlüsselaktualisierungsprozess 500-mal beschleunigt.

Problem 3: Zufallsstichprobe



Wir lieben es, die Anwendung mit verschiedenen Daten zu testen. Wir haben viele Daten und es treten regelmäßig Probleme auf. Zum Beispiel gab es einen Fall, in dem keine Werbedaten hochgeladen wurden, aber Tests dieses Problem rechtzeitig erkannt haben. Deshalb sehen Sie in jeder Anfrage unserer Tests ORDER BY RANDOM ()

Bei der Betrachtung der Ergebnisse von Abfragen mit und ohne Zufälligkeit mit EXPLAIN konnten wir eine 20-fache Leistungssteigerung feststellen. Wenn wir über das obige Beispiel sprechen, funktioniert es ohne Randomisierung für 160 ms. Wir haben ernsthaft darüber nachgedacht, was wir tun sollen, weil wir das zufällige Haus nicht wirklich komplett verlassen wollten.

In Nowosibirsk gibt es beispielsweise etwa 150.000 Unternehmen, und als wir versuchten, ein Unternehmen mit einer Adresse, einer Website und einer Überschrift zu finden, erhielten wir eine zufällige Aufzeichnung aus fast der gesamten Datenbank. Wir haben beschlossen, die Auswahl auf die ersten 100 Unternehmen zu reduzieren, die unseren Bedingungen entsprechen. Das Ergebnis der Überlegungen war ein Kompromiss zwischen einer ständigen Auswahl unterschiedlicher Daten und der Geschwindigkeit:

 SELECT * FROM (SELECT * FROM firm_1 WHERE json_data @@ 'rubrics.@# > 0 AND address_name = * AND contact_groups.#.contacts.#.type = "website"' LIMIT 100) random_hack ORDER BY RANDOM() LIMIT 1; 

Auf diese einfache Weise haben wir bei 20-facher Beschleunigung fast nichts verloren. Die Ausführungszeit einer solchen Anfrage beträgt 180 ms.

Wiederholen Sie unsere Fehler nicht: Dieser Moment kann natürlich kaum als Fehler bezeichnet werden. Wenn Sie wirklich viele Tests haben, denken Sie immer daran, wie viel Zufälligkeit in den Daten benötigt wird. Der Kompromiss zwischen der Geschwindigkeit der Abfrageausführung in der Datenbank und der Eindeutigkeit der Auswahl hat uns geholfen, SQL-Abfragen um das 20-fache zu beschleunigen.

Nochmals eine kurze Liste von Aktionen:


  1. Wenn wir im JSONB-Feld mehrere Bedingungen für die Auswahl von Daten angeben, müssen diese in einem einzigen Operator '@@' aufgeführt werden.
  2. Wenn wir Testdaten erstellen, müssen Sie diese unbedingt löschen. Auch wenn es den Anschein hat, dass ihre Anwesenheit die Funktionalität der Anwendung nicht beeinträchtigt.
  3. Wenn Sie für jeden Lauf zufällige Daten benötigen, finden wir einen Kompromiss zwischen der Eindeutigkeit der Stichprobe und der Ausführungsgeschwindigkeit.

Wir haben die Regression dank einfacher (und für einige wahrscheinlich sogar offensichtlicher) Modifikationen dreimal beschleunigt. Jetzt sind unsere 25K-Tests in 10 Minuten abgeschlossen. Und das ist nicht die Grenze - wir optimieren als nächstes den Code. Es ist nicht bekannt, wie viele unerwartete Entdeckungen uns dort erwarten.

Source: https://habr.com/ru/post/de419671/


All Articles