bosswnx commented on issue #67297:
URL: https://github.com/apache/doris/issues/67297#issuecomment-5452616028
As requested in the review, here are the full reproduction scripts and the
timestamped evidence timeline.
## Build version
- Image: official `apache/doris:fe-3.0.8` from Docker Hub (manifest digest
below). No internal patches.
```
$ docker inspect apache/doris:fe-3.0.8 --format '{{index .RepoDigests 0}}'
apache/doris@sha256:81c72270254585376d8e46239ed90b4f5c04b0d77ae0a0accafb4ea90f7d54c8
```
- Version reported by the FE: `doris-0.0.0-c7e635238f4` (from `show
frontends`). Note this is the version string baked into the 3.0.8 release
image; the same code path was also confirmed on current master at the source
level in the issue body.
## Reproduction scripts
### docker-compose.yml (4 FE, no BE — only forward-to-master statements are
used)
```yaml
version: '3'
services:
fe1: # initial MASTER (simulates the customer's old master 10.206.172.8)
image: "apache/doris:fe-3.0.8"
container_name: "repro-fe1"
hostname: "fe1"
cap_add: [NET_ADMIN]
environment:
-
FE_SERVERS=fe1:172.20.80.2:9010,fe2:172.20.80.3:9010,fe3:172.20.80.4:9010,fe4:172.20.80.5:9010
- FE_ID=1
ports: ["18030:8030", "19030:9030"]
volumes:
- /data/repro-10907/docker/fe1/meta:/opt/apache-doris/fe/doris-meta
- /data/repro-10907/docker/fe1/log:/opt/apache-doris/fe/log
networks:
doris_net:
ipv4_address: 172.20.80.2
# fe2 = 172.20.80.3 FOLLOWER, fe3 = 172.20.80.4 FOLLOWER, fe4 =
172.20.80.5 OBSERVER
# (identical blocks with FE_ID=2/3/4; fe4 is registered via
# ALTER SYSTEM DROP FOLLOWER "172.20.80.5:9010"; ALTER SYSTEM ADD
OBSERVER "172.20.80.5:9010"
# because the image entrypoint only registers followers)
networks:
doris_net:
ipam:
config:
- subnet: 172.20.80.0/24
```
### Injection script (repro_demo.sh)
Uses `nsenter -t <container-pid> -n iptables` from the host — the image
itself has no iptables binary.
```bash
MYSQL4="mysql -h 127.0.0.1 -P 19033 -u root" # observer fe4 (customer's LB
-> 10.206.172.49)
pid() { docker inspect repro-$1 --format '{{.State.Pid}}'; }
# STEP 1: freeze observer's journal replay toward the potential new masters
(bdbje 9010)
FE4PID=$(pid fe4)
for ip in 172.20.80.3 172.20.80.4; do
nsenter -t $FE4PID -n iptables -A INPUT -p tcp -s $ip --dport 9010 -j
DROP
nsenter -t $FE4PID -n iptables -A OUTPUT -p tcp -d $ip --dport 9010 -j
DROP
done
# STEP 2: old master "OOM" death
docker kill repro-fe1
# STEP 3: wait for the new master election (fe3 won in this run)
# STEP 4: restart fe1, wait for its thrift (9020) to listen, then isolate
its bdbje:
# alive-but-degraded old master (mysql/thrift serving, cannot rejoin)
docker start repro-fe1
# ... wait for /dev/tcp/172.20.80.2/9020 ...
FE1PID=$(pid fe1)
for ip in 172.20.80.3 172.20.80.4 172.20.80.5; do
nsenter -t $FE1PID -n iptables -A INPUT -p tcp -s $ip --dport 9010 -j
DROP
nsenter -t $FE1PID -n iptables -A OUTPUT -p tcp -d $ip --dport 9010 -j
DROP
done
# STEP 5: customer scenario — statement via the observer
mysql -h 127.0.0.1 -P 19033 -u root -e \
'ADMIN SET FRONTEND CONFIG ("label_keep_max_second" = "259200")'
```
## Client-visible result (FORWARD_NO_SYNC statement)
```
$ mysql -h 127.0.0.1 -P 19033 -u root -e 'ADMIN SET FRONTEND CONFIG
("label_keep_max_second" = "259200")'
ERROR 1105 (HY000) at line 1: errCode = 2, detailMessage = The statement has
been forwarded to master FE(172.20.80.2) and failed to execute because Master
FE is not ready. You may need to check FE's status
```
fe4 audit log confirms this exact error was returned to the client:
```
AuditLogger 2026-08-28 11:43:18,657 [query] | ... |Timestamp=2026-08-28
11:43:18.657|Client=172.20.80.1:...|FeIp=172.20.80.5|State=ERR|ErrorCode=1105|ErrorMessage=errCode
= 2, detailMessage = The statement has been forwarded to master
FE(172.20.80.2) and failed to execute because Master FE is not ready. You may
need to check FE's status|...|Stmt=ADMIN SET FRONTEND CONFIG
("label_keep_max_second" = "259200")
```
## Timestamped evidence timeline (all times are container-log times, same
host clock)
| Time | Node | Event (log line) |
|---|---|---|
| 11:37:57 | fe4 (observer) | `setMaster MasterInfo: host=172.20.80.2`
(masterInfo = fe1, normal) |
| 11:38:33 | fe4 | `replayed journal id is 48, replay to journal id is 49`
(replay healthy before injection) |
| 11:38:37 | fe1 | `docker kill` — old master dies |
| 11:38:37 | fe4 | `transfer FE type from OBSERVER to UNKNOWN` (lost its
feeder) |
| 11:39:00–11:39:10 | fe3 | `transfer FE type from UNKNOWN to MASTER` —
**fe3 (172.20.80.4) is the new master** |
| 11:41:41 | fe1 | restarted; `transfer FE type from INIT to FOLLOWER`
(thrift 9020 up; bdbje then isolated by iptables) |
| 11:41:42 | fe1 | `setMaster MasterInfo: host=172.20.80.4` — **briefly
learned the new master from residual replay, then isolated** |
| 11:42:12 | fe4 | `forward to master FE
TNetworkAddress(hostname:172.20.80.2, port:9020), statement id: 12` —
**observer still forwards to the old master fe1** (its masterInfo was never
refreshed: replay frozen since 11:38:37) |
| 11:42:13.114 | fe1 | `StmtExecutor.executeByLegacy():1042 execute
Exception` → `UserException: ... The statement has been forwarded to master
FE(172.20.80.2) and failed to execute because Master FE is not ready` (thrown
by the old master itself, stack: `proxyExecute` →
`FrontendServiceImpl.forward`) |
| 11:42:13.117 | fe4 | `forwarding to master get result max journal id: 79`
→ `JournalObservable.waitOn(): waiting for the observer to replay journal to 79
with timeout: 1080000 ms` — **the sync-wait hang begins even though the result
carried an error** |
| 11:43:18 | fe4 | (with the 25 s client timeout override in this test run)
error surfaces to the client; with the default `query_timeout=900`, this wait
would last up to 1080 s |
Notes on the numbers requested in the review:
- Observer `replayedJournalId` was frozen at ~49 since 11:38:37; the old
master returned `maxJournalId=79` (its own last replayed id), so `waitOn(79)`
can never be satisfied while the replay freeze lasts — this is the exact
WITH_SYNC hang mechanism.
- `meta out of date ... delta:300001ms, hasLog:false, feType:UNKNOWN`
appears at ~300 s after the freeze (default
`meta_delay_toleration_second=300`), after which the observer's failure mode
changes to `Node catalog is not ready` — consistent with the review's note that
the stale-forward window is bounded by but not fixed by this config.
- In the 11:42 attempt above, fe1's own `masterInfo` had already flipped to
fe3 (via its brief residual replay at 11:41:42 before isolation). The
customer's real-world case is harsher: an OOM-recovered old master that never
replays the new master's journals keeps `masterInfo = itself`, which is why the
hint-from-rejecting-FE approach must not be trusted blindly (matches review
constraint #2).
## FORWARD_WITH_SYNC variant (CREATE USER)
Same injection; `CREATE USER fin_1 IDENTIFIED BY 'p'` sent via fe4 while fe1
is dead-but-forwardable produced either:
- `ForwardToMasterException ... cause: EOF, Socket is closed by peer` (fe1
down), or
- when fe1 is in the degraded-alive state: the statement is rejected by fe1
with the same "Master FE is not ready" error, but fe4 blocks in
`JournalObservable.waitOn(79)` for the full timeout (only interrupted by
client-side `SET query_timeout` — with `query_timeout=5` the wait log shows
`timeout: 6000 ms`).
This confirms the review's constraint #5: a structured NOT_MASTER response
alone would not fix the sync-forward hang; the rejection path must bypass
`JournalObservable.waitOn()`.
## What I don't have
- The customer's production LB health-check config and BDB JE state-change
logs from the real failover window (their environment; I'll request them). The
reproduction above is my own environment.
--
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]