[JAVA] Leistungsprobleme bei Serialisierungsvorgängen im Zusammenhang mit der Verwendung von LocalDateTime

Dieser Artikel beschreibt Leistungsprobleme im Zusammenhang mit der Verwendung der Formate LocalDateTime und Instant Time, auf die Alibaba-Ingenieure während des Serialisierungsprozesses gestoßen sind.

Von Lv Renqi

Performance-Probleme

Bei der Durchführung eines Leistungsdrucktests mit einer neuen Version von Apache Dubbo das Attribut der Klasse Transfer Object (TO) Ich habe ein verwandtes Problem gefunden. Durch Ändern von "Date" in "LocalDateTime" wurde der Durchsatz von 50.000 auf 20.000 reduziert und die Antwortzeit von 9 ms auf 90 ms erhöht.

Von diesen Änderungen waren wir am meisten besorgt über die Änderung der Reaktionszeit. Die Reaktionszeit ist in vielerlei Hinsicht der Eckpfeiler guter Leistungsdaten, da Leistungsindikatoren erst dann von Bedeutung sind, wenn ein bestimmtes Reaktionszeitniveau sichergestellt ist. Für Stresstests sind Gigabit-pro-Sekunde- (GPS) und Transaktions-pro-Sekunde- (TPS) Nummern nur zulässig, wenn die Zielantwortzeitnummern erreicht sind. Reine theoretische Zahlen sind bedeutungslos. Beim Cloud Computing ist jede Antwortzeit wichtig. Eine Verlängerung der Antwortzeit des zugrunde liegenden Dienstes um 0,1 ms bedeutet eine Erhöhung der Gesamtkosten um 10%.

Die Latenz ist wie die Achillessehne eines Systems mit Remote-Benutzern. Die Verzögerung des Datenpakets erhöht sich pro 100 km um 1 Millisekunde. Die Wartezeit zwischen Hangzhou und Shanghai beträgt etwa 5 Millisekunden, und die Wartezeit zwischen Shanghai und Shenzhen ist aufgrund der erheblich größeren Entfernung natürlich noch höher. Das direkte Ergebnis der Latenz ist eine Verlängerung der Antwortzeit, die die Benutzererfahrung insgesamt verschlechtert und die Kosten erhöht.

Wenn die Anforderung die Datensätze in derselben Zeile in verschiedenen Einheiten ändert, sind die Kosten sehr hoch, selbst wenn sie konsistent und konsistent sein können. Remote Fast Service Framework, Ein in Alibaba weit verbreitetes verteiltes RPC-Service-Framework. Wenn ein Dienst bei einer Anforderung, die mehr als zehnmal Zugriff auf den Dienst 0.18e27d1f7aNxOS (HSF) oder eine andere entfernte Datenbank erfordert, einen anderen Dienst anruft, wird die Latenz sofort mit einem Schneeballeffekt hinzugefügt.

Bedeutung der Universalität in Java

Der Umgang mit der Zeit ist überall in der Welt der Informatik. Ohne den strengen Zeitbegriff wären 99,99% der Anträge bedeutungslos und unpraktisch. Dies gilt insbesondere für die zeitorientierte benutzerdefinierte Verarbeitung, die heutzutage in den meisten Überwachungssystemen in der Cloud zu finden ist.

Java Development Kit 8 (JDK 8) Zuvor java.util.Date wurde verwendet, um Datum und Uhrzeit zu beschreiben, und java.util.Calendar wurde für zeitbezogene Berechnungen verwendet. JDK 8 führt bequemere Zeitklassen wie "Instant", "LocalDateTime", "OffsetDateTime" und "ZonedDateTime" ein. Im Allgemeinen haben diese Klassen die Zeitverarbeitung komfortabler gemacht.

Instant speichert Zeitstempel im UTC-Format (Agreement World Time) und bietet eine maschinenseitige oder interne Zeitanzeige. Es eignet sich für Szenarien zur Datenbankspeicherung, Geschäftslogik, zum Datenaustausch und zur Serialisierung. "LocalDateTime", "OffsetDateTime" und "ZonedDateTime" enthalten Zeitzonen- oder Saisoninformationen und bieten Benutzern eine Zeitanzeige zur Eingabe und Ausgabe von Daten. Wenn dieselbe Zeit an verschiedene Benutzer ausgegeben wird, sind die Werte unterschiedlich. Beispielsweise wird Käufern und Verkäufern die Lieferzeit einer Bestellung zu unterschiedlichen Ortszeiten angezeigt. Sie können sich diese drei Klassen als Werkzeuge vorstellen, die nach außen und nicht nach den internen Arbeitsteilen der Anwendung gerichtet sind.

Kurz gesagt, "Instant" eignet sich für Back-End-Dienste und -Datenbanken, während "LocalDateTime" und seine Kohorte für Front-End-Dienste und -Anzeigen geeignet sind. Die beiden sind theoretisch kompatibel, erfüllen aber tatsächlich unterschiedliche Funktionen. Das internationale Business-Team verfügt über eine Fülle von Erfahrungen und Ideen in dieser Hinsicht.

Date und Instant werden häufig verwendet, um Dubbo in das interne High Speed Services Framework (HSF) von Alibaba zu integrieren.

Reproduktion von Leistungsproblemen

Sie können versuchen, es zu reproduzieren, um ein genaues Bild von den Leistungsproblemen zu erhalten, die Sie zuvor gesehen haben. Aber zuerst betrachten wir die Leistungsvorteile von "Instant" anhand einer kurzen Demo. Betrachten Sie dazu das allgemeine Szenario, ein Datum im Format "Datum" zu definieren und dann das Format "Sofort" zu verwenden.

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public String date_format() {
        Date date = new Date();
        return new SimpleDateFormat("yyyyMMddhhmmss").format(date);
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public String instant_format() {
        return Instant.now().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern(
                "yyyyMMddhhmmss"));
    }

