Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Investigate HTTP/2 support with Netty/Vert.x #1945

Closed
jasonjkeller opened this issue Jun 12, 2024 · 4 comments · Fixed by #1994
Closed

Investigate HTTP/2 support with Netty/Vert.x #1945

jasonjkeller opened this issue Jun 12, 2024 · 4 comments · Fixed by #1994
Assignees
Labels
5 Story Point Estimate apr-jun qtr Represents proposed work item for the Apr-Jun quarter

Comments

@jasonjkeller
Copy link
Contributor

This is a follow-on story to #1815 (also loosely related to #1799).

It was reported that the previous PR does not seem to address all cases and that there are still scenarios where HTTP/1 requests result in transaction whereas HTTP/2 requests do not. Upon further investigation it appears that Vert.x may be playing a roll in the missing HTTP/2 requests.

We should see if the instrumentation gap can be identified and addressed such that these HTTP/2 requests result in transactions being reported to NR.

@workato-integration
Copy link

@jasonjkeller jasonjkeller added the 3 Story Point Estimate label Jun 12, 2024
@jasonjkeller jasonjkeller self-assigned this Jun 12, 2024
@jasonjkeller jasonjkeller moved this from Triage to In Sprint in Java Engineering Board Jun 12, 2024
@jasonjkeller jasonjkeller added the apr-jun qtr Represents proposed work item for the Apr-Jun quarter label Jun 12, 2024
@jasonjkeller
Copy link
Contributor Author

jasonjkeller commented Jun 12, 2024

While examining the affected service, I found that the following HTTP/2 related Vert.x and Netty classes were being weaved:

Supportability/WeaveInstrumentation/WeaveClass/com.newrelic.instrumentation.netty-4.1.16/io/vertx/core/http/impl/VertxHttp2ConnectionHandler
Supportability/WeaveInstrumentation/WeaveClass/com.newrelic.instrumentation.netty-4.1.16/io/netty/handler/codec/http2/Http2ConnectionHandler

Following that lead I spun up an example HTTP/2 app using Vert.x & Netty that had similar symptoms; the same endpoint had transactions when using HTTP/1 but not HTTP/2.

Weaving io.vertx.core.http.impl.Http2ServerConnection in the Vert.x instrumentation (which already weaves io.vertx.core.http.impl.Http1xServerConnection for HTTP/1 requests) results in transactions being reported for HTTP/2 requests.

However, the transactions are named slightly differently as the transaction is actually by the Netty instrumentation for HTTP/1 (when we weave HttpObjectDecoder) but for HTTP/2 the transaction is started later by the Vert.x instrumentation (when we weave Http2ServerConnection). So far there is no obvious HTTP/2 Netty decoder that can be weaved to start the transaction earlier (there are challenges with weaving Http2ConnectionHandler$FrameDecoder). Ultimately this may be acceptable.


Debugging the repro app shows the following.

When making the HTTP/1 requests:

channelRead:52, NettyDispatcher (io.netty.bootstrap)
decode:461, HttpObjectDecoder (io.netty.handler.codec.http) // diverges here, netty instrumentation starts a txn here for HTTP/1
decodeRemovalReentryProtection:529, ByteToMessageDecoder (io.netty.handler.codec)
callDecode:468, ByteToMessageDecoder (io.netty.handler.codec)
channelRead:290, ByteToMessageDecoder (io.netty.handler.codec)
invokeChannelRead:444, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:420, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:412, AbstractChannelHandlerContext (io.netty.channel)
channelRead:1410, DefaultChannelPipeline$HeadContext (io.netty.channel)
invokeChannelRead:440, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:420, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:919, DefaultChannelPipeline (io.netty.channel)
read:166, AbstractNioByteChannel$NioByteUnsafe (io.netty.channel.nio)
processSelectedKey:788, NioEventLoop (io.netty.channel.nio)
processSelectedKeysOptimized:724, NioEventLoop (io.netty.channel.nio)
processSelectedKeys:650, NioEventLoop (io.netty.channel.nio)
run:562, NioEventLoop (io.netty.channel.nio)
run:997, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:829, Thread (java.lang)

When making the HTTP/2 requests:

handle:130, VertxUtil$1 (com.nr.vertx.instrumentation)
handle:126, VertxUtil$1 (com.nr.vertx.instrumentation) // txn has to be started in netty before here, or vertx instrumentation will start it here for HTTP/2
emit:335, ContextImpl (io.vertx.core.impl)
emit:176, DuplicatedContext (io.vertx.core.impl)
dispatch:108, Http2ServerRequest (io.vertx.core.http.impl)
onHeaders:116, Http2ServerStream (io.vertx.core.http.impl)
onHeadersRead:183, Http2ServerConnection (io.vertx.core.http.impl)
onHeadersRead:208, Http2ConnectionBase (io.vertx.core.http.impl)
onHeadersRead:44, Http2ServerConnection (io.vertx.core.http.impl) // weaving this class in vertx instrumentation will allow us to start a transaction for HTTP/2
onHeadersRead:48, Http2FrameListenerDecorator (io.netty.handler.codec.http2)
onHeadersRead:48, Http2FrameListenerDecorator (io.netty.handler.codec.http2)
onHeadersRead:63, Http2EmptyDataFrameListener (io.netty.handler.codec.http2)
onHeadersRead:409, DefaultHttp2ConnectionDecoder$FrameReadListener (io.netty.handler.codec.http2)
processFragment:450, DefaultHttp2FrameReader$1 (io.netty.handler.codec.http2)
readHeadersFrame:457, DefaultHttp2FrameReader (io.netty.handler.codec.http2)
processPayloadState:253, DefaultHttp2FrameReader (io.netty.handler.codec.http2)
readFrame:159, DefaultHttp2FrameReader (io.netty.handler.codec.http2)
decodeFrame:173, DefaultHttp2ConnectionDecoder (io.netty.handler.codec.http2)
decodeFrame:63, DecoratingHttp2ConnectionDecoder (io.netty.handler.codec.http2)
decodeFrame:63, DecoratingHttp2ConnectionDecoder (io.netty.handler.codec.http2)
decode:393, Http2ConnectionHandler$FrameDecoder (io.netty.handler.codec.http2) // different unsupported netty decoder, netty instrumentation does not start a txn in this case
decode:453, Http2ConnectionHandler (io.netty.handler.codec.http2)
decodeRemovalReentryProtection:529, ByteToMessageDecoder (io.netty.handler.codec)
callDecode:468, ByteToMessageDecoder (io.netty.handler.codec)
channelRead:290, ByteToMessageDecoder (io.netty.handler.codec)
channelRead:415, VertxHttp2ConnectionHandler (io.vertx.core.http.impl)
invokeChannelRead:444, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:420, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:412, AbstractChannelHandlerContext (io.netty.channel)
unwrap:1471, SslHandler (io.netty.handler.ssl)
decodeJdkCompatible:1334, SslHandler (io.netty.handler.ssl)
decode:1383, SslHandler (io.netty.handler.ssl) // diverges here
decodeRemovalReentryProtection:529, ByteToMessageDecoder (io.netty.handler.codec)
callDecode:468, ByteToMessageDecoder (io.netty.handler.codec)
channelRead:290, ByteToMessageDecoder (io.netty.handler.codec)
invokeChannelRead:444, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:420, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:412, AbstractChannelHandlerContext (io.netty.channel)
channelRead:1410, DefaultChannelPipeline$HeadContext (io.netty.channel)
invokeChannelRead:440, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:420, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:919, DefaultChannelPipeline (io.netty.channel)
read:166, AbstractNioByteChannel$NioByteUnsafe (io.netty.channel.nio)
processSelectedKey:788, NioEventLoop (io.netty.channel.nio)
processSelectedKeysOptimized:724, NioEventLoop (io.netty.channel.nio)
processSelectedKeys:650, NioEventLoop (io.netty.channel.nio)
run:562, NioEventLoop (io.netty.channel.nio)
run:997, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:829, Thread (java.lang)

@kford-newrelic kford-newrelic added 5 Story Point Estimate and removed 3 Story Point Estimate labels Jul 8, 2024
@jasonjkeller
Copy link
Contributor Author

Here's a repro app that ultimately shed light on the situation https://github.com/jasonjkeller/Forgerock-Identity-Gateway-HTTP-2-Netty-Repro

@jasonjkeller
Copy link
Contributor Author

Issue has been resolved by the linked PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
5 Story Point Estimate apr-jun qtr Represents proposed work item for the Apr-Jun quarter
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants