Patchen von Java-Code in der Produktion ohne Betäubung

Bild

Hier werde ich über das Gerät eines der vielen Tools sprechen, die bei der Entwicklung verschiedener Dienste für das Odnoklassniki-Projekt helfen. Innerhalb des Unternehmens nennen wir es „Hot Code Replace“ (HCR). Dieses Tool wurde entwickelt, um kritische und unkomplizierte Fehler beim Ausführen von Produktionsdiensten zu beheben, ohne sie zu stoppen. Dies ist eine äußerst wichtige Funktion, da Sie so den ziemlich langweiligen und zeitaufwändigen Prozess des Erstellens einer neuen, korrigierten Version des Junk-Dienstes vermeiden, die ausreichend lange Pause der Verfügbarkeit jedes Hosts durch die Begleitperson vermeiden und das Leeren von Caches vermeiden können.

Im Allgemeinen spart dies viel Zeit und verkürzt das Intervall vom Erkennen des Fehlers bis zur Korrektur von Stunden auf Minuten. In den meisten Fällen werden, wie geplant, kleinere Fehler im Code behoben. Beispielsweise hat der Programmierer vergessen, auf Null zu prüfen, und bei einigen Benutzern führen bestimmte Aktionen auf der Site zu einem Fehler. Das heißt, wenn die Korrektur durch Ändern mehrerer Zeilen innerhalb des Verfahrens durchgeführt wird. Und für solche geringfügigen Änderungen müssen Sie Ihre Kollegen nicht mehr ablenken und stundenlang auf die Produktion warten.

Zum Beispiel:

Bild
Sie können es leicht beheben auf:

Bild
Natürlich können Sie viel mehr Änderungen vornehmen, gleichzeitig neue Klassen hinzufügen und schnell Änderungen vornehmen, die der Manager gleichzeitig anfordert, ohne auf das nächste Update zu warten. Aber das ist schon so, wenn Monsieur viel über Perversionen weiß.

Ferner ist es möglich, "Flecken" aufeinander und bis ins Unendliche zu setzen.

Dieses Tool ist jedoch nicht allmächtig und basiert auf der Standardfunktionalität, die die Java-Klasse bietet: java.lang.instrument.Instrumentation und ihre Methode void redefineClasses (ClassDefinition ... Definitionen) .

Instrumentation.redefineClasses ersetzt zuvor geladene Klassen durch neuen Bytecode. Sie können mehrere Klassen mit unterschiedlichen Abhängigkeiten gleichzeitig überladen. Durch das Überladen werden vorhandene Klasseninstanzen nicht geändert, die Vererbung nicht geändert und Instanz- oder Klassenfelder nicht berührt. Sie können nur den Hauptteil der Methode, den Pool von Konstanten und Attributen ändern. Sie können neue Klassen oder Unterklassen hinzufügen. Methodensignaturen, Instanzfelder und Klassenfelder können nicht geändert werden. Wenn Sie versuchen, inkompatible Änderungen vorzunehmen, funktioniert redefineClasses im Prinzip nicht und gibt einen Fehler aus. Es ist zu beachten, dass bei Überladung von Klassen die Ausführung des überladenen Codeabschnitts nicht unterbrochen wird und der neue Bytecode beim nächsten Aufruf derselben Methode verwendet wird. Wenn Sie also versuchen, den Code einer Methode zu reparieren, in der sich ein unendlich langer Zyklus befindet, erfolgt der eigentliche Austausch erst nach dem Ende dieses Zyklus.

Wenn ganz einfach: Sie können den Code nur innerhalb der Methoden und des Punktes ändern.

Und hier ist ein Beispiel für eine while-Schleife, die bis zum Abschluss der Methode nicht behoben wird.

Bild

Die Hauptschwierigkeit bestand darin, ein Werkzeug zu entwickeln, das im Odnoklassniki-Ökosystem funktioniert, ein Werkzeug, das in alle etablierten Arbeitsprozesse passt. Das wird konsistent und transparent mit allen Diensten auf Hunderten von Hosts interagieren sowie flexibel und einfach zu bedienen sein. Dieses Tool sollte Dutzende von Experimenten, Arbeiten und Aktualisierungen bewältigen, die kontinuierlich in der Produktion auftreten.

Wie sieht der Prozess der Installation eines Patches aus Sicht eines Entwicklers / Administrators aus, der versucht, einen Fehler in der Produktion zu beheben, aber damit ein Standardverfahren und ein zuverlässiges Verfahren auf Dutzenden von Servern angewendet werden können? Wir lassen das Auffinden und Beheben von Fehlern im Code aus.

1. In GIT wird ein separater Brunch für Codekorrekturen erstellt. Die Verwendung der Versionierung ist nicht nur aus praktischen Gründen, sondern auch für spätere mögliche Untersuchungen sehr wichtig.

2. TeamCity startet den Patch-Erstellungsprozess. Zuerst wird aus dem angegebenen Brunch eine Projektbaugruppe erstellt, und dann wird die neue Baugruppe mit der in der Produktion installierten Baugruppe verglichen. Zu diesem Zweck habe ich ein Plug-In für das Build-Tool geschrieben, das alle Dateien aus Archiven extrahiert, Diskrepanzen vergleicht und nur die Dateien auswählt, die geändert oder hinzugefügt wurden. In diesem Fall sollte die Version des Java-Compilers in beiden Assemblys identisch sein, da Eine andere Version des Compilers erstellt andere Dateien und fast alle Projektdateien werden in den Patch aufgenommen. Es ist sehr wichtig, nur ein kleines Archiv zu erstellen, in das nur die notwendigen Dateien gelangen, weil Dies wird den Prozess der Bereitstellung des Patches für Dutzende von Servern erheblich beschleunigen. Der Erstellungsprozess eignet sich nicht nur für den Patch des Projektcodes, sondern Sie können auch die gepatchte Bibliothek im Projekt ersetzen. Beim Vergleich des Inhalts zweier Assemblys werden Unterschiede in Bibliotheken (JAR-Dateien) festgestellt.

3. Bei erfolgreicher Montage wird der Patch an ein spezielles Repository gesendet, und im Ergebnisfenster wird ein Schlüssel (oder Hash) ausgegeben, der zur eindeutigen Identifizierung des Patches und zur Gewährleistung, dass dieser Code in die Produktion gelangt, erforderlich ist.

Bild

Nun, und wieder - Sie können eine unbegrenzte Anzahl von Malen patchen und Builds mit derselben Versionsnummer unterscheiden sich durch einen Hash.

4. Als nächstes werden alle Aktivitäten an den Konfigurationsdienst übertragen, wo Sie in der üblichen Benutzeroberfläche angeben können, für welchen Dienst, auf welchen Hosts und für welche Versionen von Anwendungen Sie patchen müssen.

Bild

Eine solche Fülle von Parametern bietet das erforderliche Maß an Flexibilität bei den Einstellungen, was in einem großen Zoo von vielen Servern aus sehr wichtig ist. Angenommen, auf einigen Teilen der Server ist die Versionsnummer der Anwendung unterschiedlich, und Sie müssen diesen Code überhaupt nicht patchen. Zur Überprüfung wird Hot Code Rreplace zunächst auf einem Server oder einer Gruppe von Servern gestartet und dann auf alle Instanzen der Anwendung verteilt.

5. Durch eine Konfigurationsänderung erhalten die ausgewählten Dienste Informationen darüber, was der Patch installiert werden muss, seine Version und seinen Überprüfungs-Hash. Die Idee ist, dass alle Dienste den Befehl "Installieren des Patches" erhalten und dann unabhängig agieren. Sie vergleichen unabhängig voneinander ihre eigene Version. Nur wenn die Version übereinstimmt und der Hash des Patches fehlt oder anders ist, laden sie die Patch-Assembly unabhängig voneinander aus dem Repository herunter. Der Downloadvorgang selbst erfolgt über HTTP, und Sie können die Repository-Adresse, die Anzahl der Downloadversuche und die Wartezeit zwischen den Wiederholungsversuchen schnell ändern.

6. Jede Anwendung überprüft lokal den Hash der Assembly und entpackt ihn. In diesem Fall wird jede Datei unter den von Instrumentation.getAllLoadedClasses () zurückgegebenen Dateien auf ihr Vorhandensein im Array überprüft. Alle neuen Klassen und Dateien werden in eine neue Datei geschrieben - einen temporären Klassenpfad. Dieser Klassenpfad wird über Instrumentation.appendToSystemClassLoaderSearch () hinzugefügt, und vorhandene Klassen werden in den Speicher und eingelesen Durchlaufen Sie die redefineClasses-Methode.

7. Der gesamte Prozess: Das Eintreffen eines Signals über die Notwendigkeit, die Anwendung zu patchen, herunterzuladen, zu verifizieren, zu entpacken und die Anwendung wird detailliert protokolliert, sowohl im allgemeinen Protokoll mit der Anwendung als auch in der eigenen, so dass Sie den Prozess schnell und ohne unnötige Gesten überwachen können.

