Andrey Yarovoy created HDDS-17036:
-------------------------------------

             Summary: Pipeline EC stripe writes: several stripes in flight per 
key, without a per-stripe WriteChunk barrier
                 Key: HDDS-17036
                 URL: https://issues.apache.org/jira/browse/HDDS-17036
             Project: Apache Ozone
          Issue Type: Improvement
          Components: EC Client
            Reporter: Andrey Yarovoy


**Problem**

The EC client writes one stripe at a time. Before moving to the next stripe, it 
waits for every WriteChunk ack, and
with J2 for PutBlock only every N stripes. The stripe queue 
(`ozone.client.ec.stripe.queue.size`) only buffers
encoded stripes; it doesn't overlap their transfer. So a single key's 
throughput is bounded by stripe size divided
by the slowest datanode's round trip plus service time. Raising the queue size 
doesn't help: going from 2 to 8
only moved work into `close()`.

**Evidence** (WriteChunk-ack wait, share of flush-thread busy time)

| Environment | WriteChunk-ack wait |
|---|---|
| Real cluster, RTT 0.05 ms, TLS | 31% |
| Local mini-cluster | 33% |

That is about 1.6 ms per stripe on the real cluster, even at 0.05 ms RTT. The 
wait grows with RTT: one round trip
per stripe for WriteChunk, plus PutBlock.

**Proposal**
1. Allow up to W stripes in flight per key, with a new setting. W = 1 is 
today's behaviour.
2. Keep every datanode receiving its cells in order. 
`FilePerBlockStrategy.writeChunk` rejects a non-overwrite
chunk whose offset doesn't equal the current block file length 
(`ChunkUtils.validateChunkSize`,
`CHUNK_FILE_INCONSISTENCY`).
- Today `XceiverClientGrpc.sendCommandAsync` opens a new gRPC stream per 
request, so two in-flight requests to
the same datanode can be handled out of order.
- Use **one long-lived bidirectional gRPC stream per (block, datanode)** for 
the key's WriteChunks. gRPC
delivers messages on one stream in order, and `GrpcXceiverService` processes a 
stream's requests in order.
3. Track acks per stripe, and release a stripe's buffers when all its cells are 
acknowledged and it is covered by a PutBlockĀ 
4. On failure, rewrite from the last successful PutBlock, reusing J2's logic. 
That bounds buffered data to about
W + N stripes per key.

**Projected effect**
- Removes WriteChunk round trips from the per-stripe critical path. The flush 
thread then is limited by its own CPU work , and the writer thread by encoding.
- Larger gains at higher RTT, for example across racks or zones.
**Compatibility**
- Client-only.
- The long-lived stream uses the existing `XceiverClientProtocolService` 
bidirectional `send` RPC, so no wire
change. Verify against old datanodes.

**Testing**
- Ordering: unit and integration tests with W > 1 that must never trigger 
`CHUNK_FILE_INCONSISTENCY`.
- Failure injection at every stage: WriteChunk failure in stripe k while k+1 is 
in flight; PutBlock failure;
datanode restart.
- Read-back verification.
- Benchmarks: `TestEcWriteBenchmark` W-arm, freon at 1/4/16 threads, and with 
added network delay (netem) to confirm the RTT sensitivity.



--
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