Guia Técnico da Biblioteca Oxy para Go

Oxy

Oxy é uma biblioteca Go que fornece manipuladores HTTP (handlers) para aprimorar a biblioteca padrão HTTP.

Funcionalidades Principais

  • Buffer: Realiza novas tentativas e armazena buffers de requisições e respostas.
  • Stream: Encaminha requisições diretaemnte, suportando codificação chunked com intervalo de flush configurável.
  • Forward: Encaminha requisições para um destino remoto e reescreve os cabeçalhos.
  • Roundrobin: Implementa um balanceador de carga round-robin.
  • Circuit Breaker: Disjuntor de circuito no estilo Hystrix.
  • Connlimit: Limitador de conexões simultâneas.
  • Ratelimit: Limitador de taxa de requisições (baseado no algoritmo de balde de tokken).
  • Trace: Logger estruturado para requisições e respostas.

Exemplo: Forward

O componente Forward atua como um proxy reverso. A lógica central adapta a solicitação para o destino correto.

// adapta a requisição para o URL de destino
func (f *encaminhadorHTTP) adaptarSolicitacao(reqSaida *http.Request, destino *url.URL) {
    reqSaida.URL = utils.CopiarURL(reqSaida.URL)
    reqSaida.URL.Scheme = destino.Scheme
    reqSaida.URL.Host = destino.Host

    u := f.obterURLDaRequisicao(reqSaida)
    reqSaida.URL.Path = u.Path
    reqSaida.URL.RawPath = u.RawPath
    reqSaida.URL.RawQuery = u.RawQuery
    reqSaida.RequestURI = "" // Requisições de saída não devem ter RequestURI

    reqSaida.Proto = "HTTP/1.1"
    reqSaida.ProtoMajor = 1
    reqSaida.ProtoMinor = 1

    if f.reescritor != nil {
        f.reescritor.Reescrever(reqSaida)
    }

    // Não passa o cabeçalho Host do cliente, a menos que PassHostHeader esteja definido.
    if !f.passarHost {
        reqSaida.Host = destino.Host
    }
}

proxyReverso := httputil.ReverseProxy{
    Director: func(req *http.Request) {
        f.adaptarSolicitacao(req, reqEntrada.URL)
    },
    Transport:      f.roundTripper,
    FlushInterval:  f.intervaloDeFlush,
    ModifyResponse: f.modificarResposta,
    BufferPool:     f.poolDeBuffer,
}

proxyReverso.ServeHTTP(w, reqSaida)

Exemplo: Ratelimit

O componente Ratelimit controla a taxa de requisições por fonte (ex.: andereço IP) usando um balde de tokens.

func (lt *LimitadorPorToken) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    // Extrai informações do cliente, como IP e host.
    identificadorCliente, quantidade, err := lt.extrator.Extrair(req)
    if err != nil {
        lt.tratadorDeErros.ServeHTTP(w, req, err)
        return
    }

    // Processa o consumo da taxa permitida.
    if err := lt.processarConsumoDeTaxas(req, identificadorCliente, quantidade); err != nil {
        lt.logger.Warnf("Requisição limitada %v %v, limite: %v", req.Method, req.URL, err)
        lt.tratadorDeErros.ServeHTTP(w, req, err)
        return
    }

    lt.proximo.ServeHTTP(w, req)
}

func (lt *LimitadorPorToken) processarConsumoDeTaxas(req *http.Request, identificador string, quantidade int64) error {
    lt.mutex.Lock()
    defer lt.mutex.Unlock()

    taxasEfetivas := lt.resolverTaxas(req)
    baldeI, existe := lt.baldes.Get(identificador)
    var balde *ConjuntoDeBaldeDeToken

    if existe {
        balde = baldeI.(*ConjuntoDeBaldeDeToken)
        balde.Atualizar(taxasEfetivas)
    } else {
        balde = NovoConjuntoDeBaldeDeToken(taxasEfetivas, lt.relogio)
        // Define um TTL de 10 vezes o período da taxa.
        lt.baldes.Set(identificador, balde, int(balde.periodoMaximo/time.Second)*10+1)
    }

    atraso, err := balde.Consumir(quantidade)
    if err != nil {
        return err
    }
    if atraso > 0 {
        return &ErroTaxaMaxima{Atraso: atraso}
    }
    return nil
}

Tags: go balanceamento-carga proxy-reverso controle-taxa Oxy

Publicado em 6-16 01:03 por Thomas