Sehen Sie die Architektur? Und ich sehe nicht, aber sie ist

In der Entwicklung von hh.ru heute etwa 150 Menschen. Wir haben viele interessante Teams, und jedes leistet einen bedeutenden Beitrag. Aber in diesem Artikel werde ich nur über einen von ihnen erzählen.


Weil ich ihr Teamleiter bin. Dafür gibt es mehrere Gründe:

  • oft verstehen die Kandidaten nicht, was wir tun;
  • Manchmal wissen dies sogar Mitarbeiter im Unternehmen nicht, weil unser Team keinen Produktmanager, keinen eigenen Geschäftsfunktionsbereich und keine Liste der von uns unterstützten Dienstleistungen hat.
  • unsere Verdienste bleiben meistens im Schatten;
  • am Ende, "wenn du es herausfinden willst, versuche es jemandem zu erklären" :)

Deshalb werde ich versuchen, mit verständlichen Beispielen zu verstehen, woraus unsere Arbeit tatsächlich besteht.

Beginnen wir mit dem Allgemeinsten, dh mit Prioritäten gibt es zwei davon:

  • Systemunterstützung für die Zuverlässigkeit und Ausfallsicherheit unserer Plattform. Hier lohnt es sich, auf das Wort „System“ zu achten - es bedeutet, dass wir keine spezifischen Leistungsmängel beheben, sondern allgemeine Regeln und Muster entwickeln, diese in Frameworks, automatischen Überprüfungen usw. beheben, damit es für alle funktioniert.
  • Entwicklungsschwerpunkt auf Geschäftslogik. Das heißt, je weniger ein Entwickler daran denkt, Zuverlässigkeit, Architektur usw. zu unterstützen. - umso besser. Es ist klar, dass es ziemlich schädlich ist, Kollegen vollständig von solchen Gedanken zu befreien, aber ein vernünftiges Gleichgewicht aufrechtzuerhalten, ist sinnvoll.

Ausgehend von diesen Prioritäten folgen die Hauptrichtungen unserer Arbeit:

0. Unterstützung und Entwicklung der Architektur


hh.ru ist 5-6.000 U / min von Benutzern, wobei der Spitzenwert 10.000 erreicht, die um eine Größenordnung wachsen und Backends erreichen. Dies sind mehr als 1.500 Instanzen, die ungefähr 150 Dienste in 3 DC drehen. Also ja, zuallererst sind dies die sehr verzweigten Schemata mit Quadraten, Banken und Pfeilen: Wer geht wohin, wo was sollte sein. Natürlich zeichnen wir keine Schemata - wir decken die Anforderungen mit Automatisierung, Protokollierung und Überwachung ab, aber wir haben unsere Schüler beispielsweise vor solchen Dingen erschreckt:



Wir sind wirklich dafür verantwortlich, Engpässe und unflexible Lösungen in der Architektur zu finden, zu beseitigen und entsprechend den Anforderungen zu entwickeln.

Ich werde ein Beispiel geben:

hh.ru hat weit vom ersten Jahr an gearbeitet, und sobald es eine gute Idee schien, eine separate Maschine für die Ausführung von Hintergrundaufgaben nach einem Zeitplan zu haben, können Sie mehr Ressourcen dafür zuweisen, und es werden keine Rennen darauf stattfinden. Aber was haben wir am Ende:

  • Fehlerstelle für alle Aufgaben
  • einzigartige Konfiguration nur in prod reproduziert
  • Aufgaben, deren Logik für einen dedizierten Start auf einer separaten, fett gedruckten Maschine ausgelegt ist und nicht horizontal skaliert

Als wir das verstanden haben, haben wir sichergestellt, dass wir alle Mittel haben, um die Kronenaufgaben auf allgemeine Instanzen zu übertragen, und eine große Aufgabe in der Kategorie der technischen Schulden begonnen - jetzt, da die Zeit für die Rückzahlung von Schulden gekommen ist, beseitigen Kollegen dieses Problem allmählich.

1. Standardisierung von Krücken


Zuallererst sind dies unsere Rahmenbedingungen und Werkzeuge für die schnelle Entwicklung von Dienstleistungen: Schrauben und Muttern und Frontik . Wie auch immer, jclient und viele andere Bibliotheken, die auf unserem Github geöffnet wurden, kamen von der Idee, dass es sinnvoll ist, die Erfahrung mit dem Betrieb verschiedener Technologien zusammenzufassen. Dies ermöglicht es uns, die Einschränkungen, Muster von Design und Verhalten zu kultivieren, die wir im Kampf ausgearbeitet haben, und wir betrachten sie als die am besten geeigneten, verständlichen und zuverlässigsten.

Neben solchen offensichtlichen Beispielen für Standardisierung gibt es solche, bei denen es sinnvoll ist, bestimmte Lösungen zu verallgemeinern.

Irgendwann mussten wir zum Beispiel regelmäßig (mindestens einmal) Nachrichten an rabbitmq senden. Die Aufgaben wurden wiederholt durch selbstgeschriebene Warteschlangen an der Basis gelöst, und dba sagte immer wieder, wie sehr die Warteschlangen an der Basis stark geliebt wurden, insbesondere geladene. Am Ende wurde klar, dass hier eine Standardlösung benötigt wurde, die für dba akzeptabel ist, eine zuverlässige Lieferung gewährleistet und für die Entwicklung bequem ist - so haben wir unsere Bibliothek für die Integration von pgq und rabbitmq geschrieben. Jetzt besteht eine hohe Wahrscheinlichkeit, dass wir pgq auch in Verbindung mit kafka verwenden.

1.0. Bugs


Fehler sind auch global. Zum Beispiel haben wir irgendwann herausgefunden, dass unser Python-Framework in jedem Worker-Prozess beim Konsul registriert ist, und dies sogar, bevor die Anwendung bereit ist, Anforderungen anzunehmen. Nach dem Fixieren im Framework erreichen Änderungen nach und nach alle Dienste, sobald sie aktualisiert werden.

Ich habe über einen weiteren allgemeinen Fehler im Zusammenhang mit JVM-Einstellungen in der Demo-Phase Jpoint 2019 gesprochen .

Und was zum Beispiel mit einem Fehler zu tun hat, der einmal pro Woche in einer der Instanzen reproduziert wird, wird mit einem Neustart behandelt, aber weder durch Laden noch durch Kunststoffe reproduziert?
, java- . nuts-and-bolts:

"qtp1778300121-22" #22 prio=5 os_prio=0 cpu=797.67ms elapsed=11737.06s tid=0x00007f5890139000 nid=0x26 waiting for monitor entry [0x00007f58922c7000]
java.lang.Thread.State: BLOCKED (on object monitor)
at ch.qos.logback.core.AppenderBase.doAppend(AppenderBase.java:63)
- waiting to lock <0x00000000e86acad0> (a ru.hh.nab.logging.HhSyslogAppender)
at ru.hh.nab.logging.HhMultiAppender.doAppend(HhMultiAppender.java:47)
at ru.hh.nab.logging.HhMultiAppender.doAppend(HhMultiAppender.java:21)
at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:51)


:

"qtp1778300121-22" #22 prio=5 os_prio=0 cpu=5718.81ms elapsed=7767.14s tid=0x00007f1537dba000 nid=0x24 waiting for monitor entry [0x00007f153d2b9000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(java.base@11.0.4/ConcurrentHashMap.java:1723)
- waiting to lock <0x00000000e976a668> (a java.util.concurrent.ConcurrentHashMap$Node)
at org.springframework.beans.factory.BeanFactoryUtils.transformedBeanName(BeanFactoryUtils.java:86)


jackson:

"qtp1778300121-23" #23 prio=5 os_prio=0 cpu=494.19ms elapsed=7234.32s tid=0x00007f6c01218800 nid=0x25 waiting for monitor entry [0x00007f6c07cfa000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.glassfish.jersey.jackson.internal.jackson.jaxrs.base.ProviderBase._endpointForWriting(ProviderBase.java:711)
- waiting to lock <0x00000000e9f94c38> (a org.glassfish.jersey.jackson.internal.jackson.jaxrs.util.LRUMap)
at org.glassfish.jersey.jackson.internal.jackson.jaxrs.base.ProviderBase.writeTo(ProviderBase.java:588)


Code Cache:



java . java, , - . , .

1.1. Allgemeine Entscheidungen


Manchmal ist es möglich, Standardlösungen zu finden, bevor dies zu einem ernsthaften Problem wird. Als Beispiele können wir die Aufgabe der Verarbeitung von Protokollen anführen, über die unser Vlad Senin am selben Punkt 2019 gesprochen hat , oder die Aufgabe, Zeitüberschreitungen in unserem http-Client zu verwalten.

Dies bedeutet, dass es nützlich ist, ein angemessenes Zeitlimit nicht auf der Clientseite, sondern auf der Serverseite zu bestimmen. Für den Server liegen Daten darüber vor, wie schnell er auf seine Endpunkte reagiert. Jetzt unterstützt unser Kunde eine Zeitüberschreitung für den Service. Es ist jedoch offensichtlich, dass nicht alle Service-Endpunkte gleich reagieren - einige länger, andere schneller. Ich möchte verschiedene Timeouts verwenden können. Ansonsten ergibt sich eine ähnliche Situation:



Bisher treten solche Situationen nur unter Stresstests auf, aber ich möchte sie lösen, bevor dies zu einem Problem wird.

1.2. Offene Punkte


Aber nicht alle Probleme werden durch einige wichtige Stellen und komplizierte manuelle Prozesse erklärt. Darüber hinaus werde ich einige Beispiele für Themen nennen, die ebenfalls in den Bereich unserer Prioritäten fallen, aber gleichzeitig viel weniger deterministisch sind. Daher werde ich nur die Anfangsdaten beschreiben, und wir können die Lösungen auf Wunsch in den Kommentaren diskutieren.

