Navigation Menu

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

[FLINK-9386] Embed netty router #6031

Closed
wants to merge 2 commits into from
Closed

Conversation

pnowojski
Copy link
Contributor

This replaces netty-router dependency with our own version of it, which is simplified and adds guarantees about order of matching router patterns.

This is a prerequisite for https://issues.apache.org/jira/browse/FLINK-3952 . netty-router 1.10 is incompatible with Netty 4.1, while netty-router 2.2.0 brakes a compatibility in a way that we were unable to use it.

Verifying this change

This change ports part of the netty-router code, including tests and adds a test for preserving patter matching order by the Router. Additionally this change is covered by various of our ITCases.

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): (yes / no)
  • The public API, i.e., is any changed class annotated with @Public(Evolving): (yes / no)
  • The serializers: (yes / no / don't know)
  • The runtime per-record code paths (performance sensitive): (yes / no / don't know)
  • Anything that affects deployment or recovery: JobManager (and its components), Checkpointing, Yarn/Mesos, ZooKeeper: (yes / no / don't know)
  • The S3 file system connector: (yes / no / don't know)

Documentation

  • Does this pull request introduce a new feature? (yes / no)
  • If yes, how is the feature documented? (not applicable / docs / JavaDocs / not documented)

@pnowojski pnowojski force-pushed the f9386 branch 2 times, most recently from 5f98447 to 018b6ef Compare May 17, 2018 10:28
Copy link
Contributor

@uce uce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • I checked the copied classes and compared them to the originals. The simplications/merges look good to me and make a lot of sense. I also like the renamings. 👍

  • I've manually checked that registration order is respected. We still need to manually make sure that we register the handlers in the correct order. In the legacy WebRuntimeMonitor this was accidental as far as I can tell. In the new RestServerEndpoint we explicitly sort them before registering:

    Collections.sort(handlers, RestHandlerUrlComparator.INSTANCE);
    

    I'm wondering whether we should make this fact more explicit by adding comments to the add* methods in Router. Another approach is the Routes builder I mentioned as an inline comment.

  • I've furthermore build the project and check that job submission via REST and other endpoints for the web UI work as expected.

  • Do we file a follow up ticket to remove netty-router from our shaded Netty? Optionally, we might consider adding an import suppression for org.apache.flink.shaded.netty4.io.netty.handler.codec.http.router.* to guard against any accidental usage until we remove the dependency.

  • I don't know what your opinion is on cleaning up the copied classes. I'm OK with keeping everything as is, but I get a bunch of minor/trivial warnings about the code (like code visibility, unchecked calls, unused variables, etc.). I understand if we want to stay close to the copied classes.

import static java.util.Objects.requireNonNull;

/**
* This class replaces the standard error response to be identical with those sent by the {@link AbstractRestHandler}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/**
* This class replaces the standard error response to be identical with those sent by the {@link AbstractRestHandler}.
*/
public class RouterHandler extends SimpleChannelInboundHandler<HttpRequest> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've verified that this class merges the behaviour of Handler and AbstractHandler. 👍

Since we copied the code, we might leave it as is, but I noticed the following minor things (there are similar warnings in the other copied classes):

  • L46, L47: fields can be private
  • L62: throws Exception can be removed
  • L98: I get a unchecked call warning for RouteResult. We could use <?> to get rid of it I think

import java.util.Map.Entry;

/**
* This is adopted and simplified code from tv.cntt:netty-router library. For more information check {@link Router}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private static final Logger log = LoggerFactory.getLogger(MethodlessRouter.class);

// A path pattern can only point to one target
private final Map<PathPattern, T> routes = new LinkedHashMap<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the LinkedHashMap is what preserves the order of adding handlers, right? Or is there another thing that I've missed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please correct me if I'm wrong but I have a question regarding memory visibility: The thread that updates this map and the Netty event loop threads are different, so there might theoretically be a memory visibility issue if routes are added after the router has been passed to the RouterHandler. I don't think that we do this currently, but the API theoretically allows it. I'm wondering whether it makes sense to make the routes immutable, maybe something like creating the routes with a builder:

Routes routes = new RoutesBuilder()
  .addGet(...)
  ...
  .build();
Router router = new Router(routes);

Or use a thread-safe map here that also preserves ordering (maybe wrap using synchronizedMap).


Since we currently rely on correct registration order (e.g. /jobs/overview before /jobs/:id for correct matching), the immutable approach would allow us to include a utility in Routes that sorts pattern as done in RestServerEndpoint:143:

Collections.sort(handlers,RestHandlerUrlComparator.INSTANCE);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced that embedding the sorting logic inside router is good idea. Now it's clear that order of adding methods matter and it should be handled by the caller. If we provide sorting option, it can add confusion, especially because it can not be mandatory option - our sorting based on number of parameters is just a hack that kind of works with our patterns at the moment, but there are corner cases that would have to be "sorted"/"ordered" manually. Like patterns:

/jobs/foo/:B
/jobs/:A/bar

Which one of it should be matched to url /jobs/foo/bar?

Regarding thread safety, this class is just simply not thread safe, and it should be the user's responsibility to handle it appropriately. On the other hand, turning it into immutable would hardcode some assumption and prevent some possible use cases and I'm not sure if that's worth the effort (it would add some substantial boiler plate code in storing intermediate builder's state, without clear benefits for the future since this code hasn't changed much for last couple of years). Don't get me wrong, the builder approach is nicer (regardless of sorting/immutability), but I'm just not sure if it's worth the extra effort.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine with me to not invest more time into this and keep it as is 👍

}
}

channelHandlerContext.fireChannelRead(new RoutedRequest(routeResult, httpRequest).retain());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it makes sense to move new RoutedRequest(routeResult, httpRequest).retain() to a separate line? I was wondering whether it is retained as in the original handler, because I missed the retain() here.

I find the following clearer, but feel free to ignore:

RoutedRequest request = new RoutedRequest(routeResult, httpRequest);
request.retain();
channelHandlerContext.fireChannelRead(request);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed into

RoutedRequest<?> request = new RoutedRequest<>(routeResult, httpRequest);
channelHandlerContext.fireChannelRead(request.retain());

I like having .retain() calls to be in the same line where they are actually designed for, since it's kind of self documenting which line is the reason behind retaining.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

CompletableFuture<FullHttpResponse> responseFuture;
RouteResult result = routedRequest.getRouteResult();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if you do RouteResult<?> result = routedRequest.getRouteResult(); you don't need the cast to Set<String> in lines 101 and 106.

* <p>The pattern will be broken to tokens, example:
* {@code ["constant1", ":variable", "constant2", ":*"]}
*/
final class PathPattern {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*
* <p>Result of calling {@link Router#route(HttpMethod, String)}.
*/
public class RouteResult<T> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import java.util.Set;

/**
* This is adopted and simplified code from tv.cntt:netty-router library. Compared to original version this one
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pnowojski
Copy link
Contributor Author

Thanks for the review and manual checks! I either addressed your comments in fixup commit and left comment responses otherwise.

Do we file a follow up ticket to remove netty-router from our shaded Netty? Optionally, we might consider adding an import suppression for org.apache.flink.shaded.netty4.io.netty.handler.codec.http.router.* to guard against any accidental usage until we remove the dependency.

I planned to upgrade netty and drop netty-router in one step of upgrading flink-shaded-netty. Do you think it should be split somehow?

I don't know what your opinion is on cleaning up the copied classes. I'm OK with keeping everything as is, but I get a bunch of minor/trivial warnings about the code (like code visibility, unchecked calls, unused variables, etc.). I understand if we want to stay close to the copied classes.

I would be open to clean it up as we think it's best. I do not see a point in maintaining compatibility with the original sources. If you have other such comments, please feel free to write them.

@uce
Copy link
Contributor

uce commented May 23, 2018

I planned to upgrade netty and drop netty-router in one step of upgrading flink-shaded-netty. Do you think it should be split somehow?
No, if the ticket for upgrading covers that, we are all good.

👍 to merge. Thanks for taking care of this. Looking forward to finally have a recent Netty version.

This commit replaces netty-router dependency with our own version of it, which is
simplified and adds guarantees about order of matching router patterns.

This is a prerequisite for FLINK-3952. netty-router 1.10 is incompatible with
Netty 4.1, while netty-router 2.2.0 brakes a compatibility in a way that we
were unable to use it.
@pnowojski
Copy link
Contributor Author

pnowojski commented May 24, 2018

Thanks :) I have squashed commits and rebased the PR on latest master. Let's maybe wait for the final green travis before merging.

@asfgit asfgit closed this in a5fa093 May 28, 2018
pnowojski added a commit to dataArtisans/flink that referenced this pull request Jun 29, 2018
This commit replaces netty-router dependency with our own version of it, which is
simplified and adds guarantees about order of matching router patterns.

This is a prerequisite for FLINK-3952. netty-router 1.10 is incompatible with
Netty 4.1, while netty-router 2.2.0 brakes a compatibility in a way that we
were unable to use it.

This closes apache#6031.
NicoK pushed a commit to dataArtisans/flink that referenced this pull request Jul 9, 2018
This commit replaces netty-router dependency with our own version of it, which is
simplified and adds guarantees about order of matching router patterns.

This is a prerequisite for FLINK-3952. netty-router 1.10 is incompatible with
Netty 4.1, while netty-router 2.2.0 brakes a compatibility in a way that we
were unable to use it.

This closes apache#6031.
NicoK pushed a commit to dataArtisans/flink that referenced this pull request Jul 9, 2018
This commit replaces netty-router dependency with our own version of it, which is
simplified and adds guarantees about order of matching router patterns.

This is a prerequisite for FLINK-3952. netty-router 1.10 is incompatible with
Netty 4.1, while netty-router 2.2.0 brakes a compatibility in a way that we
were unable to use it.

This closes apache#6031.
sampathBhat pushed a commit to sampathBhat/flink that referenced this pull request Jul 26, 2018
This commit replaces netty-router dependency with our own version of it, which is
simplified and adds guarantees about order of matching router patterns.

This is a prerequisite for FLINK-3952. netty-router 1.10 is incompatible with
Netty 4.1, while netty-router 2.2.0 brakes a compatibility in a way that we
were unable to use it.

This closes apache#6031.
NicoK pushed a commit that referenced this pull request Jan 24, 2019
This commit replaces netty-router dependency with our own version of it, which is
simplified and adds guarantees about order of matching router patterns.

This is a prerequisite for FLINK-3952. netty-router 1.10 is incompatible with
Netty 4.1, while netty-router 2.2.0 brakes a compatibility in a way that we
were unable to use it.

This closes #6031.

Signed-off-by: Nico Kruber <nico@data-artisans.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants