Skip to content

Commit

Permalink
Support HTTP/2 with TLS in OTLP HTTP receiver. (#5109)
Browse files Browse the repository at this point in the history
* Support HTTP/2 with TLS in OTLP HTTP receiver.

* Add benchmark

* Explicit http/1 fallback proto

* Update CHANGELOG.md

Co-authored-by: Bogdan Drutu <lazy@splunk.com>
  • Loading branch information
anuraaga and Bogdan Drutu authored Apr 1, 2022
1 parent 9d47500 commit d2e5601
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

### 💡 Enhancements 💡

- OTLP HTTP receiver will use HTTP/2 over TLS if client supports it (#5190)

### 🧰 Bug fixes 🧰

## v0.48.0 Beta
Expand Down
2 changes: 2 additions & 0 deletions config/confighttp/confighttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/rs/cors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"golang.org/x/net/http2"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config"
Expand Down Expand Up @@ -232,6 +233,7 @@ func (hss *HTTPServerSettings) ToListener() (net.Listener, error) {
if err != nil {
return nil, err
}
tlsCfg.NextProtos = []string{http2.NextProtoTLS, "http/1.1"}
listener = tls.NewListener(listener, tlsCfg)
}
return listener, nil
Expand Down
136 changes: 135 additions & 1 deletion config/confighttp/confighttp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ func TestHttpReception(t *testing.T) {
tlsServerCreds *configtls.TLSServerSetting
tlsClientCreds *configtls.TLSClientSetting
hasError bool
forceHTTP1 bool
}{
{
name: "noTLS",
Expand All @@ -404,6 +405,23 @@ func TestHttpReception(t *testing.T) {
ServerName: "localhost",
},
},
{
name: "TLS (HTTP/1.1)",
tlsServerCreds: &configtls.TLSServerSetting{
TLSSetting: configtls.TLSSetting{
CAFile: filepath.Join("testdata", "ca.crt"),
CertFile: filepath.Join("testdata", "server.crt"),
KeyFile: filepath.Join("testdata", "server.key"),
},
},
tlsClientCreds: &configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CAFile: filepath.Join("testdata", "ca.crt"),
},
ServerName: "localhost",
},
forceHTTP1: true,
},
{
name: "NoServerCertificates",
tlsServerCreds: &configtls.TLSServerSetting{
Expand Down Expand Up @@ -505,15 +523,24 @@ func TestHttpReception(t *testing.T) {
<-time.After(10 * time.Millisecond)

prefix := "https://"
expectedProto := "HTTP/2.0"
if tt.tlsClientCreds.Insecure {
prefix = "http://"
expectedProto = "HTTP/1.1"
}

hcs := &HTTPClientSettings{
Endpoint: prefix + ln.Addr().String(),
TLSSetting: *tt.tlsClientCreds,
}
client, errClient := hcs.ToClient(map[config.ComponentID]component.Extension{}, componenttest.NewNopTelemetrySettings())
if tt.forceHTTP1 {
expectedProto = "HTTP/1.1"
hcs.CustomRoundTripper = func(rt http.RoundTripper) (http.RoundTripper, error) {
rt.(*http.Transport).ForceAttemptHTTP2 = false
return rt, nil
}
}
client, errClient := hcs.ToClient(map[config.ComponentID]component.Extension{}, component.TelemetrySettings{})
require.NoError(t, errClient)

resp, errResp := client.Get(hcs.Endpoint)
Expand All @@ -524,6 +551,7 @@ func TestHttpReception(t *testing.T) {
body, errRead := ioutil.ReadAll(resp.Body)
assert.NoError(t, errRead)
assert.Equal(t, "test", string(body))
assert.Equal(t, expectedProto, resp.Proto)
}
require.NoError(t, s.Close())
})
Expand Down Expand Up @@ -919,3 +947,109 @@ type mockHost struct {
func (nh *mockHost) GetExtensions() map[config.ComponentID]component.Extension {
return nh.ext
}

func BenchmarkHttpRequest(b *testing.B) {
tests := []struct {
name string
forceHTTP1 bool
clientPerThread bool
}{
{
name: "HTTP/2.0, shared client (like load balancer)",
forceHTTP1: false,
clientPerThread: false,
},
{
name: "HTTP/1.1, shared client (like load balancer)",
forceHTTP1: true,
clientPerThread: false,
},
{
name: "HTTP/2.0, client per thread (like single app)",
forceHTTP1: false,
clientPerThread: true,
},
{
name: "HTTP/1.1, client per thread (like single app)",
forceHTTP1: true,
clientPerThread: true,
},
}

tlsServerCreds := &configtls.TLSServerSetting{
TLSSetting: configtls.TLSSetting{
CAFile: filepath.Join("testdata", "ca.crt"),
CertFile: filepath.Join("testdata", "server.crt"),
KeyFile: filepath.Join("testdata", "server.key"),
},
}
tlsClientCreds := &configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CAFile: filepath.Join("testdata", "ca.crt"),
},
ServerName: "localhost",
}

hss := &HTTPServerSettings{
Endpoint: "localhost:0",
TLSSetting: tlsServerCreds,
}

s, err := hss.ToServer(
componenttest.NewNopHost(),
componenttest.NewNopTelemetrySettings(),
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, errWrite := fmt.Fprint(w, "test")
require.NoError(b, errWrite)
}))
require.NoError(b, err)
ln, err := hss.ToListener()
require.NoError(b, err)

go func() {
_ = s.Serve(ln)
}()
defer func() {
_ = s.Close()
}()

// Wait for the servers to start
<-time.After(10 * time.Millisecond)

for _, bb := range tests {
hcs := &HTTPClientSettings{
Endpoint: "https://" + ln.Addr().String(),
TLSSetting: *tlsClientCreds,
}
if bb.forceHTTP1 {
hcs.CustomRoundTripper = func(rt http.RoundTripper) (http.RoundTripper, error) {
rt.(*http.Transport).ForceAttemptHTTP2 = false
return rt, nil
}
}
b.Run(bb.name, func(b *testing.B) {
var c *http.Client
if !bb.clientPerThread {
c, err = hcs.ToClient(map[config.ComponentID]component.Extension{}, component.TelemetrySettings{})
require.NoError(b, err)
}
b.RunParallel(func(pb *testing.PB) {
if c == nil {
c, err = hcs.ToClient(map[config.ComponentID]component.Extension{}, component.TelemetrySettings{})
require.NoError(b, err)
}
for pb.Next() {
resp, errResp := c.Get(hcs.Endpoint)
require.NoError(b, errResp)
body, errRead := ioutil.ReadAll(resp.Body)
_ = resp.Body.Close()
require.NoError(b, errRead)
require.Equal(b, "test", string(body))
}
c.CloseIdleConnections()
})
// Wait for connections to close before closing server to prevent log spam
<-time.After(10 * time.Millisecond)
})
}
}

0 comments on commit d2e5601

Please sign in to comment.