延迟瓶颈实测为本机 CPU 而非机房位置,跨站对比主指标改为 compute_ms

用户指出本机选新加坡是因为 Bitget 机房在新加坡。查证下来 ws.bitget.com 解析
到的是 CloudFront(dxotqhr62n6z4.cloudfront.net),落在新加坡 AS16509
(Amazon),即连的是 AWS 的 CDN 边缘而非 Bitget 自有机房。

腾讯云 ap-singapore(AS132203)到该边缘实测:ICMP 往返 2.1ms、TCP 握手
3.3ms、TLS 完成 9.0ms、首字节 87.8ms。首字节减 TLS 那约 79ms 是 CloudFront
回源开销,与我们的位置无关。

延迟构成(33 根样本):数据到达中位 506ms、信号计算中位 646ms、合计 1315ms。
随机房位置变化的只有那 2ms 往返,占总延迟 0.15%。而 646ms 的信号计算是每根
在 2000 根 1m 加 800 根 5m 上重建缠论结构,本机 2 核、2 个计算进程,三币同时
收盘时第三个还要排队——这才是有改善空间的一项。

因此:
- 新增 deploy/netprobe.sh,把网络那一段单独量出来并入运行元数据。用到达
  延迟去比两个机房等于用公斤秤称克,必须把可变的那段拿出来单独看。
- compare_sites.py 主指标改为 compute_ms,lag_data_ms 降为自检项(两站应当
  接近;若差很多,先怀疑时钟而非网络)。元数据表加 nproc/cpu_model/往返。
- README 改写:第二台机器该测 CPU 规格而非地理位置,WORKERS 按核数减一给,
  币数多于 worker 数时排队时间直接计入 compute_ms。

另修正站点标签:本机是腾讯云而非 Hetzner,sg-hetzner → sg-tencent,标错的
33 行数据已清掉重采。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jack
2026-08-28 02:51:51 +08:00
co-authored by Cursor
parent 1661bbbac9
commit 95f2b614a2
4 changed files with 147 additions and 15 deletions
+34 -7
View File
@@ -1,8 +1,17 @@
"""对比两个(或多个)采集站点的数据差异。
部署第二台机器的目的就是这个:延迟是「本地接收 − 交易所 K 线收盘」,直接
取决于机器到交易所的网络距离,换个地理位置这个数会变。而滑点里最大的一项
是延迟漂移,所以站点选址本身就是一个可优化的参数。
## 该比什么(2026-08-28 实测修正)
原以为该比地理位置,实测下来不是。腾讯云新加坡的延迟构成:
数据到达 506ms 其中网络仅 2ms 往返(ws.bitget.com 是 CloudFront 边缘)
信号计算 646ms 本机 2 核,三币同时收盘还要排队
合计 1315ms
换机房只能动那 2ms。**主指标是 compute_ms,不是 lag_data_ms。**
lag_data_ms 仍然要看,但作用是**自检**:两站应当几乎相同;若差很多,先怀疑
时钟没对齐——那比网络差异的可能性大得多。
## 判读前必须先看的两件事
@@ -68,10 +77,21 @@ def show_meta(out_dirs: list[Path]) -> None:
if not rows:
return
df = pd.DataFrame(rows)
keep = [c for c in ("site", "clock_offset_ms", "git_commit", "git_dirty",
"image_digest", "nproc", "mem_gb", "tz",
# net 是嵌套 dict,摊平出关心的几项
if "net" in df.columns:
for k in ("icmp_min_ms", "tcp_connect_min_ms", "ttfb_min_ms",
"self_org", "edge_org"):
df[k] = df["net"].apply(
lambda v, k=k: v.get(k) if isinstance(v, dict) else None)
keep = [c for c in ("site", "clock_offset_ms", "nproc", "cpu_model",
"icmp_min_ms", "ttfb_min_ms", "git_commit",
"git_dirty", "image_digest", "mem_gb", "tz",
"started_utc") if c in df.columns]
print(df[keep].to_string(index=False))
if "icmp_min_ms" in df and df["icmp_min_ms"].notna().any():
x = df["icmp_min_ms"].astype(float)
print(f"\n 到 Bitget 边缘的往返:{x.min():.1f}~{x.max():.1f}ms。"
f"站间极差 {x.max() - x.min():.1f}ms 就是换机房的全部空间")
if "clock_offset_ms" in df and df["clock_offset_ms"].notna().any():
o = df["clock_offset_ms"].astype(float)
spread = float(o.max() - o.min())
@@ -94,7 +114,10 @@ def compare_latency(df: pd.DataFrame, col: str = "lag_data_ms") -> None:
f"等第二台机器的数据到齐")
return
print(f"\n########## 二、到达延迟({col} ##########")
label = {"compute_ms": "信号计算耗时(主指标,取决于 CPU",
"lag_data_ms": "数据到达延迟(自检项,两站应当接近)",
"lag_signal_ms": "合计到可下单"}.get(col, col)
print(f"\n########## {label}{col} ##########")
print("\n 全量(各站各自的样本,时段可能不同)")
for s in sites:
x = df[df["site"] == s][col].dropna().astype(float)
@@ -176,7 +199,11 @@ def main() -> None:
show_meta([p for p in metas if p.is_dir()])
df = load(lat)
compare_latency(df)
# compute_ms 是主指标:它是延迟里唯一有大幅改善空间的一项(646ms vs
# 网络的 2ms)。lag_data_ms 放后面,作用是自检两站是否可比
compare_latency(df, "compute_ms")
compare_latency(df, "lag_data_ms")
compare_latency(df, "lag_signal_ms")
compare_drift(drf)
+35 -6
View File
@@ -2,13 +2,34 @@
在第二台机器上跑一套完全相同的采集,用来看不同地理位置的数据差异。
## 为什么要跨地采集
## 先看这一节:延迟的瓶颈不在机房
滑点里最大的一项是**延迟漂移**:从 K 线收盘到实际下单之间,价格已经走掉
那部分。而延迟 = 交易所出包 + 网络传输 + 本地处理。本机(新加坡实测到达
延迟中位 350~650ms,其中网络传输占多少、换个机房能压掉多少,只有实测。
滑点里最大的一项是**延迟漂移**,所以延迟越低越好。但延迟拆开之后,可优化
地方和直觉不一样。腾讯云新加坡实测2026-08-28):
延迟压下来直接等于滑点下降,所以机房选址是个可优化参数,不是固定成本。
| 构成 | 中位 | 随机房位置变化吗 |
| --- | --- | --- |
| 数据到达(交易所推送 + 回源 + 网络) | 506ms | 只有网络那段,**2ms** |
| 信号计算(本机 CPU | **646ms** | 不变,取决于 CPU |
| 合计到可下单 | 1315ms | |
`ws.bitget.com` 解析出来是 **CloudFront**`dxotqhr62n6z4.cloudfront.net`),
落在新加坡的 AS16509(Amazon)。所以我们连的是 AWS 的 CDN 边缘,不是 Bitget
自己的机房。从腾讯云新加坡到这个边缘:
ICMP 往返 2.1ms
TCP 握手 3.3ms
TLS 完成 9.0ms
首字节 87.8ms ← 减去 TLS 的 9ms,约 79ms 是 CloudFront 回源开销
回源那 79ms 和交易所自己的推送节奏,不管我们坐在哪都一样。而随位置变化的
只有那 2ms 往返。**换机房的全部空间是 1~2ms,占总延迟 1315ms 的 0.1%。**
真正的大头是本机 646ms 的信号计算:每根 K 线要在 2000 根 1m 加 800 根 5m 上
重建缠论结构,三个币同时收盘而本机只有 2 核、2 个计算进程,第三个币还要排队。
**所以第二台机器该测的是 CPU 规格,不是地理位置。**`compute_ms`,不是
`lag_data_ms`。3 个币至少要 3 个 worker,`--workers` 给到核数减一。
## 三个必须一致,一个必须不同
@@ -41,9 +62,14 @@ git clone ssh://jack@git.jackyu66.com:2222/jack/chan.git
cd chan && git checkout chan
bash research/live/deploy/setup.sh # 装 docker + chrony,拉镜像
SHADOW_SITE=aws-tokyo bash research/live/deploy/start.sh
# 站点名带上机型,因为要比的是 CPU 而不是位置
SHADOW_SITE=aws-sg-c7a4x WORKERS=3 bash research/live/deploy/start.sh
```
`WORKERS` 按核数减一给。3 个币同时收盘,worker 少于 3 就会排队,而排队时间
直接计入 `compute_ms`。本机 2 核只能给 2,这本身就是 646ms 里的一部分。
确认健康:
```bash
@@ -88,6 +114,9 @@ python research/live/compare_sites.py \
市场性质,与机器位置无关。若漂移也差很多,先怀疑时钟或时段没对齐,而不是
急着下结论。
同理,`lag_data_ms` 两站也应当几乎相同(网络那段只有 2ms 空间)。真正该出现
差异的是 `compute_ms`。如果 `lag_data_ms` 差很多,先查时钟——比查网络更可能。
## 资源占用
本机实测:内存约 1.5GB(两个计算进程 + 盘口缓冲),CPU 单核不满。
+69
View File
@@ -0,0 +1,69 @@
#!/usr/bin/env bash
# 量本机到 Bitget 端点的网络距离,输出 JSON。start.sh 会把它并进运行元数据。
#
# 为什么要单独量:K 线到达延迟(lag_data_ms)是「交易所推送节奏 + 回源 + 网络」
# 三者之和,中位 506ms。其中只有最后一段随机房位置变化,而实测它只有 2ms
# 往返——用到达延迟去比两个机房,等于用公斤秤称克。这个探测把可变的那一段
# 单独拿出来。
#
# 还有一件事值得知道:ws.bitget.com 解析出来是 CloudFrontAWS 的 CDN 边缘),
# 不是 Bitget 自己的机房。所以「离交易所近」实际是「离 CloudFront 边缘近」。
set -uo pipefail
WS_HOST="${WS_HOST:-ws.bitget.com}"
N="${N:-10}"
resolved="$(getent hosts "$WS_HOST" 2>/dev/null | head -1 || true)"
edge_ip="$(awk '{print $1}' <<<"$resolved")"
cname="$(awk '{print $2}' <<<"$resolved")"
icmp_min=null; icmp_avg=null
if out="$(ping -c "$N" -q -W 2 "$WS_HOST" 2>/dev/null)"; then
stats="$(grep -oE 'rtt min/avg/max/mdev = [0-9./]+' <<<"$out" | awk '{print $NF}')"
if [[ -n "$stats" ]]; then
icmp_min="$(cut -d/ -f1 <<<"$stats")"
icmp_avg="$(cut -d/ -f2 <<<"$stats")"
fi
fi
# TCP 握手是一个完整往返,比 ICMP 更能代表实际连接路径(有些网络对 ICMP 降级)
tcp_min=null; tls_min=null; ttfb_min=null
if command -v curl >/dev/null 2>&1; then
vals="$(for _ in $(seq "$N"); do
curl -s -o /dev/null --max-time 8 \
-w '%{time_connect} %{time_appconnect} %{time_starttransfer}\n' \
"https://$WS_HOST/v2/ws/public" 2>/dev/null
done)"
if [[ -n "$vals" ]]; then
tcp_min="$(awk '{print $1*1000}' <<<"$vals" | sort -n | head -1)"
tls_min="$(awk '{print $2*1000}' <<<"$vals" | sort -n | head -1)"
ttfb_min="$(awk '{print $3*1000}' <<<"$vals" | sort -n | head -1)"
fi
fi
org="unknown"
if [[ -n "$edge_ip" ]]; then
org="$(curl -s --max-time 6 "https://ipinfo.io/$edge_ip/json" 2>/dev/null \
| awk -F'"' '/"org"/{print $4}')"
[[ -n "$org" ]] || org="unknown"
fi
self_org="$(curl -s --max-time 6 https://ipinfo.io/json 2>/dev/null \
| awk -F'"' '/"org"/{print $4}')"
self_city="$(curl -s --max-time 6 https://ipinfo.io/json 2>/dev/null \
| awk -F'"' '/"city"/{print $4}')"
cat <<EOF
{
"ws_host": "$WS_HOST",
"edge_ip": "${edge_ip:-unknown}",
"edge_cname": "${cname:-unknown}",
"edge_org": "$org",
"self_org": "${self_org:-unknown}",
"self_city": "${self_city:-unknown}",
"icmp_min_ms": ${icmp_min:-null},
"icmp_avg_ms": ${icmp_avg:-null},
"tcp_connect_min_ms": ${tcp_min:-null},
"tls_done_min_ms": ${tls_min:-null},
"ttfb_min_ms": ${ttfb_min:-null}
}
EOF
+9 -2
View File
@@ -64,8 +64,13 @@ docker rm -f "$NAME" >/dev/null 2>&1 || true
mkdir -p "$OUT"
say "量网络距离"
netprobe="$(bash "$(dirname "${BASH_SOURCE[0]}")/netprobe.sh" 2>/dev/null || echo '{}')"
echo "$netprobe" | grep -E 'edge_org|self_org|self_city|icmp_min_ms|tcp_connect' || true
# 运行元数据。两地数据对不上时,先看这个文件——镜像摘要、代码版本、时钟偏移
# 三者任一不同都足以解释差异,不必去猜。
# 三者任一不同都足以解释差异,不必去猜。网络探测并在这里,因为「换机房能省
# 多少」这个问题只有它能回答(到达延迟里网络只占约 2ms,用它比等于用公斤秤称克)。
meta="$OUT/run_meta_${SHADOW_SITE}.json"
cat >"$meta" <<EOF
{
@@ -82,7 +87,9 @@ cat >"$meta" <<EOF
"workers": $WORKERS,
"kernel": "$(uname -r)",
"nproc": $(nproc),
"mem_gb": $(free -g | awk '/^Mem:/{print $2}')
"cpu_model": "$(awk -F': ' '/model name/{print $2; exit}' /proc/cpuinfo 2>/dev/null || echo unknown)",
"mem_gb": $(free -g | awk '/^Mem:/{print $2}'),
"net": $netprobe
}
EOF
echo "元数据已写 $meta"