Repository navigation
[Bug]: Main CN authentication stalls at logtail barriers during catalog contention, causing ANLI Proxy 20508 failures #29965
Description
Is there an existing issue for the same bug?
- I have checked the existing issues.
Related to the receiver/catalog-contention investigation in #29275, but this report tracks normal authentication becoming unavailable before logtail recovery, not the previously observed 185-second forced-subscription recovery loop. No precise open issue for this Main incident was found.
Branch Name
main
Commit ID
- Observed:
d382fd5fa2081fcff6bcf712160d4f93c541a05d. - Latest main inspected:
5a5501b3e1048f3d19d96824cc68a62b7f0fcb07. Itspkg/vm/engine/disttae/cache/catalog.gois byte-identical to the incident version. This is a source check, not an end-to-end reproduction on latest main. - Nightly harness:
a8a59e037061a12c641ec409ba458d7af54ec6c7.
Other Environment Information
- Main nightly run 38149989746.
- ANLI TP write job 114584791861.
- Namespace:
mo-main-family-38149989746-1. - Affected TP CN:
nightly-regression-dis-tp-cn-24x2z, UUID62373261-3336-3733-3136-323265326130. - Shared TN, one TP CN and two AP CNs; two Proxy pods both recorded backend authentication timeouts targeting the TP CN.
- Final resource artifact: all nine pods ready/running, restart counts zero. No OOMKilled evidence for this event.
- Failing scenario:
insert_l2, eight writers, eight searchers, 200 rounds, 128 dimensions, 10 IVF lists.
Actual Behavior
The ANLI scenario reported 512 search failures and 508 write failures, with Proxy error 20508. Five subsequent DML scenarios were skipped. The same scenario had passed in the preceding run; this alone does not establish an introducing commit.
This is a real availability failure, not an ANN result-comparison failure. Proxy established backend connections but timed out after 10 seconds at read-auth-response. The generic text "possibly due to too many active transactions" must not be treated as proof of transaction-admission saturation.
Timeline
Times below are 2026-10-11 UTC; add eight hours for 2026-10-12 CST.
| Time | Observation |
|---|---|
| 22:18:43.043470 | TP background statistics logs check.move.on, state=false (task enabled), before calling its preparation path. |
| 22:18:45.901 | ANLI has 7,413 searches, 32,716 inserted rows and zero errors. Subsequent progress samples temporarily stop advancing. |
| 22:19:07.304 | First visible Proxy backend authentication timeout: read-auth-response, approximately 10 seconds. Both proxies target the TP CN. Client 20508 errors start in the same second. |
| 22:19:14.110967 | Statistics alpha-task completion reports 90 tables and takes=957.462944ms. This duration excludes the preceding preparation path. |
| 22:20:14.111037 | Next statistics preparation cycle begins after check.move.on. |
| 22:20:22.643 / 22:20:52.643 | TP mo_logtail_queue_size{type="receive"} samples are 16 / 15. |
| 22:20:31.684 | Another Proxy authentication-timeout burst; further client errors. |
| 22:20:39.722045 | CN connection timing records Authenticate=18.037506430s, versus CheckTenant=57.8ms, CheckUser=60.0ms and CheckRole=115.1ms. These sub-durations do not explain most of the authentication wait. |
| 22:21:00.431 onward | TN records closed response admission / context cancellation for affected session activity. This is not claimed to be the initial queue-full transition. |
| 22:21:01.866362 | TP transaction client finally changes to paused. This is roughly 114 seconds after the first authentication timeout. |
| 22:21:02.007-.496 | System-table subscription completion records have durations approximately 134ms / 123ms / 125ms. |
| 22:21:06.967556 | TP transaction client returns to normal: 5.101194 seconds paused. |
| 22:21:08.154668 | Statistics alpha-task completion: 83 tables, takes=6.272957954s. ANLI counters are advancing again by this time. |
| 22:21:34 | Scenario fails with the accumulated 512/508 errors; it did not remain permanently hung. |
The two check.move.on to alpha-completion intervals are approximately 31.07s and 54.04s. Subtracting the logged alpha durations leaves approximately 30.11s and 47.77s outside alphaTask. Code places preparation before alphaTask, but these residuals are not isolated measurements of BTree lock-hold time or of GetTableByIdAndTime alone.
Incident profiles identify the blocking paths
Two TP goroutine aggregates were requested for 22:18:45-22:19:30 and 22:20:15-22:20:55 UTC. Both contain all three paths:
Authentication:
MOServer.handshake -> MysqlProtocolImpl.Authenticate
-> Session.AuthenticateUser -> prepareAuthenticationSnapshot
-> acquireLogtailReadBarrier -> AcquireLogtailReadBarrier
-> acquireAppliedLogtailReadBarrier -> logTailSubscriber.readBarrier
-> LogtailClient.ReadBarrier -> runtime.selectgo
Background statistics:
GetMOTableStatsExecutor -> tableStatsExecutor -> prepare
-> getChangedTableList -> buildTablePairFromCache
-> CatalogCache.GetTableByIdAndTime
-> BTreeG.Ascend -> nodeScan -> GetTableByIdAndTime.func1
Logtail receiver:
PushClient.receiveLogtails -> receiveOneLogtail
-> dispatchUpdateResponse -> consumeUpdateLogTail
-> applyToCatalogCache -> CatalogCache.InsertTable / DeleteTable
-> setTableItemLocked -> BTreeG.SetHint -> sync.RWMutex.Lock
The first aggregate has weights 104 for the authentication-barrier stack, 8 for the statistics scan, and 8 for the receiver's catalog write-lock waits. The second has weights 134, 12 and 12 respectively. These are aggregate profile weights, not numbers of simultaneous goroutines or seconds of continuous lock ownership.
In the CPU profile selected for 22:18:40-22:19:30, stacks through the statistics GetTableByIdAndTime path account for 28.20 CPU-s of 119.82 sampled CPU-s (23.5%). This is an inclusive sampled CPU fraction, not wall-time attribution, whole-host utilization or proof that this path alone accounts for every failed connection.
Additional bounded metrics: TP RSS samples are about 31.1-37.7 GiB; the sampled wait-active queue is zero. The Go GC pause sum increases by about 39.8ms across the approximately four-minute sampled interval. These do not support a seconds-long stop-the-world pause or OOM as the explanation, but do not eliminate all CPU scheduling or allocation overhead.
Expected Behavior
Background catalog/statistics work should not prevent a healthy CN from making bounded progress on logtail consumption and ordinary connection authentication, causing repeated backend handshake deadline failures.
Any fix must preserve the authentication snapshot/read-barrier correctness guarantee. Bypassing that barrier, authenticating against stale catalog state, or merely increasing Proxy timeouts is not an established safe fix.
Steps to Reproduce
This report is based on the actual integration run and server profiles, not a synthetic timeout injection. A minimal deterministic end-to-end reproduction has not been completed.
- Use the Main revision and the shared Family topology above.
- Run the existing ANLI
insert_l2scenario through Proxy while the TP CN has the accumulated Family catalog and its normal background statistics task. - Capture connection-stage timing, authentication goroutines, catalog receiver stacks, statistics preparation cost and logtail receive-queue samples together.
- Observe the documented 10-second backend authentication timeouts and client 20508 failures.
Next discriminating experiment: hold catalog contents and foreground connection workload fixed in an isolated test, compare normal statistics preparation against a narrowly controlled no-scan baseline, and measure catalog writer progress plus authentication/barrier latency. Do not disable statistics or correctness barriers on a shared production cluster merely to test this hypothesis.
Additional information
Exact-version source supports the mechanism
GetTableByIdAndTimescans a name-ordered catalog BTree to find a table ID at a snapshot; the source explicitly documents O(n) lookup. Retained versions are traversed too. It has no context parameter.getChangedTableListrepeats this lookup for returned table IDs;buildTablePairFromCacheresolves each against the catalog.- The pinned dependency,
tidwall/btree v1.7.0 Ascend, retains the BTree read lock for the traversal and callbacks.SetHintrequires its write lock. This is ordinary RWMutex contention, not evidence of a bug in the BTree implementation. prepareAuthenticationSnapshotacquires the logtail barrier before reading authentication catalog data.LogtailClient.Receivecompletes barrier responses while consuming the same stream. A receiver blocked applying an earlier catalog update cannot immediately consume later barrier responses.
Assessment: The handshake failures, authentication barrier waits, catalog receiver write-lock waits and repeated statistics scans are observed. The source explains how catalog scan contention can delay logtail and therefore authentication. Statistics-driven catalog contention is the leading initiating-cause hypothesis, not yet a uniquely proven cause for the entire incident. Aggregate stacks do not identify one continuously held lock, the exact catalog cardinality is not reconstructed, and no controlled intervention has yet removed this bottleneck while keeping the rest of the workload constant.
Existing-issue and regression boundary
- [Bug]: catalog logtail recovery abandons slow forced-flush subscriptions, pausing CN transactions for 185s #29275 already records catalog contention as a precursor, but its principal failure is long forced-subscription recovery. Here authentication fails before transaction pause, and the observed pause is only 5.1s. Link the investigations; do not label this as a reappearance of a closed recovery fix or duplicate the 185s claim.
- [Bug]: main stability LogService/Raft stalls, causing 25s WAL append and Proxy 20508 #29687 has similar Proxy symptoms with a LogService/Raft stall; that root cause is not established here.
- IDC-MO [Performance]: Measure and bound residual mo_table_stats load per CN #29240 was administratively closed as an unintended tracking item, not as a verified fix for this incident.
- [Bug]: CollectChanged returns historical checkpoint table IDs outside requested window #29339 fixed out-of-window table IDs from
CollectChanged; it does not by itself remove the shown ID-lookup traversal and locking. - No introducing PR has been identified. A prior successful run is insufficient to call this a newly introduced regression.
- No durable data-loss, wrong-result, leaked-transaction or vector-distance-algorithm claim is made.
Activity
LeftHandCold commentedon Oct 12, 2026
Root-cause investigation and scoped main fix
PR: #29983, commit
d32ae8663d0251b565b76b8b43cb0356e518e82c, based on main02a2823c2007d5e4fb4ada148e93743df337551a.What is proven
There is a reproducible catalog lookup amplification defect in changed-table statistics preparation:
getChangedTableListresolves requested table IDs individually throughbuildTablePairFromCache.CatalogCache.GetTableByIdAndTimescans a BTree ordered by account/database/name/timestamp, not table ID. A missing or dropped ID can scan the entire scope. M requests against N retained entries can therefore cause O(M*N) work.InsertTable/DeleteTable. Repeated scans can interleave with many short catalog writes, delaying completion of an entire apply batch.This is cumulative scan/write contention, not an assertion that one reader holds a lock continuously for tens of seconds. Go's writer preference does not remove the repeated work between successive writes.
The original incident profiles contain all three corresponding paths: statistics scanning the catalog, catalog apply waiting for the BTree write lock, and authentication waiting at the logtail read barrier. This is not evidence that ANLI result parsing, Cosine computation, or Astra application transaction handling caused the failure.
Additional incident evidence
Original ANLI job, MO
d382fd5fa2081fcff6bcf712160d4f93c541a05d.All timestamps below are UTC on 2026-10-11; add eight hours for Beijing time on 2026-10-12.
consume-one-entry-catalog-cacherecorded 4,482 completed observations, with a duration-sum increase of 29.740047441s. Every completed observation was within the 45.562053899ms histogram bucket boundary. These are completion-based aggregates, not exact individual timings or proof of exclusive wall-clock occupancy.consume-catalog-tableduration sum increased 29.915443905s in that interval. It is nested and must not be added to the preceding value.Counterfactual reproduction on shanghai50
An isolated finite-work harness uses real
CatalogCachelookup andInsertTable/DeleteTablemethods. Both arms use the same requested IDs, retained catalog, and fixed writer workload. It injects no sleep or artificially held lock.Synthetic scope: 45,559 names x 8 versions, 4,000 requested IDs (90 visible matches), and a fixed 1,000-row insertion followed by deletion workload.
Both arms check returned IDs and visible versions. This establishes the repeated-scan mechanism and the patch's reduction in work. The synthetic single-scope distribution is not claimed to match the original incident exactly; the recovered incident catalog count did not establish its complete scope/version distribution.
The small permanent benchmark also measures 4,096 names x four versions with 64 missing IDs: 8.425ms -> 0.155ms, 23,040B / 65 allocations -> 3,208B / 5 allocations. Singleton lookups remain approximately 132us / 131us, with identical allocation counts. These are catalog measurements, not predicted application QPS.
Fix and risk boundary
The PR groups changed-table ID lookups by account/database and traverses each scope once, preserving the existing snapshot/name visibility rules, tombstones, replacement identities, order, duplicates, missing IDs, view exclusion, and callback metadata.
Production scope is two files (+117/-20 lines). No persistent index/cache, worker, retry, timeout, protocol, authentication barrier, GC rule, routing rule, or vector execution change is introduced. Ordinary scalar lookups and singleton behavior remain unchanged. Scratch state is per-call and O(requested IDs).
This is not presented as a proven newly introduced regression: the scalar lookup and statistics loop have long histories (#17721 and #20222). Their presence does not identify which later workload or change first exposed the 2026 incident.
Verification and remaining acceptance
All passed on shanghai50 with Go 1.27.1, the repository CGo wrapper, verified native-artifact provenance, four CPU affinity slots, and exact delivery-file hashes:
disttae/cacheanddisttaepackages, normal and race modes.TestMoTableStatsMoCtlandTestHandleGetChangedList.Keep this issue open for same-workload Family acceptance. The code defect and its controlled counterfactual are proven; the original 512/508-error workload has not been replayed end to end. The PR does not claim that every authentication timeout is uniquely caused by this defect, impose a latency bound on arbitrarily large catalog scopes, or eliminate all other scalar catalog consumers. GitHub CI and subsequent Family results must be tracked separately from the completed local/50 validation.
fix(disttae): batch catalog ID lookups for table statistics (#29983)