Heim >Backend-Entwicklung >Golang >Golang implementiert API-Gateway
Mit der Beliebtheit der Microservice-Architektur und der zunehmenden Anzahl von Diensten hat sich die API-Gateway-Technologie entsprechend den Anforderungen der Zeit entwickelt, um die Sicherheit, Zuverlässigkeit und Skalierbarkeit von Diensten zu verbessern. Heute werden wir darüber sprechen, wie man mit Golang ein API-Gateway schreibt.
1. Warum Golang verwenden?
2. API-Gateway-Designideen
Bevor wir ein API-Gateway entwerfen, müssen wir wissen, was ein API-Gateway tun muss. Im Allgemeinen muss ein API-Gateway Folgendes tun:
Gemäß den oben genannten Ideen entwerfen wir ein einfaches API-Gateway, das hauptsächlich die folgenden Komponenten umfasst:
3. Implementieren Sie das API-Gateway
Als nächstes werden wir die oben genannten Komponenten einzeln implementieren.
1. Router
Um einen Router zu implementieren, müssen wir zunächst ein Routing-Element definieren:
type Route struct { Path string Method string Handler http.Handler }
Route enthält einen Pfad zum Speichern Routingpfade: Eine Methode dient zum Speichern des Methodentyps der Anforderung und ein Handler zum Speichern der Methode zur Verarbeitung der Anforderung.
Als nächstes definieren wir eine Router-Struktur, um die Routing-Liste zu speichern und die Anfrage an den entsprechenden Prozessor weiterzuleiten:
type Router struct { routes []*Route } func (r *Router) HandleFunc(path string, method string, handlerFunc http.HandlerFunc) { r.routes = append(r.routes, &Route{Path: path, Method: method, Handler: handlerFunc}) } func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { for _, route := range r.routes { if route.Path == req.URL.Path && route.Method == req.Method { route.Handler.ServeHTTP(w, req) return } } http.Error(w, "404 not found", http.StatusNotFound) }
Im Code stellen wir zwei zur Verfügung. Die Methode wird zur Registrierung verwendet Die Anforderungsverarbeitungsmethode und -route sollten http.HandleFunc ähneln. Es bindet die Routing-Adresse, die Anforderungsmethode und die Anforderungsverarbeitungsmethode an ein Objekt, und ServeHTTP findet nach Erhalt der Anforderung eine passende Route wird an die entsprechende Verarbeitungsmethode weitergeleitet. Wenn nicht gefunden, wird 404 zurückgegeben.
Als nächstes schreiben Sie eine einfache Implementierung einer Verarbeitungsmethode:
func main() { router := &Router{} router.HandleFunc("/hello", "GET", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello") }) http.ListenAndServe(":8080", router) }
Diese Verarbeitungsmethode gibt „Hallo“ für jede GET-Anfrage mit der Adresse /hello zurück.
2. Filter
WAF (Web Application Firewall) ist ein häufig verwendeter Filter, der Webanwendungen vor verschiedenen Angriffen schützt. Wir können Anfragen nach Anfragemethode, Anfrageheadern, Anfrageparametern und anderen Informationen filtern. Hier verwenden wir Anforderungsheader als Filter. Wenn der Anfrageheader ein bestimmtes Tag enthält, wird es übergeben, andernfalls wird es als ungültige Anfrage betrachtet.
Um Golang zum Implementieren von Filtern zu verwenden, müssen wir eine Middleware schreiben, die prüft, ob jede Anfrage ein bestimmtes Tag enthält. Wenn es enthalten ist, leiten Sie die Anforderung weiter weiter, andernfalls wird ein Fehler zurückgegeben. Wir können Gorilla/Mux verwenden, um Middleware zu implementieren.
type FilterMiddleware struct { next http.Handler } func (f *FilterMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Header.Get("X-Auth-Token") != "magic" { http.Error(w, "Unauthorized request", http.StatusUnauthorized) return } f.next.ServeHTTP(w, r) } func (r *Router) RegisterMiddleware(middleware func(http.Handler) http.Handler) { handler := http.Handler(r) for _, m := range middlewareFunctions { handler = m(handler) } r.Handler = handler }
Im Code prüft FilterMiddleware, ob der Anforderungsheader das Tag „X-Auth-Token“ enthält. Wenn dies der Fall ist, wird die Anforderung weitergegeben, andernfalls wird ein nicht autorisierter Fehler zurückgegeben . Wir definieren auch eine RegisterMiddleware-Funktion zum Registrieren von Middleware.
3. Lastausgleich
Lastausgleich ist eine der wichtigsten Komponenten im API-Gateway, das Anfragen an verschiedene Serviceinstanzen im Backend verteilen kann. Um dies zu erreichen, können wir Umfrage-, Zufalls- und andere Algorithmen verwenden.
Hier verwenden wir einen einfachen Polling-Algorithmus für den Lastausgleich. Wir können die Adresse des nächsten Servers aus einem Pool auswählen und die Anfrage an diesen Server weiterleiten.
type LoadBalancer struct { Pool []string Next int } func (l *LoadBalancer) Pick() string { if l.Next >= len(l.Pool) { l.Next = 0 } host := l.Pool[l.Next] l.Next++ return host } func (r *Router) HandleFunc(path string, method string, handlerFunc http.HandlerFunc) { l := &LoadBalancer{ Pool: []string{"http://127.0.0.1:8081", "http://127.0.0.1:8082"}, Next: 0, } handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { url, err := url.Parse(l.Pick()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } proxy := httputil.NewSingleHostReverseProxy(url) proxy.ServeHTTP(w, req) }) r.routes = append(r.routes, &Route{Path: path, Method: method, Handler: handler}) }
Im Code haben wir eine einfache Lastausgleichsstruktur erstellt, die den Serverpool und den Standort des nächsten auszuwählenden Servers enthält. Die Methode pick() wählt eine Serveradresse basierend auf der Länge des Serverpools aus. In HandleFunc verwenden wir den Round-Robin-Algorithmus, um Anfragen an verschiedene Server weiterzuleiten.
4. Cache
Cache kann die Leistung des Systems verbessern und auch die Anzahl der Anfragen an das Backend reduzieren. Im API-Gateway können wir den Cache in den Anfrage-Antwort-Prozess einbetten und die Anfrage direkt im Cache zurückgeben, wodurch schnell eine Antwort bereitgestellt werden kann.
type Cache struct { data map[string] []byte mutex sync.Mutex } func (c *Cache) Get(key string) []byte { c.mutex.Lock() defer c.mutex.Unlock() if value, ok := c.data[key]; ok { return value } return nil } func (c *Cache) Set(key string, value []byte) { c.mutex.Lock() defer c.mutex.Unlock() c.data[key] = value } func (r *Router) HandleFunc(path string, method string, handlerFunc http.HandlerFunc) { cache := &Cache{ data: make(map[string][]byte), } handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { key := r.URL.String() if data := cache.Get(key); data != nil { w.Write(data) return } buffer := &bytes.Buffer{} proxy := httputil.NewSingleHostReverseProxy(r.URL) proxy.ServeHTTP(buffer, r) cache.Set(key, buffer.Bytes()) w.Write(buffer.Bytes()) }) r.routes = append(r.routes, &Route{Path: path, Method: method, Handler: handler}) }
Im Code erstellen wir eine Cache-Struktur und zwischenspeichern die Anfrage in HandleFunc. Wenn die gleiche Anfrage im Cache vorhanden ist, können wir das Ergebnis direkt aus dem Cache zurückgeben und so die Anzahl der Anfragen an das Backend reduzieren.
5. Überwachung
Überwachung kann uns helfen, den Betriebsstatus des Systems besser zu verstehen und die Reaktionsgeschwindigkeit des aktuellen Systems zu erfassen.
使用Prometheus来实现API网关的监控。我们只需记录下来每一个请求的响应时间、状态码及信息,然后将所有的数据发送到Prometheus。
var ( apiRequestsDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: "api_request_duration_seconds", Help: "The API request duration distribution", Buckets: prometheus.DefBuckets, }, []string{"status"}) ) type MetricMiddleware struct { next http.Handler } func (m *MetricMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { start := time.Now() ww := httptest.NewRecorder() m.next.ServeHTTP(ww, r) duration := time.Since(start) apiRequestsDuration.WithLabelValues(strconv.Itoa(ww.Code)).Observe(duration.Seconds()) for key, values := range ww.Header() { for _, value := range values { w.Header().Add(key, value) } } w.WriteHeader(ww.Code) body := ww.Body.Bytes() w.Write(body) } func main() { router := &Router{} router.HandleFunc("/hello", "GET", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello") }) logger := NewLoggerMiddleware(router) http.Handle("/metrics", prometheus.Handler()) http.Handle("/", logger) service := ":8080" log.Printf("Server starting on %v ", service) log.Fatal(http.ListenAndServe(service, nil)) }
在代码中,我们定义了一个MetricMiddleware并在请求结束后统计相关时间数据,最后通过Prometheus将数据输出到Metrics监控系统中。我们还通过http.Handle将Prometheus绑定在“/metrics”路径上,方便查询。
结束语
至此,我们用Golang实现了一个简单的API网关。在实际使用中,我们还可以添加更多的功能,如熔断、限流、容错等,来提高其安全性、稳定性和可用性。
Das obige ist der detaillierte Inhalt vonGolang implementiert API-Gateway. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!