devmadhuu commented on PR #10074:
URL: https://github.com/apache/ozone/pull/10074#issuecomment-4325120080

   > Thanks a lot @devmadhuu for the detailed explanation and continuous 
efforts in handling this.
   > 
   > **General comments:**
   > 
   >     1. IIUC, `Full snapshot` is a costly operation and the cost vary 
depends on the SCM database size, I'd suggest `not to trigger automatic 
FULL_SNAP `instead analyze the overhead of snapshot datatransfer, snapshot 
loading, GC Pressure & potential system resource utilization based on existing 
known SCM database size(say if the database size is 275GB and 300M containers). 
Then will think about the solution and proposal to the users.
   > 
   >     2. Could you please come up with the set of meaningful metrics to 
understand the TARGETED_SYNC. For example, per state based metrics which can be 
used by the users/customers to determine the nonOpenDrift acceptable 
discrepancies and tune the TARGETED_SYNC interval. Another one can be the time 
taken etc.
   > 
   >     3. Can we think of a warning or alert if the decrecepencies grows 
beyond certain threshold or limit?
   > 
   > 
   > Something like, non_open_container_decrecepencies <= 10K and the 
TARGETED_SYNC interval is 1hr
   > 
   > ```
   > Apr 22nd 00:01 AM : non_open_container_decrecepencies 10K
   > Apr 22nd 00:02 AM : non_open_container_decrecepencies 5K
   > Apr 22nd 00:03 AM : non_open_container_decrecepencies 15K WARN
   > Apr 22nd 00:04 AM : non_open_container_decrecepencies 12K WARN
   > Apr 22nd 00:05 AM : non_open_container_decrecepencies 2K
   > Apr 22nd 00:06 AM : non_open_container_decrecepencies 2K
   > Apr 22nd 00:07 AM : non_open_container_decrecepencies 2K
   > ```
   
   Yes,  full SCM DB snapshot download is a time consuming with high latency 
operation. As we have experienced, some large clusters can even reach with 500+ 
GB of SCM DB and continue to grow, so it is always good to avoid this full SCM 
DB download situation and keep doing `TARGETED_SYNC`  at regular intervals with 
default interval of 1H which is configurable.
   
   **`How we arrive at every 1 hour check of determining sync action -> 
`TARGETED_SYNC` or FULL SCM DB SNAPSHOT download. ?`**
     — We arrived based on below math for 100 million containers and impact of 
syncing in Recon by making RPC calls from Recon to SCM every 1 hour and why it 
is justified.
     — In high concurrent clusters with high workload, if we increase the 
frequency from 1 hour to 2 hours, we may observe the increase in discrepancy of 
containers between SCM and Recon in worst case, so this may force full snapshot 
download which we want to avoid.
   
   **`Why we need this `TARGETED_SYNC` every 1H when Recon is already having 
logic of processing of DN container reports which is an existing behvaior in 
Recon` and why those existing ICR and FCRs are not sufficient for SCM-only 
containers.?**
   - ICR and periodic FCR do not guarantee Recon will learn about every SCM 
container.
   - A container can exist in SCM but never appear in DN reports if the client 
fails before any replica is created or before DNs persist/report it.
   - In that case, Recon can miss an OPEN empty container entirely.
   - Later, SCM may keep that container OPEN for some time and eventually move 
it toward deletion, while Recon still has no signal from DN-side reporting.
   - That is exactly the class of drift this SCM-driven sync is meant to repair.
   
   **# Recon SCM Sync Latency Projections**
   
   ## Scope
   
   This note derives projected latency, RPC count, transfer volume, and SCM 
heap impact for Recon syncing container IDs from SCM using a batch size of 
`500,000` container IDs per RPC.
   
   The math is based on the following observed log sample from Recon:
   
   ```text
   /var/log/hadoop-ozone/ozone-recon.log:2026-03-18 10:41:40,896 WARN 
[pool-53-thread-1]-org.apache.hadoop.ozone.recon.scm.ReconStorageContainerSyncHelper:
 BASELINE: Starting sync - totalContainers=123409, batchSize=123409
   /var/log/hadoop-ozone/ozone-recon.log:2026-03-18 10:41:41,269 WARN 
