Quantcast
Channel: CodeSection,代码区,数据库(综合) - CodeSec
Viewing all articles
Browse latest Browse all 6262

追踪网站大量502

$
0
0

昨天有一场活动,活动过程当中突然redis proxy发生了长时间GC,这段时间之内大量的报警。过了几分钟就恢复了,以为没事了,晚上发现proxy层有大量的502服务。就开始了第二天的追查。

通过查proxy日志,有这几个特点。

有大量的502 后端超时时间都是3秒 多次502之后,部分机器被下架 所有机器都被下架 猜想一:后端服务有大量的502

通过查找后端服务日志,没有发现有502。并且proxy相关的日志ID,并没有出现在后端服务日志里面。

猜想二:后端服务日志没有打印出来

我们是go服务,查找代码,没有发现什么地方,能输出502。并且没有地方设置超时时间为3秒。

猜想三:Redis抖动造成的?

难道是Redis超时+重试是3秒,最后发现也不是这个原因。

这些猜想都不对,我就打算看nginx配置,proxy超时时间设置的是60秒,不是3秒,而且我们的接口有的能有5秒,也没有超时,应该不是proxy配置问题造成的。

突然发现了nginx错误日志,发现上面写的很清楚,连接upstram超时。我们都是内网,为什么会超时呢?网络应该不会有问题,其他的服务都没有问题。

猜想四:难道Nginx有一些默认的超时配置

搜索了相关的Nginx代码,并没有相关的默认配置。

猜想五:TCP握手有问题

通过查找资料,发现了新的方向。一些相同遭遇的人,通过抓包发现,SYN+重试正好是3秒。为什么连接不上呢?通过和小伙伴讨论,难道是go后端有问题?

猜想六:go代码有问题

经过看代码,发现了这么一段代码

func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
if fn := testHookServerServe; fn != nil {
fn(srv, l)
}
var tempDelay time.Duration // how long to sleep on accept failure
if err := srv.setupHTTP2(); err != nil {
return err
}
for {
rw, e := l.Accept()
if e != nil {
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve()
}
}

然后查看日志,搜索关键字,终于发现了http: Accept error: accept tcp 0.0.0.0:8081: accept4: too many open files; retrying in 5ms。瞬间豁然开朗。

经过和运维确认,发现机器重启之后,程序的默认打开文件数量变成了1024,低于我们的QPS。

出错过程

proxy将流量打到后端服务,结果后端服务连接数已经达到超时,连接失败。nginx连续遇到多次失败,将机器下架,最终造成雪崩效应,所有的机器都会被下架。下架的这段时间,自动的返回的502,不会将流量打到后端。

转载请注明:万马奔腾 追踪网站大量502


Viewing all articles
Browse latest Browse all 6262

Trending Articles