[
https://issues.apache.org/jira/browse/HDDS-15255?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Andrey Yarovoy updated HDDS-15255:
----------------------------------
Summary: Ozone client shutdown waits 3 s for each Ratis channel that
doesn't close gracefully, one channel at a time (was: Timeouts on
ManagedChannels shutdown at the end ozone freon dfsg execution)
> Ozone client shutdown waits 3 s for each Ratis channel that doesn't close
> gracefully, one channel at a time
> -----------------------------------------------------------------------------------------------------------
>
> Key: HDDS-15255
> URL: https://issues.apache.org/jira/browse/HDDS-15255
> Project: Apache Ozone
> Issue Type: Bug
> Reporter: Andrey Yarovoy
> Assignee: Andrey Yarovoy
> Priority: Major
> Labels: pull-request-available
>
> *Problem*
> When a process using the Ozone client closes its FileSystem (explicitly or
> through Hadoop's `ClientFinalizer`
> shutdown hook), `XceiverClientManager.close()` closes every cached
> `XceiverClientRatis` **one at a time**. Each
> close ends in Ratis `GrpcUtil.shutdownManagedChannel()`, which waits up to
> **3 s** for the channel to terminate
> gracefully, then up to 2 s more after `shutdownNow()`. Both timeouts are
> hard-coded. Every channel that doesn't
> drain within the grace period adds 3 s to the exit, and they add up.
> Originally seen at the end of `ozone freon dfsg`. It also happens in ordinary
> Hadoop clients. Below, the TestDFSIO
> MapReduce client spends up to a minute exiting after its job has completed.
> *Evidence*
> Cluster: 12 datanodes, Ozone 2.2.0), Kerberos, `hdds.grpc.tls.enabled=true`,
> 72–74 RATIS/THREE
> pipelines. Client: `hadoop jar ... TestDFSIO -write|-read -nrFiles N -size
> 128MB` against `ofs://`.
> After `Job ... completed successfully`, the client logs one line every 3 s,
> then exits:
> ```
> 26/10/20 17:20:02 INFO mapreduce.Job: Job job_1792540199743_0014 completed
> successfully
> 26/10/20 17:20:02 INFO fs.TestDFSIO: ----- TestDFSIO ----- : write
> ...
> 26/10/20 17:20:05 WARN grpc.GrpcUtil: Timed out gracefully shutting down
> connection:
> ManagedChannelOrphanWrapper\{delegate=ManagedChannelImpl{logId=19,
> target=10.15.25.26:9858}}.
> 26/10/20 17:20:08 WARN grpc.GrpcUtil: Timed out gracefully shutting down
> connection:
> ManagedChannelOrphanWrapper\{delegate=ManagedChannelImpl{logId=137,
> target=10.15.25.39:9858}}.
> 26/10/20 17:20:11 WARN grpc.GrpcUtil: Timed out gracefully shutting down
> connection: ManagedChannelOrphanWrapper\{delegate=ManagedChannelImpl{logId=5,
> target=10.15.25.38:9858}}.
> ...
> 26/10/20 17:20:32 WARN util.ShutdownHookManager: ShutdownHook
> 'ClientFinalizer' timeout, java.util.concurrent.TimeoutException
> ...
> 26/10/20 17:20:56 WARN grpc.GrpcUtil: Timed out gracefully shutting down
> connection: ManagedChannelOrphanWrapper\{delegate=ManagedChannelImpl{logId=8,
> target=10.15.25.13:9858}}.
> ```
> Exit time after the job completed, across 15 client runs:
> | channels that timed out | exit time after job completion |
> |---|---|
> | 0 | 0–1 s |
> | 1 | 3–4 s |
> | 4–5 | 12–16 s |
> | 8 | 24 s |
> | 12–13 | 36–39 s |
> | 18 | 54 s |
> That's exactly **3.0 s per timed-out channel**. The count varies from run to
> run (0–18) for the same workload. Above
> 10 channels the 30 s `ClientFinalizer` hook timeout
> (`hadoop.service.shutdown.timeout`) fires, and the closing
> carries on past it.
> At scale: in a 840-job TestDFSIO, **25% of client runs (207 of 839) spent
> more than 15 s outside the job,
> about 45 s each, 2.6 h of the matrix's 13.1 h of wall time**. Applications
> with short-lived clients (CLI commands,
> Hive or Spark drivers, schedulers that launch many small processes) pay this
> on every exit. Map-task containers
> also close their FileSystem on exit and may hit it too. That would delay
> container release between task waves
> (not verified).
> *Code path (master)*
> ```
> XceiverClientManager.close()
> clientCache.invalidateAll(); clientCache.cleanUp(); // "closing is done
> through RemovalListener"
> removalListener.onRemoval() // one entry at a time, inside synchronized
> (clientCache)
> XceiverClientSpi.setEvicted() -> cleanup()
> XceiverClientRatis.close() -> RaftClient.close()
> GrpcClientProtocolClient.close() // Ratis: half-closes the streams, then
> GrpcUtil.shutdownManagedChannel(channel) // awaitTermination(3 s),
> shutdownNow(), awaitTermination(2 s)
> ```
> `awaitTermination` returns only when the channel's in-flight calls have
> finished, so a channel times out when the
> datanode hasn't completed the client's stream within 3 s of the half-close.
> Why some don't is not known yet.
> HDDS-15670 attributed it to server-side latency under a disconnect storm and
> couldn't reproduce it on a 3-datanode
> compose cluster; it reproduces readily on this 12-datanode cluster with TLS.
> *Proposed fix*
> 1. **Close in parallel on shutdown.** In `XceiverClientManager.close()`,
> collect the cached clients and close them
> concurrently on a bounded pool, so that exit costs about one grace period
> (3–5 s) instead of the sum of them. That
> also removes the per-close work from inside `synchronized (clientCache)`.
> 2. **Ratis follow-up (optional):** make the graceful-shutdown timeout
> configurable, or let `RaftClient.close()` skip
> the graceful wait, as HDDS-16812 also notes. A client that is exiting gains
> nothing from waiting for a drain.
> 3. **Investigate the datanode side:** why some client streams aren't
> completed within 3 s of the client's half-close.
> Interaction with HDDS-16812 (patch available): it moves eviction closes to a
> single background thread and makes
> `XceiverClientManager.close()` wait for pending closes. That fixes the writer
> stall, but on shutdown the closes
> would still be serial. Fix 1 should apply to the pending queue as well.
> *How to reproduce*
> On a multi-datanode cluster with RATIS/THREE pipelines, run a client that
> writes to many pipelines and then exits,
> and time the gap between its last operation and process exit:
> ```
> time hadoop jar hadoop-mapreduce-client-jobclient-*-tests.jar TestDFSIO -D
> fs.defaultFS=ofs://<om-service>/ \
> -D test.build.data=/<vol>/<ratis3-bucket>/TestDFSIO -libjars
> <ozone-filesystem-hadoop3.jar> \
> -write -nrFiles 1000 -size 128MB
> # or: ozone freon dfsg -n 10000 -t 160 -p
> ofs://<om-service>/<vol>/<bucket>/dfsg
> ```
> Then count the `Timed out gracefully shutting down connection` lines after
> the last operation; each costs 3 s.
> *Links*
> - relates to HDDS-16812 (same 3 s Ratis close, on cache eviction under the
> cache lock)
> - relates to HDDS-15670 (same warning, resolved Cannot Reproduce as log noise)
> - relates to HDDS-14474 (Freon dfsg FileSystem leak; fixed, not this)
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]