阿里云 CEN 与腾讯云 CCN 跨云专线打通:context deadline exceeded 超时排查
阿里云 CEN 与腾讯云 CCN 跨云专线打通:context deadline exceeded 超时排查
文中所有 IP、网段、资源 ID、域名、服务名均为占位示意,替换成你自己的即可。涉及两朵云的私网网段,统一约定:阿里云海外侧用
10.10.0.0/16,阿里云北京侧用10.30.0.0/16,腾讯云侧用10.20.0.0/16。
结论先行
一个跑在阿里云海外地域的 Go 服务,调用腾讯云北京 TKE 里的图片生成接口,偶发 context deadline exceeded,单次卡到 28s。根因不是后端,也不是 DNS——是这条调用走的公网域名裸奔跨境,而两朵云之间其实早就拉好了专线(阿里云 CEN + 腾讯云 CCN + 物理专线),只是没被这条调用用上。
最终的卡点精确到一个字段:腾讯云专线网关发布给云联网(CCN)的「静态网段列表」里,漏了阿里云海外那个网段,导致回程不通。补上网段、再建一个内网 Ingress 把流量切到专线,跨境超时根治,真实出图从公网的 2.2s 降到内网的 1.6s 且不再抖动。
下面是完整的排查路径,以及中途踩的四个坑。
环境
| 角色 | 说明 |
|---|---|
| 调用方 | 阿里云海外地域 ECS 上的 Go 服务(下称上游服务),VPC 网段 10.10.0.0/16 |
| 被调方 | 腾讯云北京 TKE 集群里的图片生成服务,CLB Ingress 暴露,域名 api.example.com,接口 POST /img/generate |
| 已有网络 | 阿里云 CEN(云企业网,企业版转发路由器)跨地域 + 阿里云↔腾讯物理专线 + 腾讯 CCN(云联网) |
| 排查工具 | 阿里云 SLS、腾讯云 CLS、aliyun CLI、tccli、kubectl |
链路总览
一张图看清「出问题的公网路径」和「改造后的内网专线路径」,以及本次根因卡在哪:

对照上图,整条链路逐段说明:
- 现状 / 出问题的路(图中红色虚线):上游服务用公网域名
api.example.com,DNS 解析到公网 CLB,流量裸奔跨境公网 —— 高峰丢包、TCP 握手 SYN 重传,最终 28scontext deadline exceeded。 - 改造去程(绿线起步 + 蓝线):上游改走内网域名
api-inner,经阿里云 CEN 企业版转发路由器(TR) 跨地域传输,海外网段10.10.x已Propagated到北京 TR 路由表,到达阿里云北京 VBR。 - 物理专线(蓝线):北京 VBR 通过物理专线接入腾讯专线网关
dcg-xxxx,这一段的专用通道走 BGP 动态路由。 - 根因卡点(图中红框):专线网关发布给 CCN 的网段是
CcnRouteType=STATIC手工静态列表,漏了海外10.10.0.0/16—— 腾讯侧没有回到海外的路由,去得到、回不来。补上这条网段后,CCN 学到、腾讯 VPC 路由表自动出现10.10/16 → CCN,回程打通。 - 内网入口(绿线落点):腾讯 TKE 建内网 Ingress(内网 CLB
10.20.2.34),内网域名解析到它,流量打到后端abc-svc(GPU 出图 ~1.4s)。至此上游全程走专线,跨境超时根治。
一句话:去程靠阿里云 CEN 把网段传过去(已通),回程靠腾讯专线网关把对端网段加进「发布给 CCN 的静态列表」——这一环漏了海外网段,所以只配一边等于没配。
数据流向动图(公网裸奔超时 → 切内网专线打通,逐段点亮):

