英文:
Golang http server app have many Socket (CLOSE_WAIT)
问题
应用程序可以工作几天。但在某些时刻,应用程序有许多处于CLOSE_WAIT状态的套接字,并且无法接收新的客户端。
可能是某种洪水攻击(例如:同步洪水)吗?
netstat -ant | grep CLOSE_WAIT | wc
3258 19548 260640
3258个套接字处于CLOSE_WAIT状态
更新:
编写了一些处理程序:
func GetScore(mongo *mgo.Session, redisConn redis.Conn, renderer handlers.Render) http.Handler {
mutex := sync.Mutex{}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := bson.ObjectIdHex(r.FormValue("id"))
banner := models.Banner{}
err := mongo.DB("db").C("collection").FindId(id).One(&banner)
if err != nil {
log.Panicf("Banner selecting error: %s", err)
}
mutex.Lock()
sports, _ := util.GetSports(redisConn)
mutex.Unlock()
sport, _ := sports.FindSport(banner.SportId)
comp, err := sport.FindCompetition(banner.CompetitionId)
if err != nil {
comp, _ = sport.FindCompetition(0)
log.Println("Competition not found")
}
game, err := comp.FindGame(banner.GameId)
if err != nil {
game, _ = comp.FindGame(0)
}
mutex.Lock()
scores := util.GetScore(redisConn, game.ID)
mutex.Unlock()
game.Score1 = scores[0]
game.Score2 = scores[1]
w.Header().Set("Content-Type", "application/json;application/json;charset=utf-8")
renderer.RenderJson(w, 200, &game)
})
}
func GetScore(redisConn redis.Conn, gameId int) []float32 {
redisKey := fmt.Sprintf("game-%d", gameId)
bBody, err := redis.Bytes(redisConn.Do("GET", redisKey))
if err != nil || len(bBody) == 0 {
response, err := http.DefaultClient.Get(fmt.Sprintf("%s%d", GameApi, gameId))
if err != nil {
log.Panicf("GetScore error: %s", err)
}
bBody, _ = ioutil.ReadAll(response.Body)
redisConn.Send("SET", redisKey, bBody)
redisConn.Send("EXPIRE", redisKey, 60*5)
redisConn.Flush()
}
events := GameJson{}
err = json.Unmarshal(bBody, &events)
if err != nil {
log.Panicf("GetScore json error: %s", err)
}
var event []struct {
Name string `json:"name"`
Price float32 `json:"price"`
}
if len(events.AllEvents.P1XP2) != 0 {
event = events.AllEvents.P1XP2[0].Events
} else {
event = events.AllEvents.Other[0].Events
}
return []float32{event[0].Price, event[1].Price}
}
英文:
App can works few days. But in some moment, app has many socket with CLOSE_WAIT state, and cannot receive new client.
Maybe it is some kind of flooding(Example: Sync-flood)?
netstat -ant | grep CLOSE_WAIT | wc
3258 19548 260640
3258 - socket in CLOSE_WAIT state
Update:
Code some handler:
func GetScore(mongo *mgo.Session, redisConn redis.Conn, renderer handlers.Render) http.Handler {
mutex := sync.Mutex{}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := bson.ObjectIdHex(r.FormValue("id"))
banner := models.Banner{}
err := mongo.DB("db").C("collection").FindId(id).One(&banner)
if err != nil {
log.Panicf("Banner selecting error: %s", err);
}
mutex.Lock();
sports, _ := util.GetSports(redisConn)
mutex.Unlock();
sport, _ := sports.FindSport(banner.SportId)
comp, err := sport.FindCompetition(banner.CompetitionId)
if err != nil {
comp, _ = sport.FindCompetition(0);
log.Println("Competition not found");
}
game, err := comp.FindGame(banner.GameId)
if err != nil {
game, _ = comp.FindGame(0)
}
mutex.Lock();
scores := util.GetScore(redisConn, game.ID)
mutex.Unlock();
game.Score1 = scores[0]
game.Score2 = scores[1]
w.Header().Set("Content-Type", "application/json;application/json;charset=utf-8")
renderer.RenderJson(w, 200, &game)
}
func GetScore(redisConn redis.Conn, gameId int) ([]float32) {
redisKey := fmt.Sprintf("game-%d", gameId);
bBody, err := redis.Bytes(redisConn.Do("GET", redisKey))
if err != nil || len(bBody) == 0 {
response, err := http.DefaultClient.Get(fmt.Sprintf("%s%d", GameApi, gameId))
if err != nil {
log.Panicf("GetScore error: %s", err)
}
bBody, _ = ioutil.ReadAll(response.Body);
redisConn.Send("SET", redisKey, bBody)
redisConn.Send("EXPIRE", redisKey, 60 * 5)
redisConn.Flush()
}
events := GameJson{};
err = json.Unmarshal(bBody, &events)
if err != nil {
log.Panicf("GetScore json error: %s", err)
}
var event []struct {
Name string `json:"name"`
Price float32 `json:"price"`
}
if len(events.AllEvents.P1XP2) != 0 {
event = events.AllEvents.P1XP2[0].Events
} else {
event = events.AllEvents.Other[0].Events
}
return []float32{event[0].Price, event[1].Price}
}
答案1
得分: 4
CLOSE-WAIT表示TCP正在等待本地应用程序关闭套接字,已经收到对等方的关闭。
>也许这是某种洪水攻击(例如:同步洪水)?
不是的。这是你的代码中的一个错误。你在某个地方没有关闭套接字。
>问题似乎不在代码中。
问题就在你的代码中。
>代码已经测试了几次。
但没有针对这种情况进行测试,或者在产生这个问题的条件下进行测试。
>但是昨天我没有遇到这个问题。
所以昨天没有出现这些条件。
>(代码没有更改。)
所以这个错误一直存在。
英文:
CLOSE-WAIT means that TCP is waiting for the local application to close the socket, having already received a close from the peer.
> Maybe it is some kind of flooding(Example: Sync-flood)?
No. It is a bug in your code. You aren't closing a socket somewhere.
> The problem seems to be not in the code.
The problem is in your code.
> Code tested several times.
But not for this condition, or under the conditions that produce this problem.
> But yesterday I did not have this problem.
So yesterday those condtiions did not occur.
> (Code was not changed.)
So the bug has always been there.
答案2
得分: 0
模拟情况:
当客户端超时时,服务器上的套接字不会在15秒内关闭。
在我的情况下,当应用程序有很多请求时,我有超过10,000个处于CLOSE_WAIT状态的套接字。
互斥模拟:
time.Sleep(30 * time.Second)
服务器:
package main
import "net/http"
import "time";
func main() {
http.ListenAndServe(":81", http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
println("Sleep")
time.Sleep(30 * time.Second)
println("After sleep");
}));
}
客户端:
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
HttpURLConnection connection = (HttpURLConnection) new URL("http://link").openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(false);
connection.setDoInput(true);
connection.setReadTimeout(15000);
connection.getInputStream().read();
System.out.println("Close");
connection.disconnect();
}
}
英文:
Emulation of situation:
When client timeout works. Socket on server will not closed 15 sec.
In my case, when app have many request, I have > 10k socket in CLOSE_WAIT STATE.
Emulation of mutex:
time.Sleep(30 * time.Second)
Server:
package main
import "net/http"
import "time";
func main() {
http.ListenAndServe(":81", http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
println("Sleep")
time.Sleep(30 * time.Second)
println("After sleep");
}));
}
Client:
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
HttpURLConnection connection = (HttpURLConnection) new URL("http://link").openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(false);
connection.setDoInput(true);
connection.setReadTimeout(15000);
connection.getInputStream().read();
System.out.println("Close");
connection.disconnect();
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论