doucandiao9180 2014-08-25 00:01 采纳率: 100%
浏览 38
已采纳

一个HTTP代理

I'm writing a simple proxy in go that relays an HTTP request to one or more backend servers. Right now I'm still using only one backend server, but performance is not good and I'm sure I am doing something wrong. Probably related to how I send the HTTP request to another server: if I comment the call to send() then the server goes blazing fast, yielding more than 14 krps. While with the call to send() performance drops to less than 1 krps and drops even lower with time. This on a MacBook Pro.

The code is based on trivial code samples; I have created the client and reused it following the recommendation in the docs. Tests are done with Apache ab:

$ ab -n 10000 -c 10 -k "http://127.0.0.1:8080/test"

The backend server running on port 55455 does not change between experiments; Apache or nginx can be used. My custom web server yields more than 7 krps when measured directly, without proxy:

$ ab -n 10000 -c 10 -k "http://127.0.0.1:55455/test"

I would expect the proxied version to behave just as well as the non-proxied version, and sustain the performance over time.

The complete sample code follows.

package main

import (
        "fmt"
        "log"
        "net/http"
        )

func main() {

        tr := &http.Transport{
                DisableCompression: true,
                DisableKeepAlives: false,
        }
        client := &http.Client{Transport: tr}

        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

                send(r, client)
                fmt.Fprintf(w, "OK")
        })
        log.Fatal(http.ListenAndServe(":8080", nil))
}

func send(r *http.Request, client *http.Client) int {

        req, err := http.NewRequest("GET", "http://localhost:55455" + r.URL.Path, nil)
        if err != nil {
                log.Fatal(err)
                return 0
        }       
        resp, err := client.Do(req)
        if err != nil {
                log.Fatal(err)
                return 0
        }       
        if resp == nil {
                return 0
        }       
        return 1
}       

Eventually the code should send the request to multiple servers and process their answers, returning an int with the result. But I'm stuck at this step of just making the call.

What am I doing horribly wrong?

  • 写回答

1条回答 默认 最新

  • douchu4048 2014-08-25 04:54
    关注

    As the comment suggests, you should be returning (and dealing with) type error instead of ints, and to reiterate, don't use AB. The biggest thing that stands out to me is

    1. You should set the MaxIdleConnsPerHost in your Transport. This represents how many connections will persist (keep-alive) even if they have nothing to do at the moment.
    2. You have to read and close the body of the response in order for it to be returned to the pool.

    ...
    resp, err := client.Do(req)
    if err != nil {
        return err
    }
    responseBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    ...
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么