[pool-53-thread-1]-org.apache.hadoop.ozone.recon.scm.ReconStorageContainerSyncHelper:
 BASELINE: Sync complete - totalTime=516ms, rpcCalls=1, avgRpcTime=283ms, 
totalRpcTime=283ms, newContainers=0
   ```
   
   ## Code References
   
   The sizing assumption for one serialized `ContainerID` comes from:
   
   - 
[ReconStorageContainerSyncHelper.java](/Users/deveshsingh/Downloads/Ozone/workspace/fork/ozone/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconStorageContainerSyncHelper.java:81)
   
   The batch-size logic comes from:
   
   - 
[ReconStorageContainerSyncHelper.java](/Users/deveshsingh/Downloads/Ozone/workspace/fork/ozone/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconStorageContainerSyncHelper.java:714)
   
   The SCM RPC serving the state-filtered container ID list comes from:
   
   - 
[SCMClientProtocolServer.java](/Users/deveshsingh/Downloads/Ozone/workspace/fork/ozone/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java:1563)
   
   The SCM side state-map list creation comes from:
   
   - 
[ContainerStateMap.java](/Users/deveshsingh/Downloads/Ozone/workspace/fork/ozone/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java:270)
   
   The protobuf response building on SCM comes from:
   
   - 
[StorageContainerLocationProtocolServerSideTranslatorPB.java](/Users/deveshsingh/Downloads/Ozone/workspace/fork/ozone/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/StorageContainerLocationProtocolServerSideTranslatorPB.java:1442)
   
   ## Assumptions
   
   1. Each serialized `ContainerID` on the wire is approximately `12 bytes`.
   
   Formula:
   
   ```text
   size_per_container_id = 12 bytes
   ```
   
   2. The proposed application-level batch size is:
   
   ```text
   batch_size = 500,000 container IDs per RPC
   ```
   
   3. The latency sample is treated as a baseline for linear projection:
   
   ```text
   baseline_container_count = 123,409
   baseline_rpc_calls = 1
   baseline_avg_rpc_time = 283 ms
   baseline_total_time = 516 ms
   ```
   
   4. Two time models are projected:
   
   - `RPC time only`
     Uses `avgRpcTime=283ms` from the log.
   - `End-to-end sync time`
     Uses `totalTime=516ms` from the log.
   
   5. These projections are for the state-list RPC that transfers container IDs,
      not full `ContainerWithPipeline` metadata payloads.
   
   ## Maximum Theoretical IDs Per 128 MB RPC
   
   If we only consider the serialized wire size:
   
   ```text
   max_rpc_message_size = 128 MB
                          = 128 * 1024 * 1024
                          = 134,217,728 bytes
   
   max_container_ids_per_128mb_rpc =
       134,217,728 / 12
     = 11,184,810.67
   ```
   
   Therefore:
   
   ```text
   max_container_ids_per_128mb_rpc ~= 11.18 million
   ```
   
   This is only a wire-size upper bound. It is not a recommended operational
   batch size because SCM serialization cost, protobuf object creation, and
   transient heap pressure grow with the list size.
   
   ## Proposed Operational Batch Size
   
   Proposed batch size:
   
   ```text
   batch_size = 500,000
   ```
   
   This yields per-RPC wire payload:
   
   ```text
   payload_per_rpc_bytes = 500,000 * 12
                         = 6,000,000 bytes
   ```
   
   Conversions:
   
   ```text
   payload_per_rpc_decimal_mb = 6,000,000 / 1,000,000 = 6.0 MB
   payload_per_rpc_binary_mib = 6,000,000 / 1,048,576 = 5.72 MiB
   ```
   
   So:
   
   ```text
   payload_per_rpc ~= 6.0 MB ~= 5.72 MiB
   ```
   
   ## Baseline-Derived Time Per Container
   
   ### RPC Time Only
   
   Using:
   
   ```text
   baseline_avg_rpc_time = 283 ms
   baseline_container_count = 123,409
   ```
   
   Per-container RPC time:
   
   ```text
   rpc_time_per_container =
       283 ms / 123,409
     = 0.0022931878 ms
     = 2.2931878 microseconds
   ```
   
   ### End-to-End Sync Time
   
   Using:
   
   ```text
   baseline_total_time = 516 ms
   baseline_container_count = 123,409
   ```
   
   Per-container end-to-end time:
   
   ```text
   total_time_per_container =
       516 ms / 123,409
     = 0.0041804077 ms
     = 4.1804077 microseconds
   ```
   
   ## Time Per 500K RPC
   
   ### RPC Time Only
   
   ```text
   rpc_time_per_500k =
       500,000 * 0.0022931878 ms
     = 1,146.5939 ms
     = 1.1466 s
   ```
   
   ### End-to-End Sync Time
   
   ```text
   total_time_per_500k =
       500,000 * 0.0041804077 ms
     = 2,090.2039 ms
     = 2.0902 s
   ```
   
   ## General Projection Formulas
   
   For any container count `N`:
   
   ### Number of RPC Calls
   
   ```text
   rpc_calls(N) = ceil(N / 500,000)
   ```
   
   ### Total Transfer Volume
   
   ```text
   transfer_bytes(N) = N * 12
   ```
   
   ### Projected RPC Time Only
   
   ```text
   projected_rpc_time_ms(N) =
       N * (283 / 123,409)
   ```
   
   ### Projected End-to-End Sync Time
   
   ```text
   projected_total_time_ms(N) =
       N * (516 / 123,409)
   ```
   
   ## 4 Million Containers
   
   ### RPC Calls
   
   ```text
   rpc_calls =
       ceil(4,000,000 / 500,000)
     = 8
   ```
   
   ### Transfer Volume
   
   ```text
   transfer_bytes =
       4,000,000 * 12
     = 48,000,000 bytes
   
   transfer_decimal_mb = 48,000,000 / 1,000,000 = 48 MB
   transfer_binary_mib = 48,000,000 / 1,048,576 = 45.78 MiB
   ```
   
   ### RPC Time Only
   
   ```text
   projected_rpc_time_ms =
       4,000,000 * (283 / 123,409)
     = 9,172.7511 ms
     = 9.17 s
   ```
   
   ### End-to-End Sync Time
   
   ```text
   projected_total_time_ms =
       4,000,000 * (516 / 123,409)
     = 16,721.6312 ms
     = 16.72 s
   ```
   
   ## 10 Million Containers
   
   ### RPC Calls
   
   ```text
   rpc_calls =
       ceil(10,000,000 / 500,000)
     = 20
   ```
   
   ### Transfer Volume
   
   ```text
   transfer_bytes =
       10,000,000 * 12
     = 120,000,000 bytes
   
   transfer_decimal_mb = 120 MB
   transfer_binary_mib = 114.44 MiB
   ```
   
   ### RPC Time Only
   
   ```text
   projected_rpc_time_ms =
       10,000,000 * (283 / 123,409)
     = 22,931.8778 ms
     = 22.93 s
   ```
   
   ### End-to-End Sync Time
   
   ```text
   projected_total_time_ms =
       10,000,000 * (516 / 123,409)
     = 41,804.0779 ms
     = 41.80 s
   ```
   
   ## 50 Million Containers
   
   ### RPC Calls
   
   ```text
   rpc_calls =
       ceil(50,000,000 / 500,000)
     = 100
   ```
   
   ### Transfer Volume
   
   ```text
   transfer_bytes =
       50,000,000 * 12
     = 600,000,000 bytes
   
   transfer_decimal_mb = 600 MB
   transfer_binary_mib = 572.20 MiB
   ```
   
   ### RPC Time Only
   
   ```text
   projected_rpc_time_ms =
       50,000,000 * (283 / 123,409)
     = 114,659.3891 ms
     = 114.66 s
     = 1.91 min
   ```
   
   ### End-to-End Sync Time
   
   ```text
   projected_total_time_ms =
       50,000,000 * (516 / 123,409)
     = 209,020.3893 ms
     = 209.02 s
     = 3.48 min
   ```
   
   ## 100 Million Containers
   
   ### RPC Calls
   
   ```text
   rpc_calls =
       ceil(100,000,000 / 500,000)
     = 200
   ```
   
   ### Transfer Volume
   
   ```text
   transfer_bytes =
       100,000,000 * 12
     = 1,200,000,000 bytes
   
   transfer_decimal_gb = 1.2 GB
   transfer_binary_gib = 1,200,000,000 / 1,073,741,824 = 1.118 GiB
   ```
   
   ### RPC Time Only
   
   ```text
   projected_rpc_time_ms =
       100,000,000 * (283 / 123,409)
     = 229,318.7783 ms
     = 229.32 s
     = 3.82 min
   ```
   
   ### End-to-End Sync Time
   
   ```text
   projected_total_time_ms =
       100,000,000 * (516 / 123,409)
     = 418,040.7788 ms
     = 418.04 s
     = 6.97 min
   ```
   
   ## Summary Table
   
   | Containers | RPC Calls | Payload / RPC | Total Payload | Est. RPC Time 
Only | Est. End-to-End Sync Time |
   |---|---:|---:|---:|---:|---:|
   | `4M` | `8` | `~6.0 MB` | `~48 MB` | `~9.2 s` | `~16.7 s` |
   | `10M` | `20` | `~6.0 MB` | `~120 MB` | `~22.9 s` | `~41.8 s` |
   | `50M` | `100` | `~6.0 MB` | `~600 MB` | `~114.7 s` | `~209.0 s` |
   | `100M` | `200` | `~6.0 MB` | `~1.2 GB` | `~229.3 s` | `~418.0 s` |
   
   ## SCM Heap Estimate
   
   The `12 bytes` figure is only the serialized protobuf wire size for one
   `ContainerID`. It is not the Java heap size of all transient objects involved
   in serving the RPC.
   
   Important implementation details:
   
   1. SCM obtains the IDs from the state map and collects them into a `List`.
   2. SCM then converts each `ContainerID` into protobuf and adds it to the
      response builder.
   
   This means SCM heap cost per RPC is mostly:
   
   - the list of references returned for the batch
   - protobuf response objects / builder state
   - transient serialization buffers
   
   It is not equivalent to allocating `500,000 * 12 bytes` on heap.
   
   ### Practical Per-RPC Heap Estimate for 500K IDs
   
   Wire payload:
   
   ```text
   500,000 * 12 = 6,000,000 bytes ~= 6 MB
   ```
   
   Reasonable transient heap estimate at SCM:
   
   - list/reference overhead: `~2 MB to 4 MB`
   - protobuf payload/builder/buffers: `~6 MB+`
   - additional temporary object overhead: `several MB`
   
   Practical planning range:
   
   ```text
   estimated_transient_heap_per_500k_rpc ~= 10 MB to 25 MB
   ```
   
   A good midpoint estimate is:
   
   ```text
   estimated_transient_heap_per_500k_rpc ~= 15 MB
   ```
   
   ## Key Takeaways
   
   1. A `128 MB` RPC envelope could theoretically carry about `11.18 million`
      container IDs if only wire size is considered.
   2. A `500K` operational batch is much safer and produces only `~6 MB` of
      payload per RPC.
   3. For `100 million` containers:
   
   ```text
   rpc_calls = 200
   total_transfer_volume = 1.2 GB
   estimated_rpc_time_only = 229.32 s ~= 3.82 min
   estimated_end_to_end_sync_time = 418.04 s ~= 6.97 min
   ```
   
   4. SCM transient heap should remain bounded per call with `500K` batching and
      is expected to be in the `10 MB to 25 MB` range per RPC rather than 
scaling
      toward the full `100 million` container population.
   
   ## Caveats
   
   These numbers are first-order projections, not guarantees.
   
   They assume near-linear scaling from the observed baseline. Real behavior may
   shift due to:
   
   - SCM CPU saturation
   - protobuf serialization overhead
   - JVM GC behavior
   - Recon consumer-side processing
   - network bandwidth and latency variability
   - concurrent SCM load from other clients
   
   
   **On your 3rd and last point related to alerts/notifications :**
   
   Currently, we don't have any alert framework inherently supported in Recon. 
I discussed and raised this point earlier, but since users can have various 
external ways also based on hadoop metrics, so we didn't carry on with this 
idea.
   
   So based on existing hadoop metrics, we can have following metrics:
   
   1. Count of occurrences in cumulative way, how many events of full snapshot 
got hit rather than real execution of full snapshot.
   2. in last such event of full snapshot, size of last drift of that last 
event. If value comes out 50K or any other value.
   3. Time between last 2 such events of full SCM DB snapshot download.
   4. We can add separate metrics per state drift. CLOSED, QUASI_CLOSED etc, 
and size of drift.
   5. Status of Targeted sync if it is in progress , success, failure.
   6. Timetaken by last targeted sync.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to