Skip to content

Add benchmarks for critical components and hot paths. #6749

@markusthoemmes

Description

@markusthoemmes

Knative intends to add as little overhead to pure HTTP as possible. As such, some of our components are exposed to the hot-path of just about each HTTP request coming into and flowing through the system.

We need benchmarks (both micro and macro) to be able to reason about the impact of changes we do and to be able to quickly iterate on different strategies to remove that overhead.

Off the top of my mind, we need benchmarks for:

  • Concurrency measurement in the queue-proxy
  • Concurrency measurement in the activator
  • Every handler in the activator's handler chain
  • Exercising the entire handler chain in the activator
  • The Throttler in the activator

Each of these can be taken individually, an example for handler benchmarks is

func BenchmarkHandler(b *testing.B) {
ctx, cancel, _ := rtesting.SetupFakeContextWithCancel(&testing.T{})
defer cancel()
configStore := setupConfigStore(&testing.T{}, logging.FromContext(ctx))
reporter, err := activator.NewStatsReporter("test_pod")
if err != nil {
b.Fatalf("Failed to create a reporter: %v", err)
}
revReporter, err := reporter.GetRevisionStatsReporter(testNamespace, "tests_svc", "test_conf", testRevName)
if err != nil {
b.Fatalf("Failed to create a revision reporter: %v", err)
}
// bodyLength is in kilobytes.
for _, bodyLength := range [5]int{2, 16, 32, 64, 128} {
body := []byte(randomString(1024 * bodyLength))
rt := pkgnet.RoundTripperFunc(func(*http.Request) (*http.Response, error) {
return &http.Response{
Body: ioutil.NopCloser(bytes.NewReader(body)),
StatusCode: http.StatusOK,
}, nil
})
handler := (New(ctx, fakeThrottler{})).(*activationHandler)
handler.transport = rt
request := func() *http.Request {
req := httptest.NewRequest(http.MethodGet, "http://example.com", nil)
req.Host = "test-host"
reqCtx := configStore.ToContext(context.Background())
reqCtx = withRevision(reqCtx, revision(testNamespace, testRevName))
reqCtx = withRevID(reqCtx, types.NamespacedName{Namespace: testNamespace, Name: testRevName})
reqCtx = withReporter(reqCtx, revReporter)
return req.WithContext(reqCtx)
}
test := func(req *http.Request, b *testing.B) {
resp := &responseRecorder{}
handler.ServeHTTP(resp, req)
if resp.code != http.StatusOK {
b.Fatalf("resp.Code = %d, want: StatusOK(200)", resp.code)
}
if got, want := resp.size, int32(len(body)); got != want {
b.Fatalf("|body| = %d, want = %d", got, want)
}
}
b.Run(fmt.Sprintf("%03dk-resp-len-sequential", bodyLength), func(b *testing.B) {
req := request()
for j := 0; j < b.N; j++ {
test(req, b)
}
})
b.Run(fmt.Sprintf("%03dk-resp-len-parallel", bodyLength), func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
req := request()
for pb.Next() {
test(req, b)
}
})
})
}
}
(for a rather complex one) or in
func BenchmarkRequestLogHandlerNoTemplate(b *testing.B) {
handler, err := NewRequestLogHandler(baseHandler, ioutil.Discard, "", defaultInputGetter, false)
if err != nil {
b.Fatalf("Failed to create handler: %v", err)
}
resp := httptest.NewRecorder()
b.Run(fmt.Sprint("sequential"), func(b *testing.B) {
req := httptest.NewRequest(http.MethodGet, "http://example.com", nil)
for j := 0; j < b.N; j++ {
handler.ServeHTTP(resp, req)
}
})
b.Run(fmt.Sprint("parallel"), func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
req := httptest.NewRequest(http.MethodGet, "http://example.com", nil)
for pb.Next() {
handler.ServeHTTP(resp, req)
}
})
})
}
for a very simple one, which should be applicable to most of the above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/autoscalegood first issueDenotes an issue ready for a new contributor, according to the "help wanted" guidelines.help wantedDenotes an issue that needs help from a contributor. Must meet "help wanted" guidelines.lifecycle/staleDenotes an issue or PR has remained open with no activity and has become stale.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions