From 1bdeb058e1191428297cc65fc90cb59ae4a24a21 Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Tue, 29 Jul 2014 09:40:40 -0400 Subject: [PATCH] Slightly pause on requests to allow most to finish Currently, every write will result in a 202 (etcd adding a few ms of latency to each request). This forces clients to go into a poll loop and pick a reasonable server poll frequency, which results in 1 + N queries to the server for the single operation and adds unavoidable latency to each request which affects their perception of the service. Add a very slight (25ms by default) delay to wait for requests to finish. For clients doing normal writes this reduces the requests made against the server to 1. For clients on long requests this has no effect. The downside is that http connections are held on to for a longer period in high write loads. The decrease in perceived latency from the kubecfg is significant. --- pkg/apiserver/apiserver.go | 13 +++++++++---- pkg/apiserver/apiserver_test.go | 1 + pkg/apiserver/operation_test.go | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 8448517d61..e627dd1c66 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -59,10 +59,11 @@ func NewNotFoundErr(kind, name string) error { // // TODO: consider migrating this to go-restful which is a more full-featured version of the same thing. type APIServer struct { - prefix string - storage map[string]RESTStorage - ops *Operations - mux *http.ServeMux + prefix string + storage map[string]RESTStorage + ops *Operations + mux *http.ServeMux + asyncOpWait time.Duration } // New creates a new APIServer object. @@ -74,6 +75,8 @@ func New(storage map[string]RESTStorage, prefix string) *APIServer { prefix: strings.TrimRight(prefix, "/"), ops: NewOperations(), mux: http.NewServeMux(), + // Delay just long enough to handle most simple write operations + asyncOpWait: time.Millisecond * 25, } // Primary API methods @@ -279,6 +282,8 @@ func (s *APIServer) createOperation(out <-chan interface{}, sync bool, timeout t op := s.ops.NewOperation(out) if sync { op.WaitFor(timeout) + } else if s.asyncOpWait != 0 { + op.WaitFor(s.asyncOpWait) } return op } diff --git a/pkg/apiserver/apiserver_test.go b/pkg/apiserver/apiserver_test.go index 65547c46b0..4c4c221d71 100644 --- a/pkg/apiserver/apiserver_test.go +++ b/pkg/apiserver/apiserver_test.go @@ -400,6 +400,7 @@ func TestCreate(t *testing.T) { handler := New(map[string]RESTStorage{ "foo": simpleStorage, }, "/prefix/version") + handler.asyncOpWait = 0 server := httptest.NewServer(handler) client := http.Client{} diff --git a/pkg/apiserver/operation_test.go b/pkg/apiserver/operation_test.go index a828dfab79..2f7b1895d0 100644 --- a/pkg/apiserver/operation_test.go +++ b/pkg/apiserver/operation_test.go @@ -95,6 +95,7 @@ func TestOpGet(t *testing.T) { handler := New(map[string]RESTStorage{ "foo": simpleStorage, }, "/prefix/version") + handler.asyncOpWait = 0 server := httptest.NewServer(handler) client := http.Client{}