Das erste Beispiel: Jetzt wird klar, dass es ein Problem gibt, unsere Dienstleistungen untereinander zu integrieren. Die Integration beispielsweise eines Site-Handles in eine API kann länger dauern als die ursprüngliche Entwicklung.

Ein anderes, wahrscheinlich vielen bekanntes Beispiel für ein ähnliches Problem ist das Sägen eines Monolithen. Jeder versteht, dass ein Monolith, der mit einer großen Anzahl von Vermächtnissen bewachsen ist, die Entwicklung und den Betrieb erschwert. Aber wer kann wie viel sagen? Lohnt es sich, andere Aufgaben der technischen Verschuldung zugunsten des Sägens zu opfern, von denen jedes Stück einzeln einen verschwindend geringen Wert hat?

Das Ausmaß dieser und ähnlicher Probleme ist so groß, dass man manchmal weit über den technischen Rahmen hinausgehen und in völlig neue Bereiche des Arbeitsprozesses eintauchen muss, um sie zu lösen. Dies ist einerseits beängstigend, bietet aber andererseits unglaubliche Entscheidungsfreiheit.

2. Wie wir arbeiten


Die Geschichte über die Richtungen unserer Arbeit wird unvollständig sein, ohne zu beschreiben, wie wir mit all dem arbeiten.

Was hat mich anfangs dazu bewegt, in „Architektur“ zu arbeiten, und was motiviert uns alle: Wir arbeiten wirklich für Qualität.

Und bevor die Steine ​​auf mich losfliegen, werde ich versuchen zu erklären, was ich meine. Ich glaube, dass kein Entwickler absichtlich auf Qualität punktet. Der Punkt liegt in der technischen Verschuldung: Wenn es sich um einen Teil der Geschäftslogik handelt, dessen Wiederverwendung nicht geplant ist, wird die Verschuldung einer nicht so idealen Lösung mit der Zeit, wenn überhaupt, langsam zunehmen.

Auf diese Weise können Sie Ihren Perfektionismus etwas abkühlen - starten Sie eine Schuldenaufgabe und fahren Sie mit der nächsten Iteration fort. Wenn es sich jedoch um ein Framework oder ein globales Tool zur Konfigurationsvorbereitung handelt, das in Hunderten von Anwendungen verwendet wird und bestimmte Entwurfs- oder Benennungsmuster konsolidiert, kann die Rate des Schuldenwachstums aufgrund seiner erfolglosen Entscheidung Gewinne überhaupt blockieren. Es ist klar, dass es Situationen gibt, in denen selbst die beste Lösung Schwachstellen aufdeckt, wenn sie verwendet werden, aber dies kommt nicht oft vor ...

Gegen Ende möchte ich über die Hindernisse sprechen, die sich noch auf unserem Weg ergeben. Ohne dies wäre eine Geschichte über unsere Arbeit unehrlich. Damit.

2.0. Aufgaben zur Bewertung von Schwierigkeiten


Wie ich oben sagte, können wir den positiven Effekt nicht für alle Aufgaben bewerten. Um wie viel verkürzt sich die Release-Zeit für Aufgaben, wenn für eine Funktion eine "Boxed" -Lösung herauskommt? Welcher der beiden problematischen Codeabschnitte sollte zuerst überarbeitet werden? Um ein angemessenes System zur Bewertung von Aufgaben zu entwickeln, haben wir uns mehrere Monate lang mehrmals pro Woche getroffen. Dies ist jedoch ein Thema für einen separaten Beitrag.

2.1. Kollektiven Unbewussten


Etwas für 150 Personen zu koordinieren ist keine leichte Aufgabe. Unsere sehr dezentrale Organisationsstruktur manifestiert sich meistens mit ihren besten Seiten, aber für „Architektur“ ist sie manchmal ein ernstes Hindernis. Es gibt nur sehr wenige Vereinbarungen, zu denen eine Einigung erzielt werden kann, noch weniger, deren Einhaltung dann überwacht werden kann.

Und alle Änderungen müssen reibungslos gerollt werden. Der Dienst wird möglicherweise monatelang nicht aktualisiert, aber es gibt immer noch einen Monolithen ... Nun, ziemlich traurig.

Also haben wir geredet


Ich hoffe, dass ich nach meiner Geschichte ein wenig geklärt habe, was "Architektur" in hh.ru tut. Und wenn ich es geschafft habe, Ihr Interesse an unserer Arbeit zu wecken, ist das im Allgemeinen fantastisch. Darüber hinaus ist gerade eine Stelle in unserem Team offen . Wir werden uns sehr über frische Ideen freuen, die uns helfen, unsere verborgenen Blicke, aber so wichtige Siege zu erreichen.

ps Das ursprüngliche KDPV ist, wie sich herausstellt, eine Illustration dieses Mannes . Ich hoffe, er ist nicht gegen die Verwendung seiner Bilder als KDPV

All Articles