您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
一次结算单文件上传FTP失败的问题排查心得
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
一次结算单文件上传FTP失败的问题排查心得
自猿其说Tech
2022-04-19
IP归属:未知
20297浏览
### 1 背景 目前,京东物流负责承运东方购物商家(电视购物)的部分商品,运费是月结模式。商家要求京东物流每日根据其指定的文件格式生成结算单对账文件(个性化定制),用于次月的月结运费对账。 目前的方案:财务系统每天凌晨记录T-1日的运费信息、并发送binlake格式的JMQ消息,KA系统消费JMQ消息后,通过消息中的计费文件URL下载并解析文件(EXCEL格式),接着按照商家要求的格式进行EXCEL到文本文件的转换,最后上传到商家的FTP上。 线上运营时发现,在双方系统没有进行改造的情况下,京东侧时不时(每周1-2次)会上传一个空文件,可以通过财务系统更新数据时间戳,重新触发JMQ发送解决。通过对该问题的研究,对FTP协议有了更深的了解。 ### 2 问题分析过程 由于整个业务流程是: 1. 财务系统落库 2. 财务系统发送binlake格式JMQ(其中文件信息上传云存储OSS,JMQ中只传输文件URL) 3. KA系统消费并解析JMQ 4. KA系统通过JMQ中的URL,从OSS中获取账单EXCEL文件 5. KA系统解析EXCEL并转换成商家定义的文本文件 6. KA系统使用FTP协议上传到商家文件服务器 PS: 1. 为了避免MQ报文过大(JMQ2 限制2M),京东财务系统从数据库抓取数据生成EXCEL文件后上传到京东云存储OSS,获取URL地址,MQ中只传输文件URL,KA接单系统通过URL下载相关文件。 2. FTP定义了文件传输规则,一般由外部商家提供存储空间,OSS定义了文件存取规则,有京东云提供存储空间,一般用于京东内部的系统交互。  如果是1出现问题,那么就不会触发JMQ,也不会上传一个文件(哪怕是空的),所以1排除。 同理2发送JMQ不会有问题,如果内容有问题则不能通过重试(更新数据时间戳)解决,因此2也没问题。 同理,3-5有问题都不能通过重试解决,因此问题就出在了6上面(此结论也可以通过复现问题后,增加上传内容的日志打印来佐证)。 通过代码可以看到,上传过程就是通过apache的FtpClient的storeFile方法。    网上搜索发现:对于使用org.apache.commons.net.ftp.FTPClient(commons-net工具包)上传文件为空,讨论较多的是FTP客户端连接服务端时使用的是主动模式(ACTIVE MODE),而不是被动模式(PASSIVE MODE),主动模式下,数据通信端口由客户端通知服务端(通过命令端口:21,指令:PORT),服务端按照该端口向客户端发起连接,由于客户端使用的端口很可能不在服务端的防火墙允许的列表中,导致服务端无法向客户端发起连接,因此大部分实践使用的是被动模式,即客户端只是向服务端发起通信请求(指令:PASV),服务端分配数据通信端口给客户端,客户端使用被分配的端口建立数据连接、传输数据。检查代码发现当前已经是设置成了被动模式(上图中的enterLocalPassiveMode方法),因此不是该问题。 根据官方文档,可以看到storeFile方法具有一个布尔类型的返回值:  通过源码分析,可以看到这个布尔值其实就是判断每一次FTP操作的返回码是否在[200,300)这个范围内。    因此,经与商家研发、业务沟通得到允许后,在商家FTP上进行线上测试,测试结果如下:  可以观察到如果上传接口返回false,则FTP服务端给的响应码一定是425(Can't open data connection——打开数据连接失败)。  同时也可以看到,每次使用的成功的通信端口并不是一个闭区间,因此不是服务端配置的端口范围错误。  由于商家无法提供FTP服务端的相关信息,查看linux系统使用较广泛的vsftp的源码可以看到,425错误是无法按照服务端选择的被动模式下的端口进行通信,目前较为公认的原因是FTP服务器的防火墙或者网络层屏蔽该端口导致的。   ### 3 解决方案 根据上面的验证结果,可以在通信端口被屏蔽后进行重试。 原来代码不判断上传后的返回值是成功还是失败,优化方案增加返回值并对其进行判断。 改造前的无返回值的“void uploadFile"方法只适用于商家对FTP目录进行主动检测,发现未上传文件后发送通知给京东系统、京东系统再重传的场景;由于当前业务场景下,商家并没有系统层面的异常检测机制,因此需要京东在每次上传后判断FTP操作返回码,进而决定是否要重传。  根据上传结果判断是否需要重试,最多重试maxRetryTimes次。  ### 4 结论 1. 使用FtpClient的相关接口需要针对服务端返回值进行必要的判断,并增加相关的异常处理逻辑,接口不总是返回成功。 2. 对于线上不必现的,“时不时”会出现的问题,一定要引起重视,要“刨根问题”,不能“得过且过”——通过网上查找解决方案、线上或线下实验验证、源码分析等多种手段排查出根本原因,从根源上解决问题,避免需求上线后需要大量的时间进行运维,浪费研发资源。 3. 在研发方案设计阶段,不能只按照PRD描述实现正常业务流,就认为“万事大吉”,还需要针对各种可能出现的异常情况进行梳理、与同事和产品认真讨论,制定高可用的解决方案。 ------------ ###### 自猿其说Tech-京东物流技术发与数据智能部 ###### 作者:齐海智
原创文章,需联系作者,授权转载
上一篇:源码学习之Spring容器创建原理
下一篇:Jmeter压测实战:Jmeter二次开发之JSF采样器实现
自猿其说Tech
文章数
426
阅读量
2215298
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2215298
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号