背景

2020 年前后,我在大连 R 公司负责车联网平台协议解析层的开发和维护。R 平台是一套部署在公有云上的 IoT 平台,接入大量在线车载设备,实时处理车辆上报的行车数据。

那时平台有一项新的合作需求:一家做共享汽车业务的公司(以下简称 M 公司)采购了 R 公司的车载设备,安装在共享汽车上,希望通过接口从 R 平台获取这些车辆的实时行车数据,再通过自己的 App 提供给用户查询车辆状态和行驶记录。

我负责这次集成的开发工作,包括改造行车数据服务的分流逻辑,以及独立开发一个面向 M 公司的数据推送服务。这也不是我第一次做类似的事,R 平台之前也有过给其他第三方提供数据接口的项目,但 M 公司是其中规模比较大的一家。

技术方案

行车数据服务本身改动不大。原来的逻辑是收到设备上报的数据后直接写入平台内部各个下游。这次只是加了一段分流逻辑:根据车辆底盘号(VIN)查询 Redis 中的客户映射关系,如果这辆车属于 M 公司,就把这条数据额外发送到一个专用的 Kafka topic。

Kafka topic 的另一侧是我新写的 Go Kafka consumer,消费消息后做数据格式转换,处理鉴权,再通过 HTTP POST 批量推送给 M 公司的接口。推送时有一个打包策略:收到 N 条数据就打包发出,或者超过一定时间没有新数据也把当前这批发出,每次 HTTP 请求可能包含多条记录。

VIN 到客户的映射关系存储在 Redis,由业务侧维护,数据服务只做读取。

工程细节

可观测性

对接第三方的接口,出问题时的排查成本比内部服务高很多——双方都需要对齐日志,搞清楚是哪一侧的问题。

我在这个服务里做了几件事:

每一批次数据带一个唯一的 trace ID,日志里记录发送时间、trace ID、完整 payload、M 公司 API 的响应时间和状态码。在调试阶段和试运行阶段,日志级别调到 debug,把 payload 全量打印出来,方便排查数据是否正确、格式是否符合对方预期。

除了日志,我还在服务里埋了监控指标,记录推送并发量和调用对方 API 的响应时间,接入 R 平台已有的 Grafana 看板,可以直观看到推送量和延迟的变化趋势。

这些日志和监控在后来的联调和生产运行中都用上了。一旦出现数据异常或推送延迟,可以很快定位是哪个环节的问题。

联调排查:带宽瓶颈

正式与 M 公司联调前,我在内网做过完整的压力测试,并发量完全满足要求。但第一次跟对方联调时,并发量明显跑不上去,远低于预期。

代码逻辑没有变,我一时没想清楚原因。后来才意识到:内网测试用的是公有云内网,那时候还没开通公网出口。准备联调时才给这个服务配置了公网出口,而出口带宽会影响计费,测试阶段只开了 1Mbps,根本不够用。

开通外网出口之后,我们只做了业务功能测试,没有再跑压测。带宽这个问题就这样漏掉了,直到联调时才暴露。把出口带宽调高之后,问题就解决了。

这个问题现在看起来不复杂,但当时确实没有在第一时间想到。根本原因是:开通公网出口是在内部压测之后才做的,两件事在时间上是分开的,带宽配置的低限制没有记录到任何地方。

一个可以改进的做法是:在设计阶段把服务依赖的外部资源列出来,包括带宽、下游 API 限流规格等,并把已知的临时限制记到 backlog 里。这样在外部联调或上生产之前,有一个可以核查的清单,类似这样的问题就不容易漏掉。

在另一次类似的第三方集成联调中,也遇到过一个问题:我们发出了 HTTP 请求,但没有收到响应;对方却反馈说没收到我们的请求。两边的说法对不上。

我在服务器上用 tcpdump 抓包,可以看到 TCP 三次握手成功,后续的 HTTP 请求发出后也收到了对方 TCP 层的 ACK,证明数据确实到达了对方。但我们一直没有收到 HTTP Response。这说明应用层收到了请求,但没有处理或返回。有了这个抓包结果,就可以明确排除我方网络和代码的问题。最终对方排查后确认,是他们自己的业务代码有问题。