Die Welt hat sich verändert. Ich fühle es im Wasser, sehe es im Boden, fühle es in der Luft. Alles, was einmal existierte, ist verschwunden, und es gibt keine mehr, die sich daran erinnern.Aus dem Film „Der Herr der Ringe: Die Gefährten des Rings“Es gibt 100500 Artikel und Berichte im Internet zum Thema „Wie wir einen Monolithen gesehen haben“, und ich habe keine Lust, einen weiteren zu schreiben. Ich habe versucht, ein wenig weiter zu gehen und zu erzählen, wie technologische Änderungen zum Erscheinen eines völlig neuen Produkts geführt haben (Spoiler: Wir haben die Box geschrieben und die Plattform geschrieben). Der Artikel ist größtenteils eine Rezension ohne technische Details. Details werden später kommen.
Es geht um die Site des Control Panels und den Vepp-Server. Dies ist ein ISP-System-Produkt, bei dem ich die Entwicklung leite. Lesen Sie hier
in einem anderen Artikel mehr über die Funktionen des neuen Panels - nur über Technologie. Aber zuerst wie immer ein bisschen Geschichte.
Teil 1. Es ist notwendig, etwas zu ändern
Unser Unternehmen schreibt seit mehr als 15 Jahren Software für die Automatisierung von Hosting-Diensten. In dieser Zeit haben sich mehrere Generationen unserer Produkte verändert. Als wir vom zweiten zum vierten wechselten, wechselten wir Perl zu C ++ und begannen mit dem kostenlosen Verkauf unserer Software ... Als wir vom vierten zum fünften wechselten, wechselten wir im Streben nach Geschwindigkeit von einer Single-Threaded-Anwendung zu Multithreading (von einem Monolithen, der alle unsere Produkte enthält, zu Rahmen).
Aber nicht nur wir haben uns verändert, auch unsere Kunden und Konkurrenten haben sich verändert. Wenn der Websitebesitzer vor 10 bis 15 Jahren technisch versiert war (andere interessierten sich nur schwach für das Internet), kann es sich nun um eine Person handeln, die in keiner Weise mit der IT verbunden ist. Es gibt viele konkurrierende Lösungen. Unter solchen Bedingungen reicht es nicht aus, ein Produkt einfach zu bearbeiten. Es ist einfach und angenehm zu bedienen.
Heroisches Redesign
Diese Veränderung ist in jeder Hinsicht am auffälligsten geworden. Während dieser ganzen Zeit ist die Schnittstelle unserer Produkte praktisch unverändert und einheitlich geblieben. Wir haben bereits separat darüber geschrieben - eine Ansicht von der UX. In der fünften Produktgeneration definierte die API das Erscheinungsbild von Formularen und Listen. Dies ermöglichte es einerseits, viele Dinge zu implementieren, ohne Frontend-Entwickler einzubeziehen, andererseits führte dies zu sehr komplexen komplexen Aufrufen, die manchmal den größten Teil des Systems betrafen, und schränkte die Möglichkeit zum Ändern der Schnittstelle stark ein. Schließlich ist jede Änderung zwangsläufig eine Änderung der API. Und das war's, hallo zu den Integrationen!
Beispiel: Das Erstellen eines Benutzers in ISPmanager kann auch zum Erstellen eines FTP-Benutzers, einer Mail-Domäne, eines Postfachs, eines DNS-Eintrags oder einer Site führen. All dies erfolgt atomar und blockiert daher die Änderungen in den aufgelisteten Komponenten, bis der Vorgang abgeschlossen ist.In der neuen API haben wir auf kleine und einfache atomare Operationen umgestellt, und Frontend-Entwickler hatten komplexe komplexe Aktionen. Auf diese Weise können Sie eine komplexe Schnittstelle implementieren und ändern, ohne die Kern-API zu beeinträchtigen und ohne die Integration zu unterbrechen.
Für Frontend-Entwickler haben wir einen Mechanismus zur Ausführung von Stapelabfragen implementiert, mit dem im Fehlerfall umgekehrte Aktionen ausgeführt werden können. Wie die Praxis zeigt, sind komplexe Abfragen in den meisten Fällen Anforderungen zum Erstellen von Objekten, und die Erstellung kann ganz einfach durch Löschen abgebrochen werden.Reduzieren Sie die Antwortzeit und sofortige Benachrichtigungen
Wir haben lange Änderungswünsche abgelehnt. Frühere Versionen unserer Produkte können lange Zeit hängen bleiben und versuchen, eine Benutzeranforderung zu erfüllen. Wir haben beschlossen, dass es für jede Aktion schwieriger ist, die Daten in der Datenbank trivial zu ändern. Wir werden eine Aufgabe im System erstellen und so schnell wie möglich auf den Kunden reagieren, damit er weiterarbeiten kann und sich nicht mit dem endlosen Ladevorgang befasst.
Aber was ist, wenn Sie das Ergebnis brauchen, wie heißt es hier und jetzt? Ich denke, viele Leute sind mit der Situation vertraut, wenn Sie die Seite immer wieder neu laden, in der Hoffnung, dass der Vorgang bald endet.
In der neuen Produktgeneration verwenden wir Websocket für die sofortige Zustellung von Veranstaltungen.
Die erste Implementierung verwendete Longpoll, aber Frontend-Entwickler waren mit diesem Ansatz nicht zufrieden.Interne HTTP-Kommunikation
HTTP als Transport hat gewonnen. Jetzt ist in jeder Sprache ein HTTP-Server in Sekunden implementiert (wenn Sie googeln, dann in Minuten). Selbst lokal ist es einfacher, eine HTTP-Anfrage zu erstellen, als Ihr Protokoll zu blockieren.
In der vorherigen Generation waren Erweiterungen (Plugins) Anwendungen, die bei Bedarf als CGI gestartet wurden. Aber um eine langlebige Erweiterung zu schreiben, musste ich mich sehr bemühen: Schreiben Sie ein Plug-In in C ++ und erstellen Sie es bei jedem Produktupdate neu.
Daher haben wir in der sechsten Generation auf interne Interaktion über HTTP umgestellt, und die Erweiterungen wurden tatsächlich zu kleinen WEB-Servern.
Neue (nicht ganz REST) API
In früheren Produktgenerationen haben wir alle Parameter über GET oder POST übergeben. Wenn es keine besonderen Probleme mit GET gibt - seine Größe ist klein -, gab es im Fall von POST keine Möglichkeit, den Zugriff zu überprüfen oder die Anforderung umzuleiten, bis sie vollständig gelesen wurde.
Stellen Sie sich vor, wie traurig es ist, ein paar hundert Megabyte oder Gigabyte zu akzeptieren und dann festzustellen, dass sie von einem nicht autorisierten Benutzer gegossen wurden oder dass sie jetzt auf diesen Server übertragen werden müssen!Jetzt wird der Name der Funktion in der URI und die Autorisierung ausschließlich in den Headern übergeben. Auf diese Weise können Sie einen Teil der Überprüfungen durchführen, bevor Sie den Anforderungshauptteil lesen.
Darüber hinaus sind API-Funktionen einfacher geworden. Ja, jetzt garantieren wir nicht die Atomizität der Erstellung eines Benutzers, einer E-Mail, einer Website und dergleichen. Wir bieten jedoch die Möglichkeit, diese Operationen nach Bedarf zu kombinieren.
Wir haben die Möglichkeit der Stapelabfrageausführung implementiert. Tatsächlich ist dies ein separater Dienst, der eine Liste von Anforderungen akzeptiert und diese nacheinander ausführt. Er kann im Fehlerfall auch bereits abgeschlossene Vorgänge rückgängig machen.
Es lebe SSH!
Eine weitere Entscheidung, die wir aufgrund unserer bisherigen Erfahrungen getroffen haben, besteht darin, nur über SSH mit dem Server zu arbeiten (auch wenn es sich um einen lokalen Server handelt). Anfangs haben wir mit dem lokalen Server in VMmanager und ISPmanager gearbeitet, und erst dann konnten wir weitere Remote-Server hinzufügen. Dies führte dazu, dass zwei Implementierungen unterstützt werden mussten.
Und als wir uns weigerten, mit dem lokalen Server zu arbeiten, verschwanden die letzten Gründe für die Verwendung der nativen Bibliotheken des Benutzerbetriebssystems. Mit ihnen wurden wir seit der Gründung des Unternehmens gequält. Nein, native Bibliotheken haben ihre Vorteile, aber es gibt noch weitere Nachteile.
Ein absolutes Plus ist der geringere Verbrauch von Festplatte und Speicher. Für die Arbeit in VDS kann dies sehr bedeutend sein. Von den Nachteilen - die Verwendung einer Bibliothek, deren Version Sie nicht steuern, kann zu unerwarteten Ergebnissen führen, was die Belastung sowohl für die Entwicklung als auch für das Testen erheblich erhöht. Ein weiterer Nachteil ist die Unfähigkeit, die neuesten Versionen von Bibliotheken und modernem C ++ zu verwenden (unter CentOS 6 wird beispielsweise sogar C ++ 11 nicht vollständig unterstützt).Alte Gewohnheiten
Wir haben unsere Ansätze geändert und auf neue Technologien umgestellt und weiterhin auf die alte Art und Weise gehandelt. Dies führte zu Schwierigkeiten.
Das Hype-Thema mit Microservices ist uns nicht entgangen. Wir haben uns auch entschlossen, die Anwendung in separate Servicekomponenten aufzuteilen. Dies ermöglichte es, die Kontrolle über die Interaktion zu verschärfen und einzelne Teile der Anwendung zu testen. Und um die Interaktion noch genauer zu steuern, haben wir sie in Behältern angeordnet, die jedoch immer zu einem Stapel zusammengefasst werden konnten.
In einer monolithischen Anwendung können Sie problemlos auf nahezu alle Daten zugreifen. Aber selbst wenn Sie das Produkt in mehrere Anwendungen aufteilen und in der Nähe lassen, können sie als lebende Anwendungen Links bilden. Zum Beispiel in Form von gemeinsam genutzten Dateien oder direkten Anfragen aneinander.
Der Wechsel zu Microservices war nicht einfach. Das alte Muster, „eine Bibliothek zu schreiben und zu verbinden, wo immer es nötig ist“, verfolgt uns schon seit geraumer Zeit. Zum Beispiel haben wir einen Service, der für die Durchführung „langer“ Operationen verantwortlich ist. Ursprünglich wurde es als Bibliothek implementiert, die mit der Anwendung verbunden ist, die es benötigt.
Eine andere Gewohnheit kann wie folgt beschrieben werden: Warum einen anderen Dienst schreiben, wenn Sie diesen bestehenden lehren können? Das erste, was wir von unserem Monolithen abgesägt haben, ist der Autorisierungsmechanismus. Aber dann schien die Versuchung, alle gängigen Komponenten in diesen Service zu schieben, wie in COREmanager (dem Grundgerüst für Produkte der fünften Generation).
Teil 2. Kombinieren der inkompatiblen
Lese- und Schreibanforderungen wurden zunächst in einem einzigen Prozess ausgeführt. Normalerweise blockieren Schreibanforderungen Anforderungen, aber sie sind sehr schnell: Ich habe in die Datenbank geschrieben, eine Aufgabe erstellt und beantwortet. Bei einer Leseanfrage ist die Geschichte anders. Es ist schwierig, eine Aufgabe darauf zu erstellen. Es kann eine ziemlich umfangreiche Antwort erzeugen, und was ist mit dieser Antwort zu tun, wenn der Client nicht danach zurückkehrt? Wie viel soll es aufbewahren? Gleichzeitig ist die Verarbeitung von Leseanfragen perfekt parallelisiert. Diese Unterschiede führten zu Problemen beim Neustart solcher Prozesse. Ihre Lebenszyklen sind einfach nicht kompatibel!
Wir haben die Anwendung in zwei Teile geteilt: Lesen und Schreiben. Es wurde zwar bald klar, dass dies aus entwicklungspolitischer Sicht nicht sehr praktisch ist. Lesen Sie die Liste, die Sie an einem Ort erstellen, und bearbeiten Sie sie an einem anderen. Und hier die Hauptsache - vergessen Sie nicht, die zweite zu reparieren, wenn Sie die erste ändern. Ja, und das Wechseln zwischen Dateien ist zumindest ärgerlich. Daher kamen wir zu einer Anwendung, die in zwei Modi ausgeführt wird: Lesen und Schreiben.
Die Vorgängergeneration unserer Produkte verwendete in großem Umfang Fäden. Aber wie die Praxis gezeigt hat, haben sie uns nicht viel gerettet. Aufgrund der vielen Sperren überstieg die Belastung der CPU selten 100%. Das Aufkommen einer großen Anzahl separater, relativ schneller Dienste hat es ermöglicht, das Multithreading zugunsten von asynchroner Arbeit und Single-Threaded-Arbeit aufzugeben.
Während des Entwicklungsprozesses haben wir versucht, Streams zusammen mit Asynchronität zu verwenden (boost :: Asio erlaubt dies). Dieser Ansatz bringt jedoch höchstwahrscheinlich alle Mängel beider Ansätze in Ihr Projekt, als sichtbare Vorteile bieten: Sie müssen die Notwendigkeit der Kontrolle beim Zugriff auf gemeinsam genutzte Objekte und die Schwierigkeit beim Schreiben von asynchronem Code kombinieren.Teil 3. Wie wir die Box geschrieben haben und die Plattform geschrieben haben
Alle Dienste sind in Containern angeordnet und arbeiten remote mit dem Client-Server. Und warum dann die Anwendung auf den Client-Server stellen? Das ist die Frage, die ich dem Management gestellt habe, als es an der Zeit war, das resultierende Produkt für die Installation auf dem Server zu verpacken.
Was ist eine Plattform? Zunächst haben wir SaaS bereitgestellt, einen Dienst, der auf unseren Servern ausgeführt wird und mit dem Sie Ihren Server konfigurieren können. Wenn Sie ein Server-Control-Panel verwendet und selbst gekauft haben, ist dies die Lösung für Sie. Aber es passt nicht zu Anbietern: Sie sind nicht bereit, einem Drittunternehmen Zugriff auf die Server ihrer Kunden zu gewähren, und ich verstehe sie sehr gut. Dies wirft Fragen sowohl zur Sicherheit als auch zur Fehlertoleranz auf. Aus diesem Grund haben wir beschlossen, ihnen unser gesamtes SaaS zur Verfügung zu stellen, damit sie es zu Hause bereitstellen können. Es ist wie bei Amazon, das Sie in Ihrem eigenen Rechenzentrum ausführen und mit Ihrem Abrechnungssystem verbinden können. Wir haben diese Lösung als Plattform bezeichnet.
Der erste Einsatz verlief nicht sehr reibungslos. Für jeden aktiven Benutzer haben wir einen separaten Container erstellt. Docker-Container steigen schnell an, aber die Serviceerkennung funktioniert nicht sofort: Es ist nicht beabsichtigt, Container innerhalb einer Sekunde dynamisch anzuheben / zu stoppen. Und vom Moment des Erhöhens bis zum Moment, in dem der Dienst genutzt werden kann, vergingen manchmal Minuten !!!Ich habe bereits geschrieben, dass sich der Hosting-Benutzer in den letzten zehn Jahren stark verändert hat. Stellen Sie sich nun vor: Es kauft ein Hosting von Ihnen - und erhält Zugriff auf die Shell. WTF?!?! Um es zu verwenden, muss er zuerst einen SSH-Client finden (unter Windows kann dies zu einem Problem werden - standardmäßig gibt es keinen Client, ich schweige im Allgemeinen über mobile Clients).
Nachdem er noch in die Konsole gelangen konnte, muss er das Panel installieren. Und dieser Vorgang ist auch nicht schnell. Und wenn etwas schief geht? Beispielsweise kann RosKomNadzor die Server blockieren, von denen Pakete für Ihr Betriebssystem heruntergeladen werden. Mit solchen Fehlern wird der Benutzer von Angesicht zu Angesicht gelassen.

