6. apiserver(三、请求处理超时机制)
apiserver处理请求的时候存在超时机制,一旦处理请求超出时间限制(默认为1min),会直接返回timeout。
在Kubernetes 系列 - 5. apiserver(二、创建处理链)中曾提到,apiserver的handler是用DefaultBuildHandlerChain构建的,其中和超时机制有关的部分为:
...
handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc)
handler = genericapifilters.WithRequestDeadline(handler, c.AuditBackend, c.AuditPolicyRuleEvaluator,
c.LongRunningFunc, c.Serializer, c.RequestTimeout)
...
6.1 启动“闹钟”
WithRequestDeadline跟踪下去的逻辑如下:
func WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc) {
...
c := &timerCtx{
deadline: d,
}
...
dur := time.Until(d)
if dur <= 0 {
c.cancel(true, DeadlineExceeded, cause) // deadline has already passed
return c, func() { c.cancel(false, Canceled, nil) }
}
c.mu.Lock()
defer c.mu.Unlock()
if c.err == nil {
c.timer = time.AfterFunc(dur, func() {
c.cancel(true, DeadlineExceeded, cause)
})
}
return c, func() { c.cancel(true, Canceled, nil) }
}
关键在于time.AfterFunc,会启动一个timer协程,达到定时点之后会调用传入的函数,即cancel:
func AfterFunc(d Duration, f func()) *Timer {
t := &Timer{
r: runtimeTimer{
when: when(d),
f: goFunc,
arg: f,
},
}
startTimer(&t.r)
return t
}
6.2 监听超时信号
当执行cancel之后会关闭timeoutCh通道,WithTimeoutForNonLongRunningRequests里面会读取这个通道判断是否超时:
func (t *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
...
timeoutCh := r.Context().Done()
...
go func() {
defer func() {
err := recover()
// do not wrap the sentinel ErrAbortHandler panic value
if err != nil && err != http.ErrAbortHandler {
// Same as stdlib http server code. Manually allocate stack
// trace buffer size to prevent excessively large logs
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
err = fmt.Sprintf("%v\n%s", err, buf)
}
resultCh <- err
}()
t.handler.ServeHTTP(w, rCopy)
}()
select {
case err := <-resultCh:
...
case <-timeoutCh:
...
}
}