Golang HTTP客户端 - Connectex:通常允许每个套接字地址(协议/网络地址/端口)的一个用法
我正在尝试创建基于Golang Net/HTTP的Web服务,该服务从用户那里获取JSON输入,然后查询第三方Web API ITSELVES,以获取数据,然后返回对客户端的答案。我使用http.client {} client.do()方法来查询第三方Web API。当我执行性能测试(JMeter)时,通常会出现错误: Connectex:通常允许每个套接字地址(协议/网络地址/端口)使用一个用法。我怀疑种族状态,但种族检测没有任何种族状态。在我看来,发布http请求的频率很高,可能会随着时间的流逝而导致端口耗尽。因此,我试图在两个或三个实例(主机)之间平衡查询。但是,我仍然经常出现错误。有没有办法避免此错误?有没有建筑技巧,可以使我的服务高负载准备好?您可以在下面看到简化的代码示例:
var upstream = []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"}
var scheme = "http"
var timeout = 5
func main() {
fmt.Println("Listening on *: 8080")
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(405), 405)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println("Error:", err)
http.Error(w, http.StatusText(400), 400)
return
}
var jsonEntity = make(map[string]string)
json.Unmarshal(body, &jsonEntity)
payload := bytes.NewReader(body)
url := r.URL
url.Host = upstream[0]
if len(upstream) > 1 {
url.Host = upstream[random(0, len(upstream))]
}
url.Scheme = scheme
proxyReq, err := http.NewRequest(http.MethodPost, url.String(), payload)
if err != nil {
fmt.Println("Error:", err)
http.Error(w, http.StatusText(400), 400)
return
}
client := http.Client{Timeout: time.Duration(timeout) * time.Second}
response, err := client.Do(proxyReq) // <- IT FAILS HERE!!!
if err != nil {
fmt.Println("Error:", err)
http.Error(w, http.StatusText(500), 500)
sendWithCheck(w, "%s", []byte(`{"answerParam":"error"}`))
return
}
defer func() {
if err := response.Body.Close(); err != nil {
log.Println("Error:", err)
}
}()
res, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("Error:", err)
http.Error(w, http.StatusText(500), 500)
sendWithCheck(w, "%s", []byte(`{"answerParam":"error"}`))
return
}
if response.StatusCode == 200 {
sendWithCheck(w, "%s", res)
return
}
w.WriteHeader(response.StatusCode)
return
}
I`m trying to create a Golang net/http based web service, which takes a JSON input from user, and then it queries a third party web API itselves, to get data and then returns answer to client. I use http.Client{} client.Do() method to query the third party web API. When I perform a performance test (JMeter), very often I get the error: connectex: Only one usage of each socket address (protocol/network address/port) is normally permitted. I suspected the race state, but race detection shows no state of race. To my mind, posting HTTP requests too often, may cause port exhaustion over time. So, I tried to balance queries between two or three instances (hosts). However, I still get the error rather often. Is there a way to avoid this error? Is there any architecture trick, to make my service high-load ready? You can see the simplified code example below:
var upstream = []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"}
var scheme = "http"
var timeout = 5
func main() {
fmt.Println("Listening on *: 8080")
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, http.StatusText(405), 405)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println("Error:", err)
http.Error(w, http.StatusText(400), 400)
return
}
var jsonEntity = make(map[string]string)
json.Unmarshal(body, &jsonEntity)
payload := bytes.NewReader(body)
url := r.URL
url.Host = upstream[0]
if len(upstream) > 1 {
url.Host = upstream[random(0, len(upstream))]
}
url.Scheme = scheme
proxyReq, err := http.NewRequest(http.MethodPost, url.String(), payload)
if err != nil {
fmt.Println("Error:", err)
http.Error(w, http.StatusText(400), 400)
return
}
client := http.Client{Timeout: time.Duration(timeout) * time.Second}
response, err := client.Do(proxyReq) // <- IT FAILS HERE!!!
if err != nil {
fmt.Println("Error:", err)
http.Error(w, http.StatusText(500), 500)
sendWithCheck(w, "%s", []byte(`{"answerParam":"error"}`))
return
}
defer func() {
if err := response.Body.Close(); err != nil {
log.Println("Error:", err)
}
}()
res, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("Error:", err)
http.Error(w, http.StatusText(500), 500)
sendWithCheck(w, "%s", []byte(`{"answerParam":"error"}`))
return
}
if response.StatusCode == 200 {
sendWithCheck(w, "%s", res)
return
}
w.WriteHeader(response.StatusCode)
return
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论