滴滴国际商旅面试 — 口语化回答库(可直接背诵)
候选人:吴来象 | 目标:滴滴国际商旅后端负责人 使用说明:每个回答按真实口述节奏组织,1-2 分钟篇幅,背诵后稍作停顿即像自然对话。 核心原则:真实经历讲透,业务认知讲"了解"的深度,方法论讲"可迁移"。
一、开场:自我介绍
Q:请你做个自我介绍。
好的,面试官。我叫吴来象,到现在有 12 年后端研发经验,6 年技术团队管理经验,带过最大的团队是 20 多个人。
我把自己的能力总结成三句话:第一是 OTA 国际化的 0-1 建设,第二是千万级高并发交易系统,第三是跨境支付和多币种结算。
我前面 12 年是在携程,负责火车票的预订、订单、数据、还有国际业务这几个核心团队,团队从 5 个人一路扩到 20 多个人。期间有三件比较有代表性的工作:一个是主导了国际火车票 GDS 从 0 到 1 的搭建,整合了中英法德意多国铁路;第二个是把订单系统做了重构,日均订单峰值从 100 万提到了 1000 万这个量级,可用性做到 99.99%;第三个是独立负责抢票系统,拿了集团年度的 CEO 大奖。
因为在携程 12 年,依托集团生态,我对机票、酒店这些核心 OTA 业务的产品形态、供应链、交易链路也比较熟悉。
离开携程之后这两年我去做了技术合伙人,从 0 到 1 搭了一个 IoT 共享平台,还有一个定制游平台——里面用到了 Stripe 的跨境支付和多币种定价,另外还做了一个 AI 客服系统。
这次看滴滴国际商旅这个机会,是因为它要的三件事——OTA 国际化、跨境支付、0-1 团队搭建,正好是我过去十几年能力的交集。而且 JD 里也提到倾向能把携程经验应用到滴滴的候选人,这刚好是我的差异化优势。大概就是这样。
二、项目深挖:国际火车票 GDS(最高频,必背)
Q1:介绍一下国际火车票 GDS 这个项目。
这个项目是我在携程做的,背景是集团当时启动国际化战略,需要从 0 到 1 搭一个全球火车票的分销系统。简单说就是把中国、英国、法国、德国、意大利这些国家的铁路产品整合起来,对上给携程各个业务端提供统一的预订、出票、退改签接口。
我当时是技术经理,负责整个项目的战略规划、架构设计,还有团队从 0 到 1 的组建,以及跟海外供应商的对接。
这个项目最难的地方在于各国铁路系统差异特别大——车次编码不一样、席别定义不一样、退改签规则也完全不同。我的核心做法是抽象了一套统一的铁路产品模型,分成"标准车次、标准席别、标准退改签策略"三层,向上提供标准化接口,向下用适配器模式去对接每个国家的供应商,把差异屏蔽在适配层。
另外在国际化这块,我设计了多语言适配、多币种结算、还有多机房部署的架构,来满足各个国家的数据安全和出境合规要求。
最后项目顺利上线,给携程火车票的国际化打了个底。这套 GDS 分销的架构模式,我自己觉得是可以平移到机票、酒店这些业务的,因为方法论是一样的。这是这个项目大概的情况。
Q2:你说的"统一产品模型"具体怎么抽象的?退改签规则差异怎么屏蔽?
好,我具体说一下。我们当时遇到的核心问题就是,比如中国铁路的席别是硬座软座硬卧软卧,英国是 Standard、First Class,德国又有一套自己的叫法,退改签规则更是千差万别——有的能退有的不能退,有的提前 24 小时能改,有的开车前 2 小时就不能操作了。
我的做法是不去试图统一它们的原始规则,而是抽象一个标准层。具体讲就是三层:
第一层是标准车次,我们把车次抽象成"出发站、到达站、出发时间、到达时间、历时"这几个标准字段,不管原始系统怎么编码,对上都长一样。
第二层是标准席别,我们定义了一套标准的席别枚举,比如经济席、商务席、卧铺,然后每个国家的实际席别映射到这个标准枚举上,映射关系配在适配层。
第三层也是最关键的是退改签策略,我把它抽象成一个策略对象,包含"是否可退、退票手续费规则、是否可改、改签规则、时间窗口"这几个标准属性。每个国家供应商的原始规则,在适配层翻译成这个标准策略对象。
这样做的好处是,上层业务代码完全不需要知道底下是哪个国家的铁路系统,拿到的都是标准模型。如果新增一个国家,只需要写一个适配器,把它的原始数据翻译成标准模型就行,核心代码一行都不用动。这个思路其实跟机票的 GDS、NDC 是一样的——NDC 本质上也是一种统一产品模型。
Q3:多机房部署具体怎么做的?数据怎么同步?合规怎么落地?
多机房这块,我们当时是根据业务覆盖的国家来选机房的,比如欧洲用户就走欧洲的节点,亚洲用户走亚洲节点,做到就近访问,降低延迟。
数据同步方面,我们遵循一个原则——不做跨区的强一致多活。原因是各国数据出境合规要求不一样,欧盟的 GDPR 对用户数据出境有严格限制。所以我们的设计是用户数据在对应合规区本地落库,跨区只传脱敏或者聚合后的数据。比如订单数据,用户的基本信息和订单明细存在本地机房,但统计层面的聚合数据可以同步到中心做全局分析。
合规落地这块,主要几个点:一是数据本地化存储,欧盟用户数据存欧盟机房;二是传输全程加密,敏感字段做字段级加密;三是提供数据主体权利的接口,比如用户要删数据,要走级联删除;四是跟供应商签数据处理协议,也就是 DPA。
这套实践其实跟携程后来公开的全球化架构思路是一致的——他们提的"全球多 Region 加全球多合规区",核心就是解决"数据局部隔离和 OTA 业务全局性"这个矛盾。这块我在集团内是有了解的。
Q4:海外供应商怎么对接的?SLA 怎么定义?对账怎么搞?
供应商对接这块,每个供应商的接口标准都不一样,有的给 Web Service,有的给 API,还有的干脆给文件。我的做法是定义一套统一的接入规范,每个供应商实现一个适配器,适配器负责把供应商的协议翻译成我们内部的标准接口。
SLA 这块,我们会跟供应商谈几个核心指标:一个是接口可用性,一般是 99.5% 以上;一个是响应时间,比如搜索接口 P95 在 2 秒内;还有一个是出票成功率,这个是业务指标,不同供应商不一样。
对账是比较麻烦的一块,因为涉及多币种。我们的做法是每笔交易记录四元组——本币金额、外币金额、汇率、通道费,T+1 跑对账,差异自动归因。常见的差异来源就那么几种:汇率波动差、通道手续费、退款未同步、供应商结算延迟。我们对账系统会自动把差异分类,异常的再人工介入。
这套对账思路其实跟我后来做 Stripe 跨境支付的对账是一样的,只是机票的对账会更复杂,因为还涉及 GDS 的 BSP 结算周期,但底层逻辑是通的。
Q5:这个项目你遇到的最大挑战是什么?
说实话最大的挑战不是技术,是跨国协作。因为供应商都在海外,有时差,沟通成本很高;而且每个国家的业务方对规则的理解也不一样。
我当时的解决办法是建立异步为主的协作机制——重要决策全部文档化,用 RACI 表把谁负责、谁审批、谁知情写清楚;定期做跨时区的 standup,但频次不高,关键靠文档驱动。另外我让团队把技术方案都写成中英双语,方便海外同事看。
还有一个挑战是团队从 0 到 1,一开始招人很难,因为既懂铁路又懂技术的复合人才很少。我的策略是先招架构能力强的人,铁路业务知识可以补;然后从业务方那边借调了几个懂规则的人做业务顾问,技术团队和业务顾问配合。这个经验我觉得对滴滴国际商旅也适用,因为商旅同样需要跨文化协作。
三、项目深挖:千万级订单重构
Q1:介绍一下订单系统重构这个项目。
这个项目的背景是,携程火车票的订单系统当时日均峰值大概 100 万,但业务增长很快,老系统撑不住了,性能有瓶颈,稳定性也在下降。集团给我们的目标是支撑未来 10 倍增长,也就是要扛到 1000 万这个量级。
我主导了这次重构,核心做了三件事:
第一是微服务拆分。我们按领域把老的订单系统拆成了 8 个独立的子系统——退票、改签、保险、订单主服务这些,把耦合打开,每个子系统独立部署独立演进。
第二是分库分表。我设计了按订单号分 8 个库,再加读写分离。具体做法是发号阶段就把分片位嵌进订单号,路由的时候直接提取分片位定位库,不用 hash 也不用查表。分片键选的是订单号而不是用户 ID,这个选择是经过考量的,我可以展开讲。
第三是订单状态机和消息队列解耦。主逻辑走同步,比如下单、支付这些;旁路逻辑走异步,比如通知、统计、风控,全部丢到消息队列异步处理,这样主链路的吞吐就上来了。
最后结果还不错,日均峰值从 100 万提到了 1000 万+,可用性做到 99.99%,而且稳定运行到现在没有重大故障。这个项目对我个人的锻炼很大,让我真正理解了高并发系统设计要怎么做取舍。
Q2:分片键为什么选订单号而不是用户 ID?
这个问题当时我们团队内部也讨论过很久。选订单号主要有三个考虑:
第一,订单号是查询的主入口。用户查订单、客服查订单,都是拿订单号来查,按订单号分片之后,单库就能闭环完成订单详情查询,不需要跨库聚合。
第二,避免热点。如果我们按用户 ID 分,那企业大客户一个用户一天可能下上万单,全压在一个分片上,这个分片就成热点了。我们发号的时候根据负载选目标库,订单天然分散到不同分片,发号服务会自动往负载低的库倾斜,热点问题就规避了。
第三,路由效率。我们在订单号里内嵌了分片位,比如订单号末两位就是库号,这样路由的时候不用查表,直接从订单号提取分片位定位库,性能很好。
当然也有代价,就是跨用户的查询会比较麻烦,比如"某个企业这个月所有订单",这种我们就走 ES 异步索引,订单产生的时候异步同步一份到 ES,按用户维度建索引,查询的时候走 ES。这样写路径还是按订单号分片保证性能,读路径用 ES 保证灵活查询。
Q3:如果要扩容,比如从 8 库扩到 16 库,怎么搞?
扩容是个很实际的问题。我们的做法是倍数扩容加双写灰度。
倍数扩容的好处是分片规则可以平滑迁移,因为 8 到 16 是 2 倍关系,原来的一个分片可以拆成两个,数据迁移的映射关系是确定的。
具体步骤是:先建好新的 16 库,然后开始双写,新数据同时写老库和新库;老数据做后台迁移;迁移完之后读流量灰度切到新库,比如先切 1%,观察没问题再放大;全部切完后停老库的写,保留一段时间只读,作为兜底;最后彻底下线老库。
整个过程一定要保留回滚链路,一旦新库有问题,能立刻把读写切回老库。这个灰度切流的思路,我后来做 .NET 到 Java 的迁移也是用的同一套方法论。
Q4:99.99% 的可用性具体怎么保障的?
99.99% 换算下来一年最多宕机 52 分钟左右,这个标准挺高的。我们主要靠这么几手:
第一是多机房部署,同城双活加异地灾备,任何一个机房挂了业务能自动切换。
第二是多级限流和熔断,网关层、服务层、接口层都有限流,防止下游被冲垮;服务调用都加了熔断,比如退票服务挂了,不能把订单主服务也拖死。
第三是全链路可观测,每个请求都有 TraceId,关键指标都有大盘和告警,出问题能快速定位。
第四是灰度发布加一键回滚,上线一定是灰度,出问题秒级回滚。
还有一个容易被忽略的是故障演练,我们会定期做 Chaos 故障注入,主动把某个服务搞挂,看系统的容灾是不是真的生效。不演练的容灾都是纸面上的,真出事就抓瞎。这套稳定性建设的思路,我觉得可以直接搬到滴滴商旅来用。
四、项目深挖:TripPlan 跨境支付
Q1:介绍一下 TripPlan 这个项目。
这个是我离开携程之后做的,背景是面向入境游市场,用大模型替代旅行社的人工行程规划。原来游客要定制一个行程,旅行社人工要搞 2 到 5 天,我们用大模型把这件事压缩到对话级的交互就能完成,然后还要接入在线支付。
我负责整体架构设计,技术栈用的是 Python 加 FastAPI 异步框架,数据库是 PostgreSQL。核心难点是怎么把大模型的不确定性和交易的安全性平衡好——大模型可能会胡说八道,但钱的事情不能错。
我的核心设计是用 DDD 把系统拆成 9 个模块,让大模型只管理解用户意图和生成行程方案,而价格计算、订单状态、资金流转这些跟钱相关的,全部由代码严格控制,不让大模型碰。这样即使大模型出了问题,最多是行程方案不合理,不会影响交易安全。
支付这块,我们对接了 Stripe 的 PaymentIntent 加 Webhook,支持美元、欧元、人民币多币种,还做了 30% 预付款加尾款的两段式支付。最后项目完整落地,验证了跨境支付和多币种定价的工程能力。
Q2:多币种怎么避免精度丢失?
精度这个问题看着小,但在跨境支付里是最大的坑之一。我用的核心办法是全程 BigDecimal,绝对不用 double。
具体来说,我做了一个币种精度枚举统一管理,因为不同币种的小数位是不一样的——美元欧元是 2 位,日元韩元是 0 位必须取整,巴林第纳尔是 3 位。这些规则不能硬编码在代码里,要做成枚举配置。
然后四舍五入、截断、进位这些策略也要可配置,因为不同场景规则不一样,比如展示给用户的时候可能四舍五入,但实际扣款的时候得按规定来。
汇率这块我做了锁汇机制——用户下单的时候,当时的汇率会锁定写进订单,后面结算的时候按这个锁定的汇率走,不会因为汇率波动让商户亏钱。展示侧可以用实时汇率,但成交侧必须用锁定汇率。这个思路其实跟携程商旅那个多币种结算专利是一样的,他们叫"固化汇率",我是后来看到那个专利发现思路是一致的。
Q3:Stripe 跨境支付怎么对接的?幂等怎么做?
Stripe 的对接我用了一个适配层,把 Stripe 的 PaymentIntent 和 Webhook 封装起来,对上提供统一的支付接口。这样如果以后要换通道,比如换 Adyen 或者 PayPal,上层代码不用动。
幂等这块是重点,跨境支付最怕重复扣款。我做了几层:
第一层是 Stripe 本身的幂等键,每次请求带一个唯一的 Idempotency Key,Stripe 侧保证同一个 key 不会重复处理。
第二层是我们自己的业务幂等,订单号加支付场景作为幂等键,落 Redis 做占位,重复请求直接返回首次结果。
第三层是 Webhook 回调的幂等,因为 Stripe 的回调可能会重发,我们收到回调先看本地有没有处理过这个事件 ID,处理过就跳过。
还有一个特别重要的点——超时不盲目重试。如果调 Stripe 超时了,绝对不能直接重试,因为可能钱已经扣了只是响应没回来。我们的做法是先主动查 Stripe 的接口确认这笔交易的真实状态,只有确认是明确失败了才重试。这个叫"查询后置重试",是跨境支付里防资损的关键。
Q4:大模型和交易系统怎么结合的?怎么保证不出事?
这块我们当时想得比较谨慎。核心原则就是把大模型关在它擅长的笼子里。
大模型擅长的是理解用户意图、生成方案、做内容创作。所以需求收集模块、行程引擎模块、约束校验模块,这些让大模型来干——用户说"我想去欧洲玩 10 天,预算 2 万",大模型理解这个意图,生成一个行程方案。
但大模型不擅长的是精确计算和状态管理。所以定价、订单状态机、支付适配这些,全部是传统代码,大模型完全不碰。价格就是基准价乘以季节系数乘以数量,覆盖景点、酒店、包车、导游、交通、餐饮六类资源,算得很死。
订单状态机我设计了 11 个状态的有向流转,状态迁移必须经过校验,禁止跳态。核心算法都有自动化测试覆盖。
这样的好处是,即使大模型抽风给出了不合理的行程,最坏的情况就是用户不满意重新生成,但不会出现钱算错、订单状态混乱这种硬伤。这个设计思路我觉得对商旅也适用——商旅如果用 AI 做差旅政策推荐或者行程规划,同样要把资金和合规相关的逻辑用代码死死管住。
五、项目深挖:全自动出票系统 & 抢票系统
Q1:全自动出票系统怎么做的?
这个项目的背景是,火车票出票需要紧跟 12306 的更新节奏,原来人工出票效率低、错误率高。我们要实现出票全流程自动化。
我的核心设计是多引擎互备。具体讲就是做了三个服务:出票服务、调度服务、还有 12306 爬虫服务。这三个引擎互相备份,任何一个单点故障都不影响整体出票能力。
调度服务是核心,它负责协调分配任务,跟爬虫服务交互去模拟官网操作,实现扣位、出票、退改签全自动化。多个出票引擎并发跑,调度服务根据各引擎的健康状态和负载来分配任务。
另外我们做了一个监控大盘,实时看出票成功率、平均耗时、还有失败归因。失败了要能分析出来是 12306 的问题、网络问题、还是我们自己代码的问题。
上线之后出票成功率和稳定性都是行业领先的,年均给公司节省了数百万的运营成本。这个"多引擎冗余加调度服务加监控归因"的治理框架,我觉得可以平移到机票出票,只是机票的引擎换成 GDS 报文层和 NDC 直连通道,治理思路是一样的。
Q2:抢票系统拿 CEO 大奖,亮点在哪?
抢票是火车票业务的核心战役,春运抢票是市场占有率第一的关键。我当时独立负责抢票票台。
亮点主要是三个设计:
第一是任务分级。不是所有抢票请求一视同仁,我们按用户优先级和车次热度做分级调度,高价值用户和高热度车次优先处理。
第二是多引擎并发。多个出票引擎并发去抢,哪个先成功就用哪个,提升命中率。
第三是最有技术含量的——余票预测加任务合并。我们会预测余票什么时候释放,在释放的时点集中火力去抢;同时把同车次的多个用户的抢票任务合并,减少无效请求。这个能极大提升效率,因为 12306 的余票不是实时释放的,是有节奏的,摸清节奏就能精准命中。
这套"高频探测加任务合并加多引擎并发"的思路,其实在商旅旺季机票库存争抢的场景也是同构的,比如十一、春运这种热门时段的机票,本质也是抢库存。
六、架构设计题
Q1:如果让你设计滴滴国际商旅的机票搜索下单系统,QPS 1 万,多国多币种,你怎么设计?
好,我从分层来讲。
接入层,我会做多 Region 网关,海外用户就近接入海外节点,按合规区分流,这一层主要是降延迟和满足数据合规。
搜索聚合层是重点。机票的搜索是多引擎的,有 GDS 的 Amadeus、Sabre,有 NDC 直连,还有自有缓存运价。我会用异步并发去查这些引擎,每个引擎设超时,比如 800 毫秒,超时的引擎返回缓存结果或者降级——部分结果先展示给用户,后台异步刷新。结果统一用产品模型归一排序再返回。
缓存层做多级,本地 Caffeine 加 Redis。热门航线主动预热,运价缓存加 AV 实时校验防止超卖。这里有个关键点是缓存只用于展示和初筛,成交前必须实时验价。
下单层走状态机驱动,验价、建 PNR 占位、支付、出票,每一步都是状态流转。商旅会有组合订单,机加酒加车,我用主订单加子订单的双层状态机,再用 Saga 模式做分布式编排,补偿动作预定义好,比如机票出票失败就自动退酒店。
支付层做多币种定价,BigDecimal 加币种精度枚举,固化汇率,跨境通道用适配层屏蔽 Stripe、Adyen 这些差异,Webhook 幂等加查询后置重试。
稳定性这块,多级限流、熔断、全链路 TraceId、灰度发布、一键回滚,这套是标配。
大概就是这么一个分层架构。
Q2:GDS 调用慢,平均 2 秒,怎么优化搜索响应?
GDS 慢这个问题是机票业务的痛点,因为 GDS 是个老系统,响应就是慢。我的优化思路是几个方面:
第一,异步并发加超时降级。多个 GDS 并发查,设一个合理的超时,比如 800 毫秒,超时的引擎不阻塞整体,返回缓存结果或者先返回部分结果,后台异步刷新。用户看到的是"价格可能变化,点击时实时确认"。
第二,多级缓存。热门航线的运价缓存到 Redis,TTL 设短一点比如 5 分钟;AV 余座单独缓存,因为余座变化比价格快。冷门航线惰性加载,不预热。
第三,预热策略。基于历史查询数据预测热点,主动把热门航线的缓存填满,这个携程机票就是这么做的。
第四,结果异步刷新。先返回缓存结果给用户,标记"价格可能变化",后台异步更新缓存,用户真正点击下单的时候强制走实时验价。
第五,GDS 连接层优化。长连接复用减少握手开销,连接池调优。
核心思想就是,缓存负责快,GDS 负责准,两者结合。展示用缓存保证快,成交用实时验价保证准。
Q3:机票库存是动态的,缓存和实际不一致怎么办?怎么防超卖?
这个问题是机票系统的核心矛盾。我的处理原则是——缓存只用于展示和初筛,绝对不作为成交依据。
具体讲,用户搜索的时候看到的航班和价格是缓存数据,可能跟实际有差异。但用户点击下单的时候,系统会走一次实时验价,也就是 Repricing,确认当前的真实价格和库存。验价通过之后,再去 GDS 建占位,也就是创建 PNR 锁舱,这一步是原子操作,GDS 层面会锁住这个舱位。
如果占位失败,说明舱位被抢了或者价格变了,系统会走"重新验价加推荐替代"流程,给用户推荐其他航班。
缓存更新这块,舱位变化的时候 GDS 会推送,或者我们主动轮询,更新缓存的同时标记失效。
极端情况,如果缓存全失效了,那就走实时 GDS 查询,牺牲速度保准确。宁可慢一点,也不能超卖。商旅场景超卖更麻烦,因为是企业客户,体验损失更大。
Q4:商旅组合订单,机加酒加车,状态怎么协同?
组合订单的状态协同是个有意思的问题。我用的是主订单加子订单的双层状态机加 Saga 编排。
每个子订单——机票子订单、酒店子订单、用车子订单——各自有独立的状态机,走自己的生命周期。主订单的状态是由子订单聚合来的,比如"全部子订单已确认"主订单才"已确认","任一子订单出票失败"主订单就"异常"。
协同的关键是 Saga 编排。我预先定义好正向流程和补偿动作。比如机票出票成功、酒店预订成功、用车预订成功,这是正向;如果机票出票失败,那已经预订的酒店和用车要自动退款,这是补偿。每个补偿动作都是预定义的,不是出了问题再临时想。
另外还要处理部分成功的场景,比如机票成功酒店失败,这时候要决定是整体回滚还是降级处理,这个根据业务规则来配置。商旅的话,一般倾向于整体成功或者整体回滚,因为企业客户不希望出现"机票买了但没地方住"这种半成品状态。
七、技术八股(口语化)
Q1:Redis 为什么快?zset 底层是什么?
Redis 快主要有四个原因。第一是纯内存操作,数据都在内存里,这是根本。第二是核心命令执行单线程,避免了多线程的锁竞争和上下文切换。这里补一句,Redis 6.0 之后引入了 IO 多线程,也就是网络读写多线程,但命令执行仍然是单线程,所以本质还是单线程模型,这点被追问的话要讲清楚。第三是 IO 多路复用,用 epoll 实现一个线程处理大量连接。第四是数据结构设计得高效。
zset 的底层是组合结构,小数据量用 ziplist,大数据量用 skiplist 加 dict。这里补个细节,Redis 7.0 之后 ziplist 被 listpack 替代了,主要是为了修复 ziplist 的连锁更新问题,但整体设计思路没变,面试官追问 7.0 的话要能接住。skiplist 负责按 score 范围查询,多层指针,查找是 O(logN);dict 负责 member 到 score 的反查,O(1)。为什么用 skiplist 不用 AVL 树或者红黑树呢?因为 skiplist 实现简单、并发友好、而且范围查询效率高,zset 经常要做范围操作,skiplist 更合适。
Q2:分库分表怎么考虑的?拆分依据是什么?
分库分表我主要考虑这么几个维度。第一是分片键的选择,这个最关键。我一般会选查询的主入口作为分片键,比如订单号,这样单库能闭环完成核心查询。这里要强调一个细节,我们不是事后对订单号做 hash,而是在发号阶段就把分片位嵌进订单号——发号服务根据负载选目标库,生成带分片位的订单号,后续路由直接从订单号提取分片位,不用查表也不用再 hash,性能更好。第二是库表数量的规划,要按未来 3 年的容量预估,单库单表控制在 1000 万行以内,数量上选 2 的幂次方便于扩容。第三是扩容方案,提前规划好倍数扩容的路径,用双写灰度切流。第四是跨片查询的处理,走 ES 异步索引或者离线数仓,不直接扫库。第五是全局唯一 ID,用 Snowflake 或者号段模式,Snowflake 要注意单机时钟回拨问题,可以靠 NTP 监控加回拨拒绝生成;号段模式要应对 DB 依赖问题,做双 buffer 预加载。
Q3:分布式锁怎么实现?Redis 挂了怎么办?
分布式锁我用 Redis 实现,核心流程是加锁、操作共享资源、释放锁。加锁用 SET key value NX EX,value 要设成唯一标识防止误删别人的锁;释放锁用 Lua 脚本,把判断和删除做成原子操作,避免误删;业务执行时间长的还要加看门狗续期,或者主动兜底查询。
Redis 挂了的情况,要有降级方案。核心幂等键我会落 DB 唯一索引兜底,Redis 挂了走 DB 校验,性能下降但保证正确。也可以切本地 Caffeine 令牌桶,牺牲一点集群一致性换可用性。另外 Redis 挂的时候要触发降级限流,保护 DB 不被冲垮。
Q4:MySQL 给大表加列,线上有读写,怎么办?
直接 ALTER 大表会有锁表风险,即使 5.6 之后有 online DDL,元数据锁还是可能阻塞线上读写。我的做法是用 gh-ost 或者 pt-online-schema-change 这类工具,原理是建一张影子表,通过 binlog 或者触发器把数据同步过去,原表无锁。同步完之后切表名。
另外一个思路是分批操作,先加一个可空的列,这个操作是瞬时的;然后分批回填数据;最后再加默认值或者非空约束。整个过程在低峰期执行,并且监控延迟,预留好反向迁移的回滚脚本。
Q5:高并发下怎么保证订单接口幂等?
幂等我做多层防御。第一层客户端,每次请求带业务幂等键,比如业务前缀加用户 ID 加时间戳 hash,服务端用 Redis SETNX 占位。第二层接口层,同一个幂等键重复请求直接返回首次结果,把首次响应缓存起来。第三层数据库,订单号唯一索引兜底,插入冲突就走"查询已有订单"的分支。第四层支付回调,Webhook 幂等键加主动查询后置重试。
商旅还有个特殊场景是企业批量下单,一次提交 50 个人的机票。这种我用批次号做幂等键,批次内逐单走状态机推进,部分失败可以重试单条而不重放整个批次。
Q6:缓存穿透、击穿、雪崩分别怎么解决?
穿透是查不存在的数据穿到了 DB,用布隆过滤器拦截,加上空值缓存短 TTL。击穿是热点 key 过期瞬间高并发查 DB,用互斥锁只放一个去 DB 查,或者热点 key 永不过期加异步刷新。雪崩是大量 key 同时过期,TTL 加随机抖动,加多级缓存本地 Caffeine 加 Redis,加限流降级。这三个问题的本质都是缓存失效导致流量打到 DB,区别在于失效的范围和原因,解决方案也是针对性设计。
八、业务知识类(机票/酒店/商旅)
Q1:GDS 和 NDC 有什么区别?商旅该用哪个?
GDS 是传统的全球分销系统,像 Amadeus、Sabre、Travelport,国内是中航信。航司把库存给 GDS,OTA 通过 GDS 拿票,GDS 负责出票和维护 PNR。协议比较老,是 EDIFACT 或者 Web Service,但覆盖全、稳定。
NDC 是 IATA 推的新分销标准,基于 XML/JSON,是航司直连 OTA。航司自己出票、自己维护 PNR,GDS 侧只存一个 passive PNR。NDC 的优势是内容丰富,能拿到品牌运价、辅营产品、个性化报价,劣势是覆盖度还在增长中。
商旅的策略我建议是双轨并行——GDS 保覆盖度,处理长尾航司;NDC 做差异化,跟大航司直连拿更好的价格和辅营产品。然后用适配层屏蔽 GDS 和 NDC 的差异,对上层提供统一的产品模型。这个思路跟我做火车票 GDS 的"统一模型加适配器"是一样的。而且 NDC 不会取代 GDS,GDS 自己也在建 NDC 功能,未来会充当 NDC 聚合器的角色,所以双轨是长期方案。
Q2:机票的售卖流程和订单生命周期是怎样的?
机票的售卖流程从搜索开始,用户搜航班,系统返回航班列表,这时候的价格是缓存的。用户选了航班之后要做一次验价,就是 Repricing,拿到实时的价格和库存。然后提交订单、建 PNR 占位锁舱,再发起支付,支付成功后出票,生成 13 位的电子客票号。
订单生命周期是这样的:创建订单、预订也就是建 PNR、支付出票生成 ETKT、然后是作废 Voiding 这个通常出票当日可以做、退票 Refund、改签 Reissue 或者 Exchange。
这里跟火车票有个区别,机票有 PNR 这个概念,是旅客订座记录,6 位字母数字,是预订的凭证。出票之后才有票号。商旅场景还会涉及企业差标管控,下单前要校验是不是符合差旅政策,这个是在订单创建环节加规则引擎做的。
Q3:国际酒店的 Rate Plan 是什么?多币种怎么处理?
Rate Plan 就是房价计划,一个酒店房型可以挂多个 Rate Plan。不同的 Rate Plan 对应不同的取消政策、含早不含早、会员价、公开价、企业协议价这些。本质上是同一个库存的不同销售条件组合。
酒店跟机票最大的差异是,机票是全球库存池通过 GDS,酒店是单酒店的物理库存,按酒店隔离。所以酒店聚合更像是多供应商加 Channel Manager 实时同步的问题,要对接全球的 PMS 系统,比如 Opera、Fidelio,实时同步房态价格库存。
多币种这块,酒店涉及各国税制,VAT、服务费、地方税叠加计算,不同国家税率不一样。我会用 BigDecimal 做精确计算,税种做成可配置的模板,支持外加和内含两种方式。汇率用锁汇机制,下单时固化。一致性保障用 TCC 或者 Saga 模式,跨酒店集团、跨渠道、跨支付的最终一致性。
Q4:商旅和 C 端 OTA 有什么区别?
商旅也就是 TMC,跟 C 端 OTA 的差异挺大的,主要是几个方面:
第一是企业账户和差旅政策。商旅有差标管控,比如一线城市住宿不超过 800 一晚,超标要二级审批,这是 C 端没有的。
第二是公对公结算。C 端是用户个人支付,商旅有 Central Billing 总部统一支付、Local Billing 本地结算、还有 VCC 虚拟信用卡这些企业结算方式,涉及账期和预存。
第三是多组织架构。企业是集团子公司部门项目组这种嵌套结构,权限和预算管控要按组织架构走。
第四是合规和发票。商旅要处理电子发票归集、增值税专票 OCR 抵扣,还要跟企业的 ERP 系统比如 SAP、Oracle 对接。
第五是行程管理和 Duty of Care。企业要关心员工出差的安全,这是企业的责任。
这些差异决定了商旅系统的复杂度比 C 端高,但底层复用 OTA 的供应链和交易能力。携程商旅那套多币种结算的专利方案——固化汇率加预算池冻结加混付,我研究过,思路很清晰,可以应用到滴滴商旅的企业差标管控。
九、团队管理类
Q1:你怎么 0 到 1 搭建一个 20 人的团队?前 3 个月怎么排兵布阵?
这个我有实际经验,携程国际业务团队就是我从 0 搭到 20 多人的。我的节奏是先骨干后兵,先架构后开发,先规范后放量。
第一个月,核心是招 2 到 3 个资深架构师或者 tech lead,这是骨架。同时定义技术架构和开发规范,理清业务边界。这个时候不急着堆人,先把方向定准。
第二个月,补齐各业务线的负责人,比如商旅就是机票、酒店、用车、支付这几条线。启动核心系统的 0-1 设计,并行招聘中层工程师。
第三个月,团队规模基本到位,建立敏捷流程,我一般用双周迭代,加上强制的 Code Review 和每周的技术分享。然后核心系统的 MVP 开始开发。
这套节奏我在携程验证过,是能跑通的。关键点是前两个月不能急,骨架没搭好就堆人,后面很容易乱。
Q2:团队里有个资深工程师不认同你的架构方案,怎么处理?
这种情况我遇到过。我的处理原则是对事不对人,用数据决策而不是用权威压人。
首先我会让他把具体的反对理由讲清楚,是觉得性能有问题、成本太高、扩展性不够、还是有风险。把分歧点明确下来。
然后我会建一个技术决策树,从业务规模、团队规模、一致性要求、技术栈兼容性、运维成本、扩展性这几个维度去评估两个方案,必要时做 POC 验证。技术分歧能用数据解决就用数据,比如压测一下看谁的性能好。
如果 POC 之后还是僵持,那作为负责人我 会拍板,因为最终对结果负责的是我。但拍板的时候我会把决策理由说清楚,让大家理解为什么这么选。决策之后全员执行,不允许消极抵抗。事后我会做复盘,看这个决策对不对,也复盘分歧机制本身有没有问题。
我觉得技术分歧是好事,说明团队在思考,关键是要有决策机制,不能无限期争论下去。
Q3:你怎么管控技术债?研发效能怎么提升?有量化指标吗?
技术债管控我的做法是,每个迭代预留 20% 的容量专门用来偿债,不全部排业务需求。技术债要可视化,我会在看板上分级,P0 是影响线上的、P1 是影响效率的、P2 是优化项,按优先级消化。另外定期做架构评审,识别那些正在形成的技术债。
研发效能提升,我主要抓三件事:强制的 Code Review,不 review 不合入;CI/CD 自动化,构建测试部署全部自动化;还有每周的技术分享,提升团队整体水平。
量化指标我有几个:交付周期,我在 SGS 的时候用这套机制把交付周期缩短了 20%;线上故障率和 MTTR,衡量稳定性;代码覆盖率,衡量质量;还有新业务接入成本,我在 SGS 引入 DDD 重构之后,新业务接入成本降低了 30%。这些指标都是可以量化的,不是凭感觉。
Q4:你做过 .NET 到 Java 的迁移,如果让你带团队转 Go 呢?
这个方法论我验证过一次,完全可以复用。.NET 到 Java 迁移的时候,我用的是双写灰度、分批迁移、保留回滚这套组合拳,Go 迁移也是一样。
Go 这门语言对 Java 团队来说学习曲线不算陡,语法简单,难点在于并发思维,goroutine 和 channel 那一套,还有 error 处理的方式跟 Java 不一样。
我的迁移策略是,先选一个非核心的新业务用 Go 试水,让团队建立 Go 的开发规范和最佳实践,踩踩坑。核心系统保持 Java 不动,新模块根据收益决定要不要用 Go。关键路径的代码我会亲自 review,保证质量。
我不会搞"为迁移而迁移",新栈只在有明确收益的时候用,比如高并发的网关层、IoT 接入层这种场景 Go 确实有优势。业务逻辑层用 Java 也挺好,没必要折腾。这套务实的方法论是我从 .NET 转 Java 那次实践里总结的。
十、动机与软性题
Q1:为什么从携程离职?
这个问题我想说,离开携程不是携程不好,是我个人想验证一些东西。在携程 12 年我沉淀了 OTA 的全栈能力,但一直在平台里,很多事是平台赋能的,我自己想验证一下脱离平台后 0-1 的全链路能力到底怎么样。所以我去做了技术合伙人,从 0 到 1 搭了 IoT 平台、定制游平台、AI 客服系统。
这两年我验证完了,0-1 的能力是站得住的。现在我想回到大平台,回到国际化的主战场,把这套方法论在更大规模上落地。所以这次看滴滴国际商旅,不是逃离创业,是带着创业验证过的能力回来做更大的事。
Q2:为什么选滴滴国际商旅?为什么不是别的机会?
主要是三个匹配。
第一是业务匹配。国际商旅这个事,要的是 OTA 国际化、跨境支付、GDS 供应链治理,这三样正好是我 12 年携程加 2 年创业的能力交集。市场上能把这三样凑齐的机会不多。
第二是阶段匹配。这个岗位是 0-1 搭建,我擅长 0-1,携程国际火车票、IoT 平台、定制游平台,我做了好几个 0-1。
第三是平台匹配。滴滴国际已经覆盖 14 个国家,有全球化的基础设施底座,商旅是高增长的第二曲线,空间大。而且 JD 里明确说倾向能把携程经验应用到滴滴的候选人,这刚好是我的差异化优势。
至于为什么不是别的机会,说实话我看机会的核心标准就是"国际化加 0-1 加大平台",这三个条件同时满足的不多,滴滴国际商旅是最契合的。
Q3:为什么选上海?
这个岗位在上海,我本身就对上海不排斥。另外从业务角度,上海是国际航司、国际酒店集团在中国的聚集地,做国际商旅业务,跟供应商的对接、跟海外业务方的沟通,上海在地缘上是有优势的。我个人方面,上海离我老家也不远,家人也支持。所以上海这个地点对我来说不是问题。
Q4:你觉得自己最大的不足是什么?
我想了想,最大的不足应该是机票和酒店的垂直业务经验还不够深。我过去 12 年主要深耕的是火车票,虽然依托携程集团生态对机票酒店的链路是了解的,但毕竟没有亲自主导过机票 GDS 或酒店 Rate Plan 系统的建设。
这个不足我已经在主动补,比如研读携程公开的机票查询架构、国际机票数据中台化这些技术文章,也系统学习了 GDS、NDC、PNR、ATPCO 这些业务知识。
另外,我有一个优势可以弥补这个不足——我做国际火车票 GDS 的架构方法论是可迁移的,统一产品模型加适配器这套思路对机票酒店同样适用。协议层的具体对接我可以在 1 到 2 个月内通过团队补齐,但架构设计和落地的方法论我已经验证过一次了。所以这个不足是短期的、可补的,不是结构性的问题。
Q5:你做过最失败的一件事是什么?学到了什么?
我讲一个。在携程做国际火车票 GDS 的时候,早期我对一个欧洲供应商的接口稳定性评估过于乐观,上线的时候没有做充分的降级预案。结果有一次那个供应商接口大面积超时,导致我们的搜索响应时间从 1 秒飙到了 8 秒,用户体验严重下降,那段时间客诉不少。
事后我做了复盘,核心教训是——对第三方供应商永远不能信任过度,必须假设它会挂。后来我们补上了多供应商并发加超时降级的机制,任何一个供应商超时不影响整体响应。这个教训我后来用到了所有依赖外部系统的场景,比如 TripPlan 对接 Stripe 的时候,我就预先设计了查询后置重试的兜底机制。
这件事让我真正理解了什么叫"防御性架构",对外部依赖永远要做最坏打算。这个思维我觉得对滴滴国际商旅特别重要,因为商旅要对接大量海外供应商,稳定性是生命线。
Q6:你的薪资期望是多少?
薪资这块,我希望能跟岗位的级别和市场行情匹配。这个岗位最高到 D9,我相信滴滴对 D9 这个级别是有合理的薪资体系的。我希望能在了解到具体的职级定级、还有股票期权这些整体 package 之后,再具体讨论。
我更看重的是这个机会本身——国际商旅的 0-1 建设、滴滴国际的平台、团队能不能配到位,这些对我来说比单纯的现金薪资更重要。当然,如果一定要我给个范围,我希望整体 package 能在合理范围内有竞争力,具体数字咱们可以聊。我是有诚意的,不会因为薪资谈不拢轻易放弃这个机会。
Q7:未来 5 年的职业规划?
我分两个阶段说。
短期 1 到 2 年,我希望把滴滴国际商旅的核心系统从 0 到 1 搭起来,团队能稳定运转,业务能规模化落地。这是最直接的目标。
中期 3 到 5 年,我希望把国际商旅做成滴滴的第二增长曲线之一,系统能支撑多国家多业务线的规模化,团队从 20 人成长到 50 人以上的多业务线研发组织。我自己也从"业务负责人"成长为"能驾驭复杂业务全局的技术领导者"。
我没有特别短期的跳槽打算,这次回来是想在一个大平台长期做下去的,所以 5 年规划我是认真想过的,希望能跟滴滴国际商旅的成长绑定在一起。
十一、诚实防御类(被追问时用)
Q1:你到底做没做过国际机票系统?
我要诚实地说,我主导的是国际火车票 GDS 系统,国际机票我没有亲自主导过。但我在携程 12 年,依托集团生态,对机票业务的产品形态、供应链、交易链路是熟悉的,也研读过集团公开的机票查询架构、国际机票数据中台化这些技术方案。
我的核心价值不在"做过完全一样的事",而在"架构方法论可迁移"。国际火车票 GDS 和国际机票 GDS 在架构层面是同源的——都需要统一产品模型屏蔽供应商差异、适配器对接、多币种结算、多机房合规部署。这套方法论我已经验证过一次。协议层的具体对接,比如 Amadeus、Sabre 的报文、NDC 标准,我可以在 1 到 2 个月内通过团队补齐。
JD 里也提到"能把携程业务经验和技术方案应用到滴滴",我觉得关键在"应用能力",这个我有信心。
Q2:火车票业务是不是比机票简单?
表面上看火车票是单一线路,但实际做国际火车票 GDS 一点都不简单。难点在于各国铁路系统差异极大——车次编码、席别定义、退改签规则完全不同,要把这些统一起来,抽象的难度不亚于机票。机票虽然协议复杂,但至少 IATA 有统一标准;铁路是各国各搞一套,没有全球统一标准。
另外我做过 12306 的爬虫和多引擎互保出票,这套供应链治理的经验是真实的。火车票的出票要紧跟 12306 的更新节奏,抗反爬、多引擎冗余、调度协调,这些治理思路跟机票出票治理是同构的。
所以我觉得难易不是关键,关键是治理框架和架构方法论能不能复用,这个我有把握。
Q3:你离开携程去创业,现在又回来,是不是不稳定?
我理解这个顾虑。但其实我的轨迹是有逻辑的,不是随机跳。携程 12 年是深耕,离开是为了验证 0-1 的全链路能力,这个已经验证完了。现在回来不是又想跳,是想找一个能长期做下去的大平台,把验证过的能力在更大规模上落地。
我今年 38 岁,已经过了频繁跳的阶段,这次选滴滴是奔着长期去的。商旅的 0-1 到 1-100,至少需要 3 到 5 年,我是希望能跟这个业务一起成长的。稳定性这块,您可以看我携程 12 年的履历,那才是我的基本盘,创业只是中间的验证期。
十二、反问面试官(选 2-3 个)
这几个问题我根据面试官的身份来选。技术面我问架构和供应链,业务面我问战略,HR 面我问团队。
问技术面/架构师
"商旅用车天然适合滴滴的 Set 化单元部署,但机票酒店是全球库存模型。你们在架构上怎么做 LBS 强隔离和全球库存集中的平衡?"
问技术面
"国际机票你们计划走 GDS 加 NDC 双轨,还是先以 GDS 为主?供应商对接和出票成功率治理目前最大的痛点是什么?"
问业务/高管面
"国际商旅目前是什么阶段?是已经有 MVP 在跑,还是完全 0-1 从零搭?未来 12 个月最关键的里程碑是什么?"
问 HR/高管面
"目前后端团队的规模、技术栈分布、最大的能力缺口是什么?我入职后前 3 个月最需要补的是架构、招聘还是治理?"
问高管面
"国际商旅团队和滴滴国际出行业务、国内商旅之间的协作边界怎么划?技术上有共享中台吗?"
附:算法手撕清单(每日 3 题保持手感)
滴滴必考算法,面试前 3 天每天手撕 3 题:
| 题目 | 考点 | 滴滴出现频率 |
|---|---|---|
| 最长不重复子串 | 滑动窗口/双指针 | ★★★★★ |
| 链表反转/区间反转 | 链表操作 | ★★★★☆ |
| 二分查找变种 | 二分 | ★★★★☆ |
| 两数之和 | 哈希表 | ★★★☆☆ |
| 最长递增子序列 | DP | ★★★☆☆ |
| LRU 缓存 | 哈希+双向链表 | ★★★☆☆ |
| 合并有序数组/链表 | 双指针 | ★★★☆☆ |
| 大数据 top K | 堆/分治 | ★★★☆☆(三面) |
算法不是这个岗位的核心考察点,但答不上来会减分。重点是思路清晰、代码能跑通,不追求最优解,先写出正确解再优化。
使用建议
- 优先背项目深挖:国际火车票 GDS 的 5 个追问、订单重构的 4 个追问、TripPlan 的 4 个追问,这是面试主战场。
- 业务知识要能脱稿:GDS/NDC 区别、机票流程、Rate Plan、商旅差异——这四块是证明"懂业务"的关键。
- 诚实防御话术要熟:被追问"做没做过机票"时,诚实但有说服力,不能慌。
- 自我介绍练到 1 分半:定时练习,超时就精简,不够就补充细节。
- 算法每天 30 分钟:保持手感即可,不用刷难题。