>백엔드 개발 >Golang >golang은 API 게이트웨이를 구현합니다.

golang은 API 게이트웨이를 구현합니다.

王林
王林원래의
2023-05-10 09:34:36871검색

마이크로서비스 아키텍처의 대중화와 서비스 수의 증가에 따라 서비스의 보안, 신뢰성 및 확장성을 향상시키기 위해 API 게이트웨이 기술이 시대에 맞게 등장했습니다. 오늘은 Golang을 사용하여 API 게이트웨이를 작성하는 방법에 대해 이야기하겠습니다.

1. Golang을 선택하는 이유

  1. 동시성 성능: Golang은 자연스럽게 코루틴을 지원하므로 동시성 시나리오에서 효율성을 향상하고 처리량이 더 높아집니다.
  2. 완전한 기능: Golang은 HTTP, WebSocket 등과 같은 완전한 네트워크 패키지를 갖추고 있으며 gRPC, MQTT 등과 같은 여러 프로토콜도 지원합니다.
  3. 코드 품질: Golang은 정적 언어입니다. 해당 유형 시스템은 코드 품질을 보장하는 동시에 편집기의 완성, 프롬프트 및 기타 기능을 최대한 활용하여 개발 효율성을 향상시킬 수 있습니다.
  4. 크로스 플랫폼: Golang은 다양한 플랫폼에서 실행될 수 있으며 배포도 매우 간단합니다.

2. API 게이트웨이 디자인 아이디어

API 게이트웨이를 디자인하기 전에 API 게이트웨이가 무엇을 해야 하는지 알아야 합니다. 일반적으로 API 게이트웨이는 다음을 수행해야 합니다.

  1. 라우팅: 요청된 URI를 기반으로 해당 서비스로 요청을 라우팅합니다.
  2. 필터링: 요청을 확인하고 인증합니다.
  3. 로드 밸런싱: 백엔드의 다양한 서비스 인스턴스에 요청을 분산합니다.
  4. 캐싱: 응답 속도를 향상하기 위해 응답 결과를 캐시합니다.
  5. 모니터링: 요청 응답 결과의 통계 및 모니터링.

위 아이디어에 따라 우리는 주로 다음 구성 요소를 포함하는 간단한 API 게이트웨이를 설계합니다.

  1. Router: 요청을 해당 서비스로 라우팅하는 역할을 담당합니다.
  2. Filter: 요청의 확인, 인증 및 기타 작업을 담당합니다.
  3. 로드 밸런싱: 백엔드의 다양한 서비스 인스턴스에 요청을 분산하는 역할을 담당합니다.
  4. 캐싱: 응답 결과를 캐싱하고 응답 속도를 향상시키는 역할을 담당합니다.
  5. 모니터링: 요청 응답 결과의 통계 및 모니터링을 담당합니다.

3. API Gateway 구현

다음으로 위 구성요소를 하나씩 구현하겠습니다.

1. Router

라우터를 구현하려면 먼저 라우팅 항목을 정의해야 합니다.

type Route struct {
    Path      string
    Method    string
    Handler   http.Handler
}

Route에는 라우팅 경로를 저장하는 경로, 요청의 메소드 유형을 저장하는 메소드 및 핸들러가 포함됩니다. 요청을 저장하고 처리합니다.

다음으로 경로 목록을 저장하고 요청을 해당 프로세서로 라우팅하는 라우터 구조를 정의합니다.

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)
}

코드에서 요청 처리 방법 및 경로를 등록하는 두 가지 방법을 제공합니다. HandleFunc는 http.HandleFunc와 유사해야 합니다. 라우팅 주소, 요청 방법 및 요청 처리 방법을 개체에 바인딩합니다. ServeHTTP는 요청을 받은 후 일치하는 경로를 검색합니다. 발견되지 않으면 해당 요청을 해당 처리 방법으로 전달합니다.

다음으로 간단한 처리 메서드 구현을 작성합니다.

func main() {
    router := &Router{}

    router.HandleFunc("/hello", "GET", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprint(w, "hello")
    })

    http.ListenAndServe(":8080", router)
}

이 처리 메서드는 주소가 /hello인 모든 GET 요청에 대해 hello를 반환합니다.

2. 필터

WAF(Web Application Firewall)는 다양한 공격으로부터 웹 애플리케이션을 보호하는 데 일반적으로 사용되는 필터입니다. 요청 방법, 요청 헤더, 요청 매개변수 및 기타 정보를 기반으로 요청을 필터링할 수 있습니다. 여기서는 요청 헤더를 필터로 사용합니다. 요청 헤더에 특정 태그가 포함되어 있으면 해당 태그가 전달되고, 그렇지 않으면 잘못된 요청으로 간주됩니다.

Golang을 사용하여 필터를 구현하려면 각 요청에 특정 태그가 포함되어 있는지 확인하는 미들웨어를 작성해야 합니다. 포함된 경우 계속해서 요청을 전달하고, 그렇지 않으면 오류가 반환됩니다. gorilla/mux를 사용하여 미들웨어를 구현할 수 있습니다.

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
}

코드에서 FilterMiddleware는 요청 헤더에 "X-Auth-Token" 태그가 포함되어 있는지 확인합니다. 포함되어 있으면 요청이 전달되고, 그렇지 않으면 승인되지 않은 오류가 반환됩니다. 또한 미들웨어 등록을 위한 RegisterMiddleware 함수를 정의합니다.

3. 로드 밸런싱

로드 밸런싱은 API 게이트웨이에서 가장 중요한 구성 요소 중 하나입니다. 백엔드의 다양한 서비스 인스턴스에 요청을 분산시킬 수 있습니다. 이를 달성하기 위해 폴링, 무작위 및 기타 알고리즘을 사용할 수 있습니다.

여기서는 로드 밸런싱을 위해 간단한 폴링 알고리즘을 사용합니다. 풀에서 다음 서버의 주소를 선택하고 해당 서버로 요청을 전달할 수 있습니다.

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})
}

코드에서는 서버 풀과 선택할 다음 서버의 위치를 ​​포함하는 간단한 로드 밸런싱 구조를 만들었습니다. pick() 메소드는 서버 풀의 길이에 따라 서버 주소를 선택합니다. HandleFunc에서는 Round Robin 알고리즘을 사용하여 요청을 다른 서버로 전달합니다.

4. 캐싱

캐싱은 시스템 성능을 향상시키고 백엔드에 대한 요청 수를 줄일 수도 있습니다. API 게이트웨이에서는 요청 응답 프로세스에 캐시를 내장하고 캐시에 직접 요청을 반환할 수 있어 빠른 응답을 제공할 수 있습니다.

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})
}

코드에서는 캐시 구조를 생성하고 HandleFunc에 요청을 캐시했습니다. 캐시에 동일한 요청이 있는 경우 캐시에서 직접 결과를 반환할 수 있으므로 백엔드에 대한 요청 수를 줄일 수 있습니다.

5. 모니터링

모니터링을 통해 시스템의 작동 상태를 더 잘 이해하고 현재 시스템의 응답 속도 등을 파악할 수 있습니다.

使用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网关。在实际使用中,我们还可以添加更多的功能,如熔断、限流、容错等,来提高其安全性、稳定性和可用性。

위 내용은 golang은 API 게이트웨이를 구현합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.