8. Nachdem der Patch erfolgreich angewendet wurde, endet der Prozess mit dem Ändern der Anwendungsversion in die gepatchte Version, indem eine speziell zusammengesetzte Zeile mit dem Patch-Hash hinzugefügt wird. Für den Fall, dass für einige Hosts die Version nicht auf die erwartete geändert wurde, gehen wir zum Hot Code Replace-Protokoll für diesen Host und sehen, was dort passiert ist. Wenn dies Kommunikationsprobleme waren, können Sie den Patch-Befehl sicher wiederholen, und der gewünschte Host versucht es erneut.

Welche möglichen Probleme können das Patchen der Anwendung verhindern? Es gibt einige von ihnen, und unter ihnen die Funktionalität der Instrumentierungsklasse, die ich an letzter Stelle setzen würde. Bisher wurde krummer Code, der die strengen Bedingungen von redefineClasses nicht erfüllt, von der JVM immer ohne Konsequenzen für die Anwendung geflasht. Bei Anwendung der Methode redefineClasses stoppt die JVM die Anwendung vollständig, dieser Vorgang dauert jedoch einen Sekundenbruchteil. Weil es überhaupt nicht beängstigend ist.

Der riskanteste Moment ist die Lieferung des Patches an den Server, die durch zusätzliche Umschulungen entschieden wurde. Wenn Retrays jedoch nicht helfen, können Sie den Befehl zum Aufrufen des Patches wiederholen, und jeder der Hosts versucht, den Vorgang zu wiederholen, installiert den Patch jedoch nur bei Bedarf, d. H. Der Patch wurde zuvor nicht installiert oder wenn sich der Hash-Schlüssel geändert hat.

Ein weiteres potenzielles Problem besteht darin, dass das Update einen Fehler behebt und einen neuen hinzufügt. Um dieses Risiko zu minimieren, laden wir den Patch zunächst auf eine begrenzte Anzahl von Servern hoch, sehen uns die Protokolle und Diagramme an und überwachen das Ergebnis. Und erst dann führen wir Korrekturen für andere Hosts durch.

Was tun beim Neustart einer Anwendung oder eines Servers? Dies ist bereits in die Logik aller Klassenkameradenanwendungen eingebettet: Eine der ersten in jeder Anwendung ist das HCR-Modul. Wenn während der Initialisierung Informationen über die Notwendigkeit des Patchens der Anwendung bemerkt werden, wird der Patch zuerst angewendet.

Und nun ein wenig darüber, woraus Hot Code Replace besteht.

  1. Unser JavaAgent. JavaAgent, falls jemand dies vergessen hat , ist dies ein separates, speziell geformtes * .jar-Archiv, das von der JVM abgerufen wird, wenn die Anwendung einen zusätzlichen Parameter verwendet, z. B.: -Javaagent: /path/to/lib/my-agent.jar Dank der zusätzlichen Funktionen von Javaagent- und es ist möglich, Code-Ersatz-Magie zu verwenden Im Agenten ist die Klasse java.lang.instrument.Instrumentation verfügbar. Aber ich habe ihn (den Agenten) nicht mit zusätzlichem Code verstopft, weil Die Agentenaktualisierung ist eine nicht triviale Aufgabe, sondern verschiebt einfach die Instanz der Instrumentation-Klasse in das statische Feld der Utility-Klasse. Somit können alle Manipulationen von überall in der Anwendung initiiert werden.
  2. Konfigurationsdienst - ist für die Konfiguration einer unserer Anwendungen verantwortlich und wird daher in jeder Anwendung zuerst initialisiert. Dort ist die Hauptfunktionalität von Hot Code Replace verborgen. Beim Start der Anwendung oder beim Ändern der HCR-Konfiguration für eine bestimmte Anwendung wird die Versionskompatibilität überprüft und alle oben genannten Manipulationen werden durchgeführt.
  3. TeamCity und Build-Skripte - um bequem „Patches“ zu erstellen und nur geänderte oder hinzugefügte Klassen und Ressourcen darin zu speichern.

Welche Vorteile bietet dieses Tool? Die erste ist die Geschwindigkeit, mit der kritische Fehler im Produkt korrigiert werden. Aus den Protokollen geht hervor, dass Kollegen HCR nach und nach immer häufiger verwendeten, anstatt auf Veröffentlichungen zu warten. Als nächstes kommt die Geschwindigkeit der Anwendung. Die Anwendung muss nicht gestoppt werden, die JVM friert nur für den Bruchteil einer Sekunde ein und alle Ihre Objekte bleiben an ihrem Platz und arbeiten weiter.

Und unsere Entwickler heilten frei und glücklich und korrigierten ihre Fehler sofort und unabhängig direkt in der Produktion, unabhängig von der Anzahl der Server und der Auslastung.

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


All Articles