Sie können argumentieren, dass der Benutzer in den meisten Fällen das vom Hoster bereits installierte Panel erhält und das oben Gesagte nicht für ihn gilt. Möglicherweise. Das auf dem Server ausgeführte Panel verbraucht jedoch die Ressourcen, für die Sie bezahlt haben (beansprucht Speicherplatz, verbraucht Ihren Prozessor und Speicher). Die Leistung hängt direkt von der Leistung des Servers ab (der Server ist abgestürzt - das Panel ist abgestürzt).
Es mag immer noch diejenigen geben, die keine Panels verwenden und denken: Das geht mich nichts an. Aber vielleicht steht auf Ihrem Server, wenn Sie einen haben, noch eine Art Panel und frisst Ressourcen, aber Sie verwenden es einfach nicht?
"Es ist sogar wunderbar, dass Sie uns helfen, Ressourcen zu verkaufen", sagen russische Gastgeber. Andere fügen hinzu: „Warum verwenden wir unsere Ressourcen für die Bereitstellung einer Plattform, die mehr als ein eigenständiges Panel benötigt?“
Auf diese Frage gibt es mehrere Antworten.
- Die Servicequalität wird verbessert: Sie können die Panel-Version steuern - aktualisieren Sie sie schnell, wenn neue Funktionen angezeigt werden oder Fehler erkannt werden. Sie können Aktien direkt im Panel ankündigen.
- Auf Infrastrukturskala sparen Sie Festplatte, Speicher und einen Prozessor, da einige Prozesse nur für aktive Benutzer gestartet werden und andere viele Clients gleichzeitig bedienen.
- Der Support muss nicht analysieren, ob das Verhalten ein Merkmal einer bestimmten Version des Panels oder ein Fehler ist. Das spart Zeit.
Viele weitere unserer Kunden kauften Lizenzen in Paketen, jonglierten dann mit ihnen und verkauften sie an ihre Kunden weiter. Es besteht im Prinzip keine Notwendigkeit mehr, sinnlose Arbeit zu leisten. Immerhin ist dies jetzt ein Produkt.
Darüber hinaus hatten wir die Möglichkeit, umfangreiche Lösungen zu verwenden, die zuvor unzugängliche Funktionen bieten. Zum Abrufen von Screenshots einer Site muss beispielsweise ein kopfloses Chrom gestartet werden. Ich glaube nicht, dass der Benutzer sehr glücklich sein wird, wenn ihm aufgrund einer solchen Operation der Speicher ausgeht und er sich selbst erschießt, beispielsweise MySQL.
Abschließend möchte ich festhalten, dass wir aus den Erfahrungen anderer lernen und unsere eigenen aktiv entwickeln. Protokollierung, Docker, Serviceerkennung, alle Arten von Verzögerungen, Wiederholungsversuchen und Warteschlangen ... Jetzt können Sie sich nicht mehr an alles erinnern, was Sie beherrschen oder neu erfinden mussten. All dies erleichtert die Entwicklung nicht, eröffnet aber neue Möglichkeiten und macht unsere Arbeit spannender.
Die Geschichte ist noch nicht vorbei, aber was passiert ist, kann
auf der Vepp-Website eingesehen werden .