一、现象:context deadline exceeded
上游服务日志(阿里云 SLS)里一条典型报错:
HTTP request failed. URL: http://api.example.com/img/generate ,
Total Time: 28.67s, Error: context deadline exceeded,
Trace: event=DNSDone cost=0.8ms; event=ConnectStart addr=<对端公网IP>:80;
event=ConnectDone (耗时 3.46s); event=WroteRequest; <之后无响应>
拆开这条 trace,卡点一目了然:
- DNS:0.8ms,正常;
- TCP 建连:3.46s(正常应是毫秒级,说明握手就有 SYN 重传);
- 请求写完后,服务端长时间不返回,直到 28s deadline 触发。
先在 SLS 里按报错聚合,确认量级和规律:
aliyun sls get-logs-v2 --region <REGION-A> --project <proj> --logstore <ls> \
--from <ts1> --to <ts2> \
--query '"/img/generate" and "context deadline exceeded" | select date_format(from_unixtime(__time__), '"'"'%H'"'"') as hr, count(*) c group by hr order by hr'
结果很有指向性,两个维度都指向跨境公网。
按天看 —— 爆发式,不是天天稳定:
| 日期 | context deadline exceeded 次数 |
|---|---|
| D1 | 38,222(单日大爆发) |
| D2 / D3 | 10 / 2(几乎为零) |
| D4 | 6,728 |
| D5 | 1,292 |
按小时看 —— 只在中国网络高峰犯,深夜清零:超时几乎全部集中在北京白天到晚高峰(04:00–12:00 UTC,对应北京 12:00–20:00)。单分钟峰值在 07:05 UTC 一分钟 94 次、07:09 UTC 又 40 次;06:30–07:30 UTC 一小时累计 204 次;而北京深夜(13:00 UTC 之后)基本为 0。
「只在中国流量高峰犯、深夜清零、日间量级差几个数量级」——这套特征几乎只有跨境公网链路在高峰拥塞/丢包能解释,基本排除了后端容量、DNS、固定故障。
二、第一刀:证明后端无辜
下游图片服务在腾讯云,日志在腾讯云 CLS。用同一时段的请求量和耗时核对后端表现:
tccli cls SearchLog --region <REGION-B> --TopicId <TOPIC_ID> \
--From <ms1> --To <ms2> --Query '"abc" and "elapsed_ms"' --Limit 1000 --Sort asc
坑预告:CLS 的
SearchLog默认Limit很小,且全文匹配"ERROR"会把日志里任何含该子串的行都带回来。要Limit拉满、按秒分桶看吞吐,不要拿全文匹配的命中数当"错误数"。
后端实测:出图 P50 约 1.1s、P95 约 2.3s,全部 SUCCESS,Pod 零重启。再用 kubectl 交叉验证 Pod 状态,全程 Running、无 OOM。后端无辜。
对照之下,调用方侧成功的请求也要 4s、15s,失败的 28s——后端只花 1~2s,差额全在传输链路上。结合 TCP 握手 3.46s 的 SYN 重传特征,矛头指向跨境公网。
三、关键转折:专线明明有,却没走
聊到这里才发现:两朵云之间早就有专线(阿里云 CEN + 腾讯 CCN + 物理专线)。那为什么还在裸奔公网?
因为上游服务调的是公网域名 api.example.com,它解析到腾讯的公网 CLB IP,流量自然走公网出口。专线在那躺着没被这条调用用上。
于是问题转化为:能不能让这条调用走内网专线? 先做最朴素的连通性对比——从阿里云海外 ECS 去 ping 腾讯内网:
# 腾讯一台节点内网 IP
ping -c 3 10.20.0.18
# --- 100% packet loss
而同在阿里云北京的运维机(专线同侧)却 ping 得通这个 IP。北京通、海外不通——专线本身没问题,是海外这一段没接上。
四、逐层定位:从 CEN 到 CCN 到专线网关
先放一张完整的 CEN + 专线配置详图(可对照复刻):VPC/IP、CEN 的转发路由器(TR)/路由表/跨地域连接 100Mbps/路由策略,专线的 VBR/专用通道/BGP-ASN,腾讯侧的 CCN/VPC 路由表/子网/安全组,都标在图里。

