In diesem Artikel werde ich die Verwendung des Go-Kits beschreiben, einer Reihe von Tools und Bibliotheken zum Erstellen von Microservices unter Go. Dieser Artikel ist eine Einführung in das Go-Kit. Der erste Teil meines Blogs, der Quellcode für die Beispiele, ist hier verfügbar.
Go wird zunehmend für die Entwicklung moderner verteilter Systeme ausgewählt. Wenn Sie ein Cloud-basiertes verteiltes System entwickeln, müssen Sie möglicherweise verschiedene spezifische Funktionen in Ihren Diensten unterstützen, z . B .: Verschiedene Transportprotokolle ( usw., übersetzt HTTP, gRPC usw. ) und Nachrichtenkodierungsformate für diese, RPC-Zuverlässigkeit, Protokollierung , Ablaufverfolgung, Metriken und Profilerstellung, Unterbrechen von Anforderungen, Begrenzen der Anzahl von Anforderungen, Integration in die Infrastruktur und sogar Beschreiben der Architektur. Go ist aufgrund seiner Einfachheit und seiner „No Magic“ -Ansätze eine beliebte Sprache. Daher eignen sich Go-Pakete, beispielsweise eine Standardbibliothek, bereits besser für die Entwicklung verteilter Systeme als die Verwendung eines vollwertigen Frameworks mit viel „Magic under the Hood“. Persönlich habe ich [ ca. trans. Shiju Varghese ] Ich unterstütze die Verwendung vollwertiger Frameworks nicht, ich bevorzuge Bibliotheken, die dem Entwickler mehr Freiheit geben. Das Go-Kit füllte die Lücke im Go-Ökosystem und ermöglichte die Verwendung einer Reihe von Bibliotheken und Paketen beim Erstellen von Microservices, die wiederum die Verwendung guter Prinzipien für das Entwerfen einzelner Dienste in verteilten Systemen ermöglichen.

