您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
一次结算单文件上传FTP失败的问题排查心得
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
一次结算单文件上传FTP失败的问题排查心得
自猿其说Tech
2022-04-19
IP归属:未知
791600浏览
### 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定义了文件存取规则,有京东云提供存储空间,一般用于京东内部的系统交互。 ![](//img1.jcloudcs.com/developer.jdcloud.com/7b74ebea-d6bf-47e2-a0b2-89232bca7ca620220419150048.png) 如果是1出现问题,那么就不会触发JMQ,也不会上传一个文件(哪怕是空的),所以1排除。 同理2发送JMQ不会有问题,如果内容有问题则不能通过重试(更新数据时间戳)解决,因此2也没问题。 同理,3-5有问题都不能通过重试解决,因此问题就出在了6上面(此结论也可以通过复现问题后,增加上传内容的日志打印来佐证)。 通过代码可以看到,上传过程就是通过apache的FtpClient的storeFile方法。 ![](//img1.jcloudcs.com/developer.jdcloud.com/a54b39fd-a982-4014-b71a-becd56d2104d20220419150109.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/5b670e1f-4142-4742-b908-a1209957f67f20220419150118.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/c7c7483b-3c20-4701-bf0d-f7e864b6096120220419150124.png) 网上搜索发现:对于使用org.apache.commons.net.ftp.FTPClient(commons-net工具包)上传文件为空,讨论较多的是FTP客户端连接服务端时使用的是主动模式(ACTIVE MODE),而不是被动模式(PASSIVE MODE),主动模式下,数据通信端口由客户端通知服务端(通过命令端口:21,指令:PORT),服务端按照该端口向客户端发起连接,由于客户端使用的端口很可能不在服务端的防火墙允许的列表中,导致服务端无法向客户端发起连接,因此大部分实践使用的是被动模式,即客户端只是向服务端发起通信请求(指令:PASV),服务端分配数据通信端口给客户端,客户端使用被分配的端口建立数据连接、传输数据。检查代码发现当前已经是设置成了被动模式(上图中的enterLocalPassiveMode方法),因此不是该问题。 根据官方文档,可以看到storeFile方法具有一个布尔类型的返回值: ![](//img1.jcloudcs.com/developer.jdcloud.com/56001eb9-5878-4eb7-896d-d178ca15359220220419150148.png) 通过源码分析,可以看到这个布尔值其实就是判断每一次FTP操作的返回码是否在[200,300)这个范围内。 ![](//img1.jcloudcs.com/developer.jdcloud.com/2986e638-b043-4258-9c02-4b347c8a863220220419153855.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/392ba634-d486-432c-bd2d-2aa027c8be1b20220419153953.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/40e00793-7161-42f2-8fc4-e3a6a69aef9a20220419153959.png) 因此,经与商家研发、业务沟通得到允许后,在商家FTP上进行线上测试,测试结果如下: ![](//img1.jcloudcs.com/developer.jdcloud.com/1a3029f4-ed84-40b2-b671-d5710e4d8fde20220419154013.png) 可以观察到如果上传接口返回false,则FTP服务端给的响应码一定是425(Can't open data connection——打开数据连接失败)。 ![](//img1.jcloudcs.com/developer.jdcloud.com/69f1ef4a-74b3-4681-a4bd-bfa21dddbf3820220419154256.png) 同时也可以看到,每次使用的成功的通信端口并不是一个闭区间,因此不是服务端配置的端口范围错误。 ![](//img1.jcloudcs.com/developer.jdcloud.com/006a2fc9-d082-468f-994a-cb77362adfb620220419154310.png) 由于商家无法提供FTP服务端的相关信息,查看linux系统使用较广泛的vsftp的源码可以看到,425错误是无法按照服务端选择的被动模式下的端口进行通信,目前较为公认的原因是FTP服务器的防火墙或者网络层屏蔽该端口导致的。 ![](//img1.jcloudcs.com/developer.jdcloud.com/d1a49129-d446-403b-a72a-9e1277c10b0f20220419154324.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/f419c2eb-760a-47ee-8b01-28f7f6b2438820220419154331.png) ### 3 解决方案 根据上面的验证结果,可以在通信端口被屏蔽后进行重试。 原来代码不判断上传后的返回值是成功还是失败,优化方案增加返回值并对其进行判断。 改造前的无返回值的“void uploadFile"方法只适用于商家对FTP目录进行主动检测,发现未上传文件后发送通知给京东系统、京东系统再重传的场景;由于当前业务场景下,商家并没有系统层面的异常检测机制,因此需要京东在每次上传后判断FTP操作返回码,进而决定是否要重传。 ![](//img1.jcloudcs.com/developer.jdcloud.com/5be16b98-f82f-4464-979c-b9e347cd2c8c20220419154405.png) 根据上传结果判断是否需要重试,最多重试maxRetryTimes次。 ![](//img1.jcloudcs.com/developer.jdcloud.com/b00a1959-c16f-418b-9553-48ddc88c9bed20220419154417.png) ### 4 结论 1. 使用FtpClient的相关接口需要针对服务端返回值进行必要的判断,并增加相关的异常处理逻辑,接口不总是返回成功。 2. 对于线上不必现的,“时不时”会出现的问题,一定要引起重视,要“刨根问题”,不能“得过且过”——通过网上查找解决方案、线上或线下实验验证、源码分析等多种手段排查出根本原因,从根源上解决问题,避免需求上线后需要大量的时间进行运维,浪费研发资源。 3. 在研发方案设计阶段,不能只按照PRD描述实现正常业务流,就认为“万事大吉”,还需要针对各种可能出现的异常情况进行梳理、与同事和产品认真讨论,制定高可用的解决方案。 ------------ ###### 自猿其说Tech-京东物流技术发与数据智能部 ###### 作者:齐海智
原创文章,需联系作者,授权转载
上一篇:源码学习之Spring容器创建原理
下一篇:Jmeter压测实战:Jmeter二次开发之JSF采样器实现
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
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
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号