下面按这张图,从阿里云侧往腾讯侧逐层查。
4.1 阿里云侧:CEN 路由是通的
先在阿里云 CEN(企业版转发路由器,TR)上查路由表,确认海外网段有没有传到北京。这里踩了第一个坑:
# 错误:默认只返 20 条,海外网段 10.10.x 排在后面没返回,差点误判"没传过来"
aliyun cbn ListTransitRouterRouteEntries --TransitRouterRouteTableId <tr-rtb> --region <REGION-B>
# 正确:拉满分页
aliyun cbn ListTransitRouterRouteEntries --TransitRouterRouteTableId <tr-rtb> \
--region <REGION-B> --MaxResults 100
拉满后看到 10.10.0.0/24、10.10.1.0/24(海外网段)都已经 Propagated 到北京 TR 路由表。再用 tracepath 从海外 ECS 打腾讯内网,去程能跨境跑到腾讯骨干网段(220ms,跨境 RTT),说明阿里云侧路由、跨境带宽、专线去程全部正常。
4.2 腾讯侧:回程缺了海外网段
去程通,那问题在回程。查腾讯 VPC 路由表:
tccli vpc DescribeRouteTables --region <REGION-B> --Limit 100
# 只有 10.30.0.0/16(阿里云北京) -> CCN,没有 10.10.x(阿里云海外)
回程路由只认了阿里云北京网段,没有海外网段。再往专线网关这一层挖:
# 专线网关发布给 CCN 的路由
tccli vpc DescribeDirectConnectGatewayCcnRoutes --DirectConnectGatewayId dcg-xxxxxxxx --region <REGION-B>
# 列出 7 条:6 个内部互联 /24 网段 + 10.30.0.0/16(阿里云北京),唯独没有 10.10.0.0/16(海外)
再确认这个专线网关到 CCN 的路由模式:
tccli vpc DescribeDirectConnectGateways --DirectConnectGatewayIds '["dcg-xxxxxxxx"]' --region <REGION-B>
# CcnRouteType = STATIC EnableBGP = False
真相大白。要分清两层:
- 专用通道(VBR ↔ 专线网关,物理层)是 BGP 动态;
- 专线网关 → CCN 这一层是 STATIC——发布哪些网段给云联网,是手工维护的静态列表。
而这个静态列表里只有阿里云北京网段,漏了阿里云海外 10.10.0.0/16。所以海外的包能跨境到腾讯,但腾讯不知道怎么把包送回海外——去得到、回不来,表现就是 ping 100% 丢包、TCP 黑洞。
五、打通方案:先修网络,再切流量
找到根因后,解决分两步——先在网络层把专线回程修通,再在应用层把流量切上去。两步缺一不可:只修路不改道,流量还在走公网;不修路,内网根本不通。
5.1 网络层:补专线网关静态网段,打通回程
腾讯云控制台 → 专线接入 → 专线网关 → 「IDC 网段 / 路由」→ 新增 10.10.0.0/16。等价的 CLI:
tccli vpc CreateDirectConnectGatewayCcnRoutes --DirectConnectGatewayId dcg-xxxxxxxx \
--Routes '[{"DestinationCidrBlock":"10.10.0.0/16"}]' --region <REGION-B>
加完立刻验证,一条链路三处自动生效:
# 1. 专线网关已发布
tccli vpc DescribeDirectConnectGatewayCcnRoutes --DirectConnectGatewayId dcg-xxxxxxxx --region <REGION-B> # 出现 10.10.0.0/16
# 2. CCN 学到
tccli vpc DescribeCcnRoutes --CcnId ccn-xxxxxxxx --region <REGION-B> # 出现 10.10.0.0/16
# 3. VPC 路由表自动同步(无需手工加)
tccli vpc DescribeRouteTables --region <REGION-B> --Limit 100 # 10.10.0.0/16 -> CCN
安全组也确认了一下:腾讯节点安全组里本就有 10.0.0.0/8 放通,海外网段在内,无需改安全组。
回到海外 ECS 验证端到端:
ping -c 3 10.20.0.18
# 3 received, 0% packet loss, rtt 223 ms ← 从 100% 丢包黑洞,到 0% 丢包稳定
跨境固有 RTT ~220ms(物理距离决定,专线也省不掉),但丢包没了——这才是 28s 超时的根因所在。
5.2 应用层:建内网 Ingress,把流量切到专线
专线通了,但上游服务还在走公网域名。要切到内网,需要给被调服务一个内网入口,并让上游用它。这里用「内网 Ingress + 独立内网域名」的方案,在腾讯 TKE 里照着现有的公网 Ingress 改一份:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-inner
namespace: prod
annotations:
kubernetes.io/ingress.class: qcloud
ingress.cloud.tencent.com/direct-access: "true"
kubernetes.io/ingress.subnetId: subnet-xxxxxxxx # 内网 CLB 落的子网
labels:
ingress.cloud.tencent.com/loadbalance-type: INTERNAL # 关键:内网
spec:
rules:
- host: api-inner.example.com # 独立内网域名
http:
paths:
- backend:
service:
name: abc-svc # 见下方「坑三」:必须是有后端的那个 service
port:
number: 80
path: /img
pathType: ImplementationSpecific
apply 后拿到一个内网 CLB VIP(10.20.2.34),配上内网 DNS api-inner.example.com → 10.20.2.34,上游服务把目标域名一换,流量就走专线了。
六、四个坑
坑一:用 GET 测一个 POST 接口,被 302/404 带偏
验证内网入口时,顺手 curl 了一下,公网返回 302、内网返回 404,于是一头扎进"为什么状态码不一致"猜了半天 Host、backend。真相是 /img/generate 是 POST 接口,GET 打它,后端返回什么都不奇怪(302/404 全是假象)。
教训:验证业务接口一定用真实的方法和 body。换成 POST + 真实参数后,内外网行为立刻一致。怎么拿到真实参数?去后端 CLS 日志里捞一条真实请求:
tccli cls SearchLog --region <REGION-B> --TopicId <TOPIC_ID> \
--From <ms1> --To <ms2> --Query '"generate request"' --Limit 4 --Sort desc
# generate request={"prompt":"...","upload_key_prefix":"img/20260101/"}
坑二:内网 CLB 第一个实例创建卡住,重建才好
第一次建的内网 CLB,VIP ping 100% 丢包、80 端口 filtered,tracepath 到腾讯边界黑洞。一度怀疑"腾讯内网 CLB 不支持被 CCN 访问"。这个推断是错的——删掉重建一个新 CLB,VIP 立刻可达。就是第一个 CLB 实例 provision 卡住/异常,跟 CCN 支不支持无关。遇到内网 CLB VIP 不通,先重建一次再下结论。
坑三:backend 指向了一个「空 service」
腾讯 qcloud Ingress 实际转发看的是它的 http-rules/spec.backend。排查时发现集群里有两个相似的 service:
kubectl get endpoints abc-empty-svc -n prod # ENDPOINTS <none> ← 空壳,没有后端
kubectl get endpoints abc-svc -n prod # 10.20.0.x:8000 ... (14 个 Pod)
abc-empty-svc 是个没有任何 endpoint 的空 service(从它的 ClusterIP 发起连接直接 connection refused)。内网 Ingress 的 backend 一旦指到它,就不通。必须指向有真实 Pod 的 abc-svc。
坑四:ListTransitRouterRouteEntries 默认只返 20 条
前面提过——阿里云 CEN 查 TR 路由条目,aliyun cbn ListTransitRouterRouteEntries 默认分页 20 条,关键网段排在后面就被截断,直接误导出"路由没传过来"的错误结论。永远带 --MaxResults 100,并留意返回里的 NextToken。
七、验证:真实出图,内网 1.6s vs 公网 2.2s
用从日志捞到的真实 body,内外网各打一发对照:
# 内网(走内网 VIP,--resolve 强制解析)
curl -X POST --resolve api-inner.example.com:80:10.20.2.34 \
-H 'Content-Type: application/json' \
-d '{"prompt":"a 1970s discotheque in a snowy alpine landscape","upload_key_prefix":"img/20260101/"}' \
-w '\n[code=%{http_code} total=%{time_total}s]\n' \
http://api-inner.example.com/img/generate
# {"code":0,"data":{"out_imgs":["img/20260101/xxxx.jpg"]}} [code=200 total=1.63s]
# 公网对照
# {"code":0,"data":{"out_imgs":["img/20260101/yyyy.jpg"]}} [code=200 total=2.24s]
两边都 code=0 真实出图、功能完全一致;内网 1.63s vs 公网 2.24s。GPU 出图本身 ~1.4s 是一样的,差在网络:内网专线握手快且稳定——切内网解决的是"高峰偶发暴雷(28s)",而不是日常快几百毫秒。
再用两次请求的 trace_id 去 CLS 反查落点,确认内外网打到的是同一套 abc deployment 的 Pod(只是不同副本),后端一致。收工。
八、三天后复查:这个"超时归零"是真的吗?
修复当天的漂亮数字不算数——改完容易一时好转、过几天又回潮。隔了三天回头查,这次带着一个问题:这个"0"会不会是假象?
先看趋势,还是那条 SLS 聚合,按天数 /img/generate 的跨境超时:
日期 context deadline exceeded 次数
06-02 30
06-03 380
06-04 1390 ← 峰值(故障当天)
06-05 22 ← 修复落地,收尾的零星
06-06 0
06-07 0
06-08 0 ← 连续三天归零
峰值 1390 一路降到连续三天 0。但"日志查不到"有三种假象,逐一排除才敢说真归零:
① 采集断了? 查同一个 logstore 的全量超时(不限这个接口),06-06/07/08 每天仍有几万条(66330 / 20317 / 11266)——日志在正常进来,不是采集挂了导致的空。
② 没流量了? 万一这几天根本没人出图,自然不超时。查监控里的出图请求量,每天增量稳定在 ~9 万(90526 / 58809 / 89247),出图一直在正常跑。
③ 真切到专线了,还是公网碰巧通畅? 这点最该坐实——前两条排除了"假 0",但"超时为 0"既可能是流量切到了内网专线,也可能是公网这几天恰好没拥塞。登上游服务所在的海外 ECS 实测:
# 内网域名现在解析到哪
$ getent hosts api-inner.example.com
10.20.2.34 api-inner.example.com # ← 内网 VIP(专线)
# /etc/hosts 里那行其实还是注释态 —— 靠内网 DNS(PrivateZone)生效,不是 hosts
$ grep api-inner /etc/hosts
#10.20.2.34 api-inner.example.com
# 当前出图的 established 连接,到底连内网还是公网
$ ss -tn | grep -E '10.20.2.34|<对端公网IP>' | awk '{print $5}' | sort | uniq -c
4 10.20.2.34:80 # 内网专线:4 个活跃连接
# 公网 <对端公网IP>:80 —— 0 个
内网 4 个活跃连接、公网 0 个——流量是真切到专线了。归零的真因是"残留流量切上了内网",不是"公网碰巧没犯病"。修复当天内网 DNS 还没配好、上游还在用公网域名(所以 06-05 还剩 22 条);这三天 DNS 落地、上游用上内网域名,才彻底干净。
一个教训:改完别只看当天数字。几天后带着"会不会是假 0"的怀疑再复查一遍,把采集没断、流量正常、链路实际走向三样都验证过,才算真闭环——尤其"超时归零"这种结论,既可能是真修好,也可能是诱因恰好消失,不实测链路根本分不清。
快速参考
排查链路(从现象到根因)
- SLS 聚合超时,看时间规律(高峰才犯 → 怀疑跨境公网);
- CLS +
kubectl证明后端无辜(后端 1~2s,差额在传输); - 海外
ping腾讯内网对比"北京通/海外不通" → 专线没接上海外; - 阿里云 CEN 路由 → 腾讯 VPC 路由 → CCN 路由 → 专线网关静态网段列表,逐层下钻;
- 找到
CcnRouteType=STATIC的网段列表漏了海外网段。
关键命令速查
# 阿里云 CEN:查 TR 路由条目(务必带 --MaxResults)
aliyun cbn ListTransitRouterRouteEntries --TransitRouterRouteTableId <tr-rtb> --region <R> --MaxResults 100
# 腾讯:VPC 路由 / CCN 路由 / 专线网关发布的网段
tccli vpc DescribeRouteTables --region <R> --Limit 100
tccli vpc DescribeCcnRoutes --CcnId ccn-xxxx --region <R>
tccli vpc DescribeDirectConnectGatewayCcnRoutes --DirectConnectGatewayId dcg-xxxx --region <R>
tccli vpc DescribeDirectConnectGateways --DirectConnectGatewayIds '["dcg-xxxx"]' --region <R> # 看 CcnRouteType
# 专线网关补一条静态网段(打通回程的关键)
tccli vpc CreateDirectConnectGatewayCcnRoutes --DirectConnectGatewayId dcg-xxxx \
--Routes '[{"DestinationCidrBlock":"10.10.0.0/16"}]' --region <R>
铁律 / 易错点
- 跨云专线双向都要通:去程靠阿里云 CEN 把网段传过去,回程靠腾讯专线网关把对端网段加进发布给 CCN 的静态列表——只配一边等于没配。
- 专用通道 BGP ≠ 专线网关→CCN 的 STATIC,别被"专线是 BGP"误导,后者是手工网段列表。
- 验证业务接口用真实方法 + 真实 body,别用 GET 测 POST,状态码会骗你。
- 内网 CLB 的 backend 必须指向有 endpoint 的 service(
kubectl get endpoints先看一眼,<none>的是空壳)。 - 内网 CLB VIP 不通先重建一次再排查。
aliyun cbn ListTransitRouterRouteEntries默认 20 条,--MaxResults 100,别被分页截断误判。- 跨境专线根治的是丢包/抖动/超时,固有 RTT(物理距离)省不掉。

浙公网安备 33010602011771号