Führen Sie anschließend den Stresstest 30 Sekunden lang an vier lokalen gleichzeitigen Threads aus. Das Ergebnis ist wie folgt.

Benchmark                            Mode  Cnt        Score   Error  Units
DateBenchmark.date_format           thrpt       4101298.589          ops/s
DateBenchmark.instant_format        thrpt       6816922.578          ops/s

Aus diesen Ergebnissen können wir schließen, dass "Instant" hinsichtlich der Formatleistung vorteilhaft ist. Tatsächlich hat Instant auch für andere Vorgänge einen Leistungsvorteil. Beispielsweise wurde festgestellt, dass Instant beim Addieren und Subtrahieren von Datum und Uhrzeit eine vielversprechende Leistung zeigt.

Sofortige Fallstricke bei Serialisierungsvorgängen

Als Replikation des oben gezeigten Problems Java und Hessian (optimiert für Taobao) Wir haben auch Stresstests durchgeführt, um die Leistungsänderungen während der Serialisierungs- bzw. Deserialisierungsvorgänge festzustellen.

Hessisch ist HSF 2.2 und Dubbos Standard-Serialisierungsschema:

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public Date date_Hessian() throws Exception {
        Date date = new Date();
        byte[] bytes = dateSerializer.serialize(date);
        return dateSerializer.deserialize(bytes);
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public Instant instant_Hessian() throws Exception {
        Instant instant = Instant.now();
        byte[] bytes = instantSerializer.serialize(instant);
        return instantSerializer.deserialize(bytes);
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    public LocalDateTime localDate_Hessian() throws Exception {
        LocalDateTime date = LocalDateTime.now();
        byte[] bytes = localDateTimeSerializer.serialize(date);
        return localDateTimeSerializer.deserialize(bytes);
    }

Das Ergebnis war wie folgt. Bei Verwendung des hessischen Protokolls sank der Durchsatz bei Verwendung der Formate "Instant" und "LocalDateTime" stark. In der Realität ist der Durchsatz 100-mal niedriger als bei Verwendung des Datumsformats. Bei weiteren Untersuchungen stellten wir fest, dass der serialisierte Byte-Stream "Datum" 6 Byte beträgt, während der LocalDateTime-Stream 256 Byte beträgt. Es erhöht auch die Kosten der Netzwerkbandbreite für die Übertragung. Die in Java integrierte Serialisierungslösung weist einen leichten Rückgang auf, macht jedoch keinen wesentlichen Unterschied.

Benchmark                         Mode  Cnt        Score   Error  Units
DateBenchmark.date_Hessian       thrpt       2084363.861          ops/s
DateBenchmark.localDate_Hessian  thrpt         17827.662          ops/s
DateBenchmark.instant_Hessian    thrpt         22492.539          ops/s
DateBenchmark.instant_Java       thrpt       1484884.452          ops/s
DateBenchmark.date_Java          thrpt       1500580.192          ops/s
DateBenchmark.localDate_Java     thrpt       1389041.578          ops/s

Problemanalyse

Unsere Analyse ist wie folgt. Das Datum ist eine von acht primitiven Arten der Serialisierung hessischer Objekte.

image.png

Zweitens musste Instant sowohl für die Serialisierung als auch für die Deserialisierung "Class.forName" durchlaufen, was zu einem starken Rückgang des Durchsatzes und der Antwortzeit führte. Daher hat Date einen Vorteil.

image.png

Letzter Eindruck

Ich habe festgestellt, dass Sie Hessisch aktualisieren und optimieren können, indem Sie com.alibaba.com.caucho.hessian.io.Serializer in einer Klasse wie Instant über eine Erweiterung implementieren und in der SerializerFactory registrieren, also in diesem Artikel Sie können das angesprochene Problem lösen. Es wird jedoch Kompatibilitätsprobleme mit früheren und zukünftigen Versionen geben. Dies ist ein ernstes Problem. Alibabas ziemlich komplexe Abhängigkeiten machen dies unmöglich. Angesichts dieses Problems können wir nur empfehlen, Datum als bevorzugtes Zeitattribut für die TO-Klasse zu verwenden.

Technisch gesehen ist das RPC-Protokoll von HSF ein Protokoll auf Sitzungsebene, und die Versionserkennung wird auch hier durchgeführt. Die Präsentationsschicht der Servicedaten ist jedoch in einem selbstbeschreibenden Serialisierungsframework wie Hessisch implementiert und weist keine Versionserkennung auf. Daher ist ein Upgrade sehr schwierig.

Recommended Posts

Leistungsprobleme bei Serialisierungsvorgängen im Zusammenhang mit der Verwendung von LocalDateTime
Stellen Sie die Zeit von LocalDateTime auf eine bestimmte Zeit ein
Ausgabe der Verwendung der Slice-Methode
Java: Verwenden Sie Stream, um den Inhalt einer Sammlung zu sortieren
Verwendung der link_to-Methode
Verwendung der include? -Methode
Verwendung der Methode form_with
[Java Edition] Geschichte der Serialisierung
Verwendung der Wrapper-Klasse
Verwendung von setDefaultCloseOperation () von JFrame
Ich habe versucht, den CPU-Kern mit Ruby voll auszunutzen
Ich möchte, dass Sie Enum # name () für den Schlüssel von SharedPreference verwenden