Einführung in das Go-Kit
Das Go-Kit besteht aus einer Reihe von Go-Paketen, mit denen sich auf einfache Weise zuverlässige und unterstützte Microservices erstellen lassen. Das Go-Kit bietet Bibliotheken zum Implementieren verschiedener Komponenten einer transparenten und zuverlässigen Anwendungsarchitektur unter Verwendung von Ebenen wie Protokollierung, Metriken, Ablaufverfolgung, Begrenzung und Unterbrechung von Anforderungen, die zum Ausführen von Microservices auf dem Produkt erforderlich sind. Das Go-Kit ist gut, da es gut implementierte Tools für die Interaktion mit verschiedenen Infrastrukturen, Nachrichtenkodierungsformaten und verschiedenen Transportschichten enthält.
Zusätzlich zu den Bibliotheken für Dienste in Entwicklungsländern bietet und fördert es die Verwendung guter Prinzipien für die Gestaltung der Architektur Ihrer Dienste. Mit dem Go-Kit können Sie die SOLID-Prinzipien, den von Alistair Cockburn vorgeschlagenen themenorientierten Ansatz (DDD) und die hexagonale Architektur oder einen anderen Ansatz aus den von Jeffrey Palermo als „ Zwiebelarchitektur “ und von Robert C. Martin als „ saubere Architektur “ bekannten Architekturprinzipien einhalten. Obwohl das Go-Kit als Paket für die Entwicklung von Microservices konzipiert wurde, eignet es sich auch für die Entwicklung eleganter Monolithen.
Architektur Go Kit
Die drei Hauptebenen in der Architektur von Anwendungen, die mit dem Go-Kit entwickelt wurden, sind:
- Transportniveau
- Endpunktebene
- Service Level
Transportniveau
Wenn Sie Microservices für verteilte Systeme schreiben, müssen die darin enthaltenen Dienste häufig über verschiedene Transportprotokolle wie HTTP oder gRPC miteinander kommunizieren oder Pub / Sub-Systeme wie NATS verwenden. Die Transportschicht im Go-Kit ist an ein bestimmtes Transportprotokoll gebunden (im Folgenden: Transport). Das Go-Kit unterstützt verschiedene Transporte für Ihren Dienst, z. B. HTTP, gRPC, NATS, AMQP und Thirft ( ca. Sie können auch Ihren eigenen Transport für Ihr Protokoll entwickeln ). Daher konzentrieren sich Services, die mit dem Go-Kit geschrieben wurden, häufig auf die Implementierung einer bestimmten Geschäftslogik, die nichts über den verwendeten Transport weiß. Sie können verschiedene Transporte für denselben Service verwenden. Beispielsweise kann ein in Go Kit geschriebener Dienst gleichzeitig über HTTP und gRPC Zugriff darauf gewähren.
Endpunkte
Ein Endpunkt oder Endpunkt ist der grundlegende Baustein für Services und Kunden. Im Go-Kit ist das Hauptkommunikationsmuster RPC. Der Endpunkt wird als separate RPC-Methode dargestellt. Jede Dienstmethode im Go-Kit wird in einen Endpunkt konvertiert, sodass Sie im RCP-Stil zwischen Server und Client kommunizieren können. Jeder Endpunkt stellt eine Dienstmethode unter Verwendung der Transportschicht bereit, die wiederum verschiedene Transportprotokolle wie HTTP oder gRPC verwendet. Ein separater Endpunkt kann über mehrere Transporte gleichzeitig aus dem Dienst entfernt werden ( ca. Lane HTTP und gRPC an verschiedenen Ports ).
Dienstleistungen
Geschäftslogik ist in der Serviceschicht implementiert. Mit dem Go-Kit geschriebene Dienste sind als Schnittstellen konzipiert. Die Geschäftslogik in der Serviceschicht enthält den Hauptkern der Geschäftslogik, die nichts über die verwendeten Endpunkte oder ein bestimmtes Transportprotokoll wie HTTP oder gRPC oder über das Codieren oder Decodieren von Anforderungen und Antworten verschiedener Nachrichtentypen wissen muss. Auf diese Weise können Sie bei Diensten, die mit dem Go-Kit geschrieben wurden, eine saubere Architektur einhalten. Jede Servicemethode wird mithilfe eines Adapters in einen Endpunkt konvertiert und mithilfe eines bestimmten Transports außerhalb verfügbar gemacht. Durch die Verwendung einer sauberen Architektur kann eine einzelne Methode mit mehreren Transporten gleichzeitig festgelegt werden.
Beispiele
Schauen wir uns nun die oben beschriebenen Ebenen anhand eines Beispiels einer einfachen Anwendung an.
Geschäftslogik im Service
Die Geschäftslogik im Service wird mithilfe von Schnittstellen entworfen. Wir werden uns ein Beispiel für eine Bestellung im E-Commerce ansehen:
Die Order Service-Schnittstelle funktioniert mit der Order Domain Entity:
Hier implementieren wir die Schnittstelle des Bestellservices:
package implementation import ( "context" "database/sql" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/gofrs/uuid" ordersvc "github.com/shijuvar/gokit-examples/services/order" )
Anfragen und Antworten für RPC-Endpunkte
Dienstmethoden werden als RPC-Endpunkte verfügbar gemacht. Daher müssen wir die Nachrichtentypen ( ca. Per. DTO - Datenübertragungsobjekt ) bestimmen, die zum Senden und Empfangen von Nachrichten über RPC-Endpunkte verwendet werden. Definieren wir nun Strukturen für Anforderungs- und Antworttypen für RPC-Endpunkte im Bestellservice:
Go-Kit-Endpunkte für Servicemethoden wie RPC-Endpunkte
Der Kern unserer Geschäftslogik wird vom Rest des Codes getrennt und in die Serviceschicht eingefügt, die mithilfe von RPC-Endpunkten verfügbar gemacht wird, die die Go-Kit-Abstraktion namens Endpoint
.
So sieht der Endpunkt aus dem Go-Kit aus:
type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
Wie oben erwähnt, stellt der Endpunkt eine separate RPC-Methode dar. Jede Servicemethode wird mithilfe von Adaptern in endpoint.Endpoint
konvertiert. Lassen Sie uns Go-Kit-Endpunkte für Bestelldienstmethoden erstellen:
import ( "context" "github.com/go-kit/kit/endpoint" "github.com/shijuvar/gokit-examples/services/order" )
Der Endpunktadapter akzeptiert die Schnittstelle als Argument für die Eingabe und konvertiert sie in eine Abstraktion des Go-Kit- endpoint.Enpoint
macht jede einzelne Dienstmethode zu einem Endpunkt. Diese Adapterfunktion führt Vergleichs- und Typkonvertierungen für Anforderungen durch, ruft eine Dienstmethode auf und gibt eine Antwortnachricht zurück.
func makeCreateEndpoint(s order.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(CreateRequest) id, err := s.Create(ctx, req.Order) return CreateResponse{ID: id, Err: err}, nil } }
Bereitstellen eines Dienstes über HTTP
Wir haben unseren Service erstellt und RPC-Endpunkte für die Bereitstellung unserer Servicemethoden beschrieben. Jetzt müssen wir unseren Service außerhalb veröffentlichen, damit andere Services RCP-Endpunkte aufrufen können. Um unseren Service verfügbar zu machen, müssen wir das Transportprotokoll für unseren Service festlegen, nach dem Anfragen angenommen werden. Das Go-Kit unterstützt verschiedene Transporte wie HTTP, gRPC, NATS, AMQP und Thrift.
Zum Beispiel verwenden wir den HTTP-Transport für unseren Service. Das Go-Kit-Paket github.com/go-kit/kit/transport/http bietet die Möglichkeit, HTTP-Anforderungen zu bearbeiten. Die NewServer
Funktion aus dem transport/http
Paket erstellt einen neuen http-Server, der http.Handler
implementiert und die bereitgestellten Endpunkte http.Handler
.
Im Folgenden finden Sie den Code, der Go-Kit-Endpunkte in einen HTTP-Transport konvertiert, der HTTP-Anforderungen bedient:
package http import ( "context" "encoding/json" "errors" "github.com/shijuvar/gokit-examples/services/order" "net/http" "github.com/go-kit/kit/log" kithttp "github.com/go-kit/kit/transport/http" "github.com/gorilla/mux" "github.com/shijuvar/gokit-examples/services/order/transport" ) var ( ErrBadRouting = errors.New("bad routing") )
Wir erstellen http.Handler
mit der NewServer
Funktion aus dem transport/http
Paket, das Endpunkte und Anforderungsdecodierungsfunktionen (gibt den Wert vom type DecodeRequestFunc func
) und Antwortcodierung (z. B. type EncodeReponseFunc func
) type EncodeReponseFunc func
.
Das Folgende sind Beispiele für DecodeRequestFunc
und EncodeResponseFunc
:
HTTP-Server starten
Schließlich können wir unseren HTTP-Server ausführen, um Anforderungen zu verarbeiten. Die NewService
beschriebene NewService
Funktion implementiert die http.Handler
Schnittstelle http.Handler
der wir sie als HTTP-Server ausführen können:
func main() { var ( httpAddr = flag.String("http.addr", ":8080", "HTTP listen address") ) flag.Parse() var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) logger = log.NewSyncLogger(logger) logger = level.NewFilter(logger, level.AllowDebug()) logger = log.With(logger, "svc", "order", "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller, ) } level.Info(logger).Log("msg", "service started") defer level.Info(logger).Log("msg", "service ended") var db *sql.DB { var err error
Jetzt wird unser Dienst gestartet und verwendet das HTTP-Protokoll auf Transportebene. Derselbe Dienst kann mit einem anderen Transport gestartet werden. Beispielsweise kann ein Dienst mit gRPC oder Apache Thrift verfügbar gemacht werden.
Für den Einführungsartikel haben wir bereits genug Go-Kit-Grundelemente verwendet, aber es bietet auch mehr Funktionen zum Erstellen von Systemen mit transparenten, zuverlässigen Mustern, Serviceerkennung, Lastausgleich usw. Wir werden diese und andere Dinge im Go-Kit in den folgenden Artikeln diskutieren.
Quellcode
Der gesamte Quellcode für die Beispiele kann hier auf GitHub eingesehen werden.
Middleware im Go-Kit
Das Go-Kit ist prädisponiert für die Verwendung guter Prinzipien des Systemdesigns, wie z. B. Layering. Die Isolierung von Servicekomponenten und Endpunkten ist mit Middlewares möglich ( ca. Lane Mediator Pattern ). Middlewares im Go-Kit bietet einen leistungsstarken Mechanismus, mit dem Sie Dienste und Endpunkte umschließen und Funktionen (isolierte Komponenten) hinzufügen können, z. B. Protokollierung, Unterbrechung von Anforderungen, Begrenzung der Anzahl von Anforderungen, Lastausgleich oder verteilte Ablaufverfolgung.
Unten sehen Sie ein Bild von der Go-Kit- Website, das als typische „Zwiebelarchitektur“ mit Middlewares im Go-Kit dargestellt wird:

Vorsicht vor dem Spring Boot Microservices Syndrom
Wie das Go-Kit ist Spring Boot ein Microservice-Toolkit in der Java-Welt. Im Gegensatz zum Go-Kit ist Spring Boot jedoch ein sehr ausgereiftes Framework. Viele Java-Entwickler verwenden Spring Boot, um mithilfe des Java-Stacks World Services mit positivem Feedback aus der Verwendung zu erstellen. Einige von ihnen glauben, dass es bei Microservices nur um die Verwendung von Spring Boot geht. Ich sehe viele Entwicklungsteams, die die Verwendung von Microservices falsch interpretieren, dass sie nur mit Spring Boot und OSS Netflix entwickelt werden können und Microservices bei der Entwicklung verteilter Systeme nicht als Muster wahrnehmen.
Denken Sie also daran, dass Sie mit einer Reihe von Tools, wie einem Go-Kit oder einem Framework, Ihre Entwicklung auf Mikroseurises als Entwurfsmuster ausrichten. Obwohl Microservices viele Skalierungsprobleme sowohl von Befehlen als auch von Systemen lösen, entstehen auch viele Probleme, da die Daten in Microservice-Systemen auf verschiedene Datenbanken verteilt sind, was manchmal viele Probleme beim Erstellen von Transaktions- oder Datenabfragen verursacht. Es hängt alles vom Problem des Themenbereichs und dem Kontext Ihres Systems ab. Das Coole ist, dass das Go-Kit, das als Tool zum Erstellen von Microservices entwickelt wurde, auch zum Erstellen eleganter Monolithen geeignet ist, die mit einem guten Architekturdesign für Ihre Systeme erstellt wurden.
Einige Funktionen des Go-Kits, z. B. das Unterbrechen und Einschränken von Anforderungen, sind auch auf Service-Mesh-Plattformen wie Istio verfügbar. Wenn Sie also etwas wie Istio verwenden, um Ihre Mikroseurises zu starten, benötigen Sie möglicherweise nicht einige Dinge aus dem Go-Kit, aber nicht jeder hat genug Kanalbreite, um das Service-Mesh zum Erstellen einer dienstübergreifenden Kommunikation zu verwenden, da dies mehr hinzufügt eine Ebene und zusätzliche Komplexität.
PS
Der Autor der Übersetzung teilt möglicherweise nicht die Meinung des Autors des Originaltextes . Dieser Artikel wurde nur zu Bildungszwecken für die russische Sprachgemeinschaft Go übersetzt.
UPD
Dies ist auch der erste Artikel im Übersetzungsbereich und ich wäre für jedes Feedback zur Übersetzung dankbar.