Jetty12 (Jakarta EE8) upgrade#18424
Conversation
| public static Handler getJettyRequestLogHandler() | ||
| { | ||
| // Ref: http://www.eclipse.org/jetty/documentation/9.2.6.v20141205/configuring-jetty-request-logs.html | ||
| RequestLogHandler requestLogHandler = new RequestLogHandler(); | ||
| requestLogHandler.setRequestLog(new JettyRequestLog()); | ||
|
|
||
| return requestLogHandler; | ||
| } |
There was a problem hiding this comment.
it looks like this is replaced with Server.setRequestLog in jetty 12, https://jetty.org/docs/jetty/12.1/programming-guide/migration/11-to-12.html#api-changes-handler-requestlog, do we need to add that somewhere like the server initializers class or something?
There was a problem hiding this comment.
💯 definitely a miss by not properly migrating this. I think initialization in JettyServerModule is the right spot? Confirmed that it was wired up across all druid services in my Docker env after moving it in latest commits.
| then | ||
| DOCKER_COMPOSE='docker-compose' | ||
| else | ||
| DOCKER_COMPOSE='docker compose' |
There was a problem hiding this comment.
shouldn't we prefer docker compose? i think docker-compose is pretty old now and hasn't been included in docker distribution for a while now
There was a problem hiding this comment.
heh, ya. I probably just need to fix my local setup and not use docker-compose. If nothing else I'll flip it to only fall back to docker-compose.
| On Java 11, if these parameters are not included, you will see warnings like the following: | ||
|
|
||
| ``` | ||
| WARNING: An illegal reflective access operation has occurred | ||
| WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations | ||
| WARNING: All illegal access operations will be denied in a future release | ||
| ``` | ||
|
|
There was a problem hiding this comment.
I think you still see these if you don't add the stuff, are we just assuming that people are used to it by now?
There was a problem hiding this comment.
ehh that was probably me just seeing Java 11 and not Java 11+ and hitting delete. I'll confirm it is still there and add back without the explicit java 11 part
There was a problem hiding this comment.
actually maybe removing them is right if java 17 is actually throwing exceptions without them like we indicate on line 66
|
@kfaraz Thank you for the initial review! I made some modifications to the initialization code and avatica handler per your review. Let me know if this is going down the lines of what you were thinking. |
kfaraz
left a comment
There was a problem hiding this comment.
Thanks for addressing the feedback, @capistrant !
I have left minor suggestions/queries in some places.
But none of those should block this PR.
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| # Determine if docker compose is available. If not, assume Docker supports |
There was a problem hiding this comment.
Does this change need to be included in this PR? Or can it be done separately too?
There was a problem hiding this comment.
I ended up removing it and will not PR it separately. My machine just had a bad setup for docker, I assume most people use docker compose > docker-compose these days so supporting legacy is not needed. Especially since we are phasing out legacy ITs
| <groupId>org.eclipse.jetty.ee8</groupId> | ||
| <artifactId>jetty-ee8-servlet</artifactId> | ||
| <version>${jetty.version}</version> | ||
| <exclusions> |
There was a problem hiding this comment.
Nit: indentation seems off here.
| // Keep Druid jetty jars out of the classpath. They are not runnable in the < 17 hadoop java runtime | ||
| if (jarFile.getName().endsWith(".jar") && !jarFile.getName().contains("jetty")) { |
There was a problem hiding this comment.
Could we use jetty-ee8-* instead?
| /** | ||
| * Needed for Hadoop indexing that needs server-like Injector but can't run jetty 12 | ||
| */ | ||
| @VisibleForTesting |
There was a problem hiding this comment.
I think this method is used by HadoopDruidIndexerConfig too. If that is the case, let's remove this annotation.
| return this.build(false); | ||
| } | ||
|
|
||
| public static Module registerNodeRoleModule(Set<NodeRole> nodeRoles) |
There was a problem hiding this comment.
It seems that this method is unchanged. Can we move it back to its original position so that we can avoid it from showing up in the diff?
| import org.apache.calcite.avatica.util.UnsynchronizedBuffer; | ||
| import org.eclipse.jetty.server.Handler; | ||
|
|
||
| public abstract class DruidAvaticaHandler extends Handler.Abstract implements MetricsAwareAvaticaHandler |
There was a problem hiding this comment.
Please add a short javadoc, if possible.
| public static final String AVATICA_PATH_NO_TRAILING_SLASH = "/druid/v2/sql/avatica-protobuf"; | ||
| public static final String AVATICA_PATH = AVATICA_PATH_NO_TRAILING_SLASH + "/"; | ||
|
|
||
| private final ProtobufHandler pbHandler; |
There was a problem hiding this comment.
| private final ProtobufHandler pbHandler; | |
| private final ProtobufHandler protobufHandler; |
| try (Timer.Context ctx = this.requestTimer.start()) { | ||
| if (!"POST".equals(request.getMethod())) { | ||
| response.setStatus(405); | ||
| response.write( | ||
| true, | ||
| ByteBuffer.wrap("This server expects only POST calls.".getBytes(StandardCharsets.UTF_8)), callback | ||
| ); | ||
| return true; | ||
| } | ||
| final byte[] requestBytes; | ||
| // Avoid a new buffer creation for every HTTP request | ||
| final UnsynchronizedBuffer buffer = threadLocalBuffer.get(); | ||
| try (InputStream inputStream = Content.Source.asInputStream(request)) { | ||
| requestBytes = AvaticaUtils.readFullyToBytes(inputStream, buffer); | ||
| } | ||
| finally { | ||
| buffer.reset(); | ||
| } | ||
|
|
||
| response.getHeaders().put("Content-Type", "application/octet-stream;charset=utf-8"); | ||
|
|
||
| org.apache.calcite.avatica.remote.Handler.HandlerResponse<byte[]> handlerResponse; | ||
| try { | ||
| handlerResponse = pbHandler.apply(requestBytes); | ||
| } | ||
| catch (Exception e) { | ||
| LOG.debug(e, "Error invoking request"); | ||
| handlerResponse = pbHandler.convertToErrorResponse(e); | ||
| } | ||
|
|
||
| response.setStatus(handlerResponse.getStatusCode()); | ||
| response.write(true, ByteBuffer.wrap(handlerResponse.getResponse()), callback); | ||
| return true; |
There was a problem hiding this comment.
I wonder if parts of this logic can also live in the super class DruidAvaticaHandler. Not a blocker for this PR though.
|
|
||
| // Default implementation is for JSON to allow debugging of tests. | ||
| protected AbstractAvaticaHandler getAvaticaHandler(final DruidMeta druidMeta) | ||
| protected Handler.Abstract getAvaticaHandler(final DruidMeta druidMeta) |
There was a problem hiding this comment.
| protected Handler.Abstract getAvaticaHandler(final DruidMeta druidMeta) | |
| protected DruidAvaticaHandler getAvaticaHandler(final DruidMeta druidMeta) |
|
|
||
| @Override | ||
| protected AbstractAvaticaHandler getAvaticaHandler(final DruidMeta druidMeta) | ||
| protected Handler.Abstract getAvaticaHandler(final DruidMeta druidMeta) |
There was a problem hiding this comment.
| protected Handler.Abstract getAvaticaHandler(final DruidMeta druidMeta) | |
| protected DruidAvaticaHandler getAvaticaHandler(final DruidMeta druidMeta) |
* jetty 10 upgrade * checkpoint * compiling but broken cuz of at least one dep calcite depending on jetty9 * Fix breakage in router * Compilation fixes after merging master in. plus getting checkstyle fixed up * Remove some of the avatica deps blocking jetty12 * bump jetty to latest and fixup licenses.yaml * fixup after merging master * Fixup some licenses reporting issues * remove jetty dependency from indexing hadoop in attempt to keep it alive * stop doing static checks and build with jdk11 * Modifications to index_hadoop to try and keep it alive * Modify duplicate header removal strategy * Remove dependency on non public jetty nested packages * Revert back to verbose and dirty Injector setup to get hadoop index fully working * Fix http trailers for QueryResultPusher * Fix trailer related tests in QueryResourceTest * add some UTs * prevent banned dep from getting pulled in * Run rewrite rules mvn goal to fixup test files * stop accounting for buggy mock impl in sql test * Add new http server config for Jetty UriCompliance mode. Default to allow backwards compatibility * fix import order * fix spell checker flag * Fixup java docs links to use java17 * Unify approach to jetty handler for avatica json and protobuf * use 405 response code for avatica jdbc non post requests * fix checkstyle * Add link for new jetty related config * fix grammar in java support doc * Make the legacy ITs easier to run in a wider variety of docker steps * Cleanup some of the Injector initialization code for hadoop tasks, based on review * Starting point for creating a DruidAvaticaHandler base class * Share a little bit of the code between the avatica handlers * Work to fix AvaticaHandler constructor issues * Fix codeql flag * Revert "Make the legacy ITs easier to run in a wider variety of docker steps" This reverts commit bafb2fc. * Add RequestLogger configuration back using proper jetty12 mechanism * Fix checkstyle * fix import order * Address review comments * fix serialization (cherry picked from commit 7a084e6)
Description
Upgrade to Jetty 12
Upgrades our jetty dependency to jetty 12.0.x (12.0.25 at time of writing). Uses Jakarta EE8 compatible jetty 12 to enable a less intrusive upgrade.
Avatica Changes
Calcite Avatica has a hard dependency on jetty9 still and there is no clear timeline on their upgrade plans. To avoid this being a blocker we have reduced our dependency footprint on Avatica in this PR by bringing the Jetty handler implementations for Druid JDBC while retaining compatibility with the Avatica JDBC client.
Hadoop Compatibility
Hadoop ecosystem also comes with lots of dependencies on jetty9 and java11 support. This section lays out implications for hadoop support
Deep storage
Confirmed functionality using Docker IT env
index_hadoop
Confirmed functionality using Docker IT env. We will want more expansive testing here. I tried to slim down the code that sets up the injector, but since the task needs to load all of the extensions, I ended up falling back to an ugly duplication of the service injector creation, just without jetty. I'm sure it can be improved if we want to.
Java 11 Support Implications
Jetty12 deps are in java 17 class file version, so running druid services on java11 seems out of the question. If this is the case, java 11 support will have to be dropped in 35.
Future Work
Release note
Upgrading Druid to Jetty 12 requires dropping Java 11 runtime support for Druid. The one exception to this is that Hadoop Ingestion can continue to run on Java 11 YARN clusters because the Jetty 12 dependency can be excluded from that runtime classpath safely.
A new server configuration option has been added with this PR:
druid.server.http.uriCompliance. Jetty 12 by default has strict enforcement ofRFC3986URI format. This is a change from Jetty 9. To retain compatibility with legacy Druid, we default this config toLEGACY, which uses the more permissive URI format enforcement that jetty9 used. If the cluster you operate does not require LEGACY compatibility, it is recommended to use the upstream jetty default ofRFC3986in your Druid deployment. Please see jetty documentation for more info.Upgrade Note
Java 11 runtime no longer supported. Java 17 is the only officially supported and recommended runtime environment for Druid 35
Key changed/added classes in this PR
PR is mostly a lot of tiny changes and tweaks. But some places to get close look could be:
This PR has: