[ 
https://issues.apache.org/jira/browse/HDDS-14949?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Andrey Yarovoy updated HDDS-14949:
----------------------------------
    Issue Type: Improvement  (was: Bug)

> GrpcOmTransport should use shaded netty version from Ratis
> ----------------------------------------------------------
>
>                 Key: HDDS-14949
>                 URL: https://issues.apache.org/jira/browse/HDDS-14949
>             Project: Apache Ozone
>          Issue Type: Improvement
>            Reporter: Andrey Yarovoy
>            Assignee: Andrey Yarovoy
>            Priority: Major
>              Labels: pull-request-available
>
> *Problem*
> The OM gRPC path (`GrpcOzoneManagerServer` on OM and `GrpcOmTransport` in S3 
> Gateway) is the only main RPC path that still uses unshaded `io.grpc` / 
> `io.netty`. Every other gRPC path (datanode `XceiverServerGrpc` / 
> `XceiverClientGrpc`, container replication, inter-SCM, Ratis) uses the 
> ratis-thirdparty shaded copy. As a result:
> - **No native epoll.** The dist ships the unshaded 
> `netty-transport-native-epoll` jar without its `linux-*` classifier, so it 
> has no `.so`. Unshaded `Epoll.isAvailable()` is therefore always `false`, and 
> `GrpcOzoneManagerServer` hard-codes `NioEventLoopGroup` / 
> `NioServerSocketChannel` anyway. The shaded copy (`ratis-thirdparty-misc`) 
> already bundles the epoll natives for `x86_64` and `aarch_64`.
> - **Two Netty/gRPC stacks per JVM in OM and S3 Gateway:** two sets of pooled 
> allocators, two sets of default event-loop threads, and two tcnative loads.
> - **Dist and client classpath weight.** The dist carries the unshaded 
> `grpc-*` and `netty-*` jars plus five `netty-tcnative-boringssl-static` 
> classifier jars, all with matching `jar-report.txt` / `LICENSE.txt` entries. 
> Applications that put the unshaded Ozone client on their classpath also pull 
> unshaded `io.grpc` / `io.netty` in transitively.
> *Why moving to shaded gRPC is not a simple package rename*
> `OMRequest` / `OMResponse` are generated with unshaded `com.google.protobuf` 
> (`hadoop-ozone/interface-client`, protobuf `${protobuf.version}`) and are 
> shared with the Hadoop RPC path and the whole OM request pipeline. The 
> `protoc-gen-grpc-java` stub `OzoneManagerServiceGrpc` builds its method 
> descriptor with 
> `io.grpc.protobuf.ProtoUtils.marshaller(OMRequest.getDefaultInstance())`. The 
> shaded `ProtoUtils` requires a *shaded* protobuf `Message`, so rewriting 
> `io.grpc` to the shaded prefix in the generated code (as 
> `hadoop-hdds/interface-client` does) does not compile. Moving the OM protos 
> to shaded protobuf is out of scope.
> *Proposed change*
> Replace the generated gRPC stub with a small hand-written binding that uses 
> shaded gRPC and keeps the unshaded `OMRequest` / `OMResponse` messages.
> 1. **Method descriptor and marshaller** (new class in `hadoop-ozone/common`, 
> e.g. `OzoneManagerServiceGrpcBinding`):
> - A shaded `MethodDescriptor<OMRequest, OMResponse>` of type `UNARY` with 
> full method name **`hadoop.ozone.OzoneManagerService/submitRequest`**. This 
> must match the name the generated stub uses today, so the wire format is 
> unchanged.
> - `Marshaller<T>` for both messages:
> - `stream(T)`: returns an `InputStream` that also implements shaded 
> `io.grpc.KnownLength`, so gRPC can frame the message without buffering it 
> first. Write the message with `writeTo` / `toByteArray`.
> - `parse(InputStream)`: `OMRequest.parser().parseFrom(...)` / 
> `OMResponse.parser().parseFrom(...)` on the unshaded messages.
> - A `ServerServiceDefinition` builder for the server side, using 
> `ServerCalls.asyncUnaryCall`, and a blocking call helper for the client side, 
> using `ClientCalls.blockingUnaryCall`.
> 2. **OM server:**
> - `OzoneManagerServiceGrpc` (ozone-manager) implements the handler against 
> the new binding instead of extending the generated 
> `OzoneManagerServiceImplBase`.
> - `GrpcOzoneManagerServer` switches to shaded `NettyServerBuilder`, picks 
> `EpollEventLoopGroup` / `EpollServerSocketChannel` when `Epoll.isAvailable()` 
> is true (falling back to NIO, mirroring `XceiverServerGrpc`), and logs the 
> selected channel type.
> - TLS uses the shaded `GrpcSslContexts` with 
> `SecurityConfig.getGrpcSslProvider()`, as on the datanode.
> 3. **Client:** `GrpcOmTransport` and `GrpcOMFailoverProxyProvider` move to 
> shaded `NettyChannelBuilder` / `ManagedChannel` / `Status`, call through the 
> binding, and use shaded TLS classes.
> 4. **Interceptors:** move `ClientAddressServerInterceptor`, 
> `ClientAddressClientInterceptor` and `GrpcClientConstants` (ozone-common), 
> and `GrpcMetricsServer\{Request,Response}Interceptor` and 
> `GrpcMetricsServerTransportFilter` (hdds-framework), to shaded `io.grpc`.
> 5. **Build:**
> - Drop the `grpc-java` plugin execution from `hadoop-ozone/interface-client` 
> so the unshaded `OzoneManagerServiceGrpc` stops being generated. Protobuf 
> message generation is unchanged.
> - Remove unshaded `io.grpc` / `io.netty` dependencies from `ozone-common`, 
> `ozone-manager`, `hdds-framework` and `s3gateway` where they become unused.
> 6. **Dist (follow-up or same PR):** remove the unshaded `grpc-*` / `netty-*` 
> / `netty-tcnative-*` jars and their `jar-report.txt` / `LICENSE.txt` entries 
> only if `dependency:tree` on the dist shows nothing else needs them at 
> runtime.
> *Compatibility*
> - **Wire:** unchanged. Shading only changes Java class names, and the method 
> name and message bytes stay the same. A mixed-version S3 Gateway and OM 
> interoperate in both directions, and rolling upgrade is unaffected.
> - **Proto / RPC:** no `.proto` changes. Only the generated gRPC stub class is 
> removed. It is internal (used only by OM and `GrpcOmTransport`).
> - **Config:** no new keys. The existing `ozone.om.grpc.*` keys (boss/worker 
> group size, port, max message size) keep their meaning.
> *Risks / trade-offs*
> - **Netty and gRPC versions follow ratis-thirdparty.** Ozone pins unshaded 
> Netty `4.1.136.Final`, but ratis-thirdparty ships `4.1.130.Final`, so this 
> path moves back 6 patch releases. Future Netty / gRPC security fixes for OM 
> gRPC then need a ratis-thirdparty release first.
> - **Netty system properties may stop applying.** Shading probably also 
> relocates `io.netty.*` system-property names, so any `-Dio.netty.*` JVM flags 
> operators use for OM / S3 Gateway would stop affecting this path. Verify 
> before documenting.
> - **Test utilities are missing from the shaded jar.** `ratis-thirdparty-misc` 
> does not ship shaded `grpc-inprocess` or `grpc-testing`. 
> `TestS3GrpcOmTransport` and `TestGrpcOmTransportConcurrentFailover` use 
> `InProcess\{Server,Channel}Builder` and `GrpcCleanupRule`, and need to switch 
> to a shaded `NettyServerBuilder` on an ephemeral localhost port with explicit 
> shutdown in `@AfterEach`.
> - **Overlap:** HDDS-16740 / HDDS-16741 touch the same `GrpcMetrics*` 
> interceptors. Land those first or rebase on top of them.
> *Testing*
> - Unit tests:
> - marshaller round-trip for `OMRequest` / `OMResponse`, including a payload 
> near `ozone.om.grpc.maximum.response.length`
> - the `MethodDescriptor` full name equals the old generated 
> `OzoneManagerServiceGrpc.getSubmitRequestMethod().getFullMethodName()`, 
> checked once against the old stub before removing it
> - Ported `TestS3GrpcOmTransport` / `TestGrpcOmTransportConcurrentFailover`; 
> existing S3 Gateway integration tests and the `TestS3SDK` suite.
> - Secure compose cluster (gRPC TLS on): S3 Gateway → OM traffic works; 
> mixed-version check with an old S3 Gateway against a new OM and the reverse.
> - Linux: OM log shows `EpollServerSocketChannel`; jstack shows epoll 
> event-loop threads in OM and S3 Gateway and no unshaded `io.netty` threads.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to