最近负责的项目是 一个题库系统,客户通过excel来批量录入试题,且题里面会有图片和视频。所以采用的方案是
① excel中使用某种规则表达式来表示图片
② 客户手动上传图片(得到图片路径)
③ code中使用正则替换excel里面的图片表达式为正常的图片路径
这篇文章说的主要是和②有关的一些问题
和产品要了几次原型图,都没有给,最后口述了一下:“就是在原页面上,出现一个上传图片的按钮,然后出现 一行预览的就可以,你看着做就行”。这让我想起了之前去药店买药,药店摆开了3盒药,问我想吃哪盒。
另一个产品则不耐烦的告诉我们做成和老系统一样就可以(老系统的交互只能录单题,是上传到富文本编辑器里面,且一次性只能上传1张)
做的过程中,对一次性最多上传多少张,产品也含糊其辞,我自定义了最多50张。产品也附和着说应该够用。
后来又一直催着上线,所以就做了解决方案1.0 上线(多图片单接口)
① 客户实际用的时候,最猛一次性录了近5k道题目,后来后台接口限制了一次性最多1k道题。
② 一次性1k道题的情况下,客户又说想一次性上传几百张图片,分批次上传太麻烦了。产品让把50张图片的限制放开了。
放开限制以后,客户一次性上传了250张。因为是多图片单接口的,且接口有timeout (1分钟)。所以超时了。且客户公司网速也很不稳定,(上传同样一张200kb的图片有时候是几ms,有时候是几s,有时候甚至更长)
产品一字不落的转述了客户的需求 :”我们人手不足,题很多,别说200张,一次性300张也是家常便饭,不要耽误我们录题的进度”。产品表示问题必须尽快解决
多图片单接口。说白了,就是所有图片都通过一个接口上传。1张图片是一个接口,300张图片也是一个接口
多图片单接口因为网速和图片数量的问题,接口超时就比较常见了。且功能比较简陋,没有做历史上传判断,所以一批图片,成功了就都成功了,失败一个,就判断都不成功。
排在前面有几条路:
① 让客户多传几次(他们那边其实人不少,有10几个人在负责,从最后数据来看,带图片试题只有1500道左右,按照我们一开始的限定一次性50张,只需要每个人上传几次就可以,这是后话了。 当时的情况是客户一口咬定她们图片很多很多,多到她们自己都不知道多少张)。
② 走单图片单接口的方案(自己感觉比较low,哈哈)
③ 做成网盘异步那种(和产品沟通以后,产品表示“这样改太麻烦了,人家着急用呢”)
④ 让后台接口放开超时时间(后台表示timeout可以放开,但是不能无限放开,这次他们要300,下次他们要1000怎么办,再下次要2000怎么办)
我在一个微信大佬群里面,发出了我的疑惑。一会儿一个大佬回复我的疑惑
我问几个后台同事 “如果一次性上传1000张图片,单图单接口和多图单接口,你们选哪个”
java同事A,说:“( ̄ェ ̄;) 你要往服务器上传片儿吗?”。哦,天呐,看看我的沙雕同事,“现在不都是在线看吗。。。“
java同事B,说:“他会选单图单接口,因为会有粒度控制(即进度条)”
java同事C,说:“他也会选择单图单接口。后台接口或nginx的timeout虽然可以放开。但是不能无限放开。而且单图单接口也可以优化多单图单接口和多图单接口相混合的”
android 小姐姐说,她们android平时批量上传一般也单图单接口,因为多了会超时。(-ω-) 你别说 android 小姐姐的眼影画的好漂亮,唇色也好看,还会闪闪发光呢。
结合以上接口选择了单图单接口的方案。初步测试结果如下。
162 张,大概16s, 平均1s = 10张
明明这160个接口是一起发出的,理论完成时间不应该是约等于单张图片上传时间吗?为什么差这么多。
用了node写了一个接口,有5s等待,让前端同时调用2次
然后诡异的事情发生了:
按道理来说,2个接口同时发送。应该所用时间是5s才对啊。为什么会发生了等待呢。 但是使用postman 同时send 2次该接口。总耗时又是5s左右。
之前没听过说接口会发生阻塞啊。那么使用多接口同时请求呢?
可以看到多接口多并发是正常的,没有发生阻塞
① 如果单接口多并发会发生阻塞,那么一定时间后。会不会超时呢?我们可以把单接口的等待提高到40s。按照3.4.1的逻辑老说。单接口单次是40s,单接口多并发2次应该是80s
② 不应该啊,等待不应该是40s。为什么是20s。肯定哪里不对
③ 多来几个并发呢 (单接口4并发)
可以看到后3个接口的等待时间都是20s。也没有发生超时。可以看到1个等待40s的单接口,同时请求4次,时间总耗时1min
④ 循环20次总可能会超时吧
可以看到1个等待40s的单接口,同时请求20次,时间总耗时3min左右
总感觉哪里不对。是不是node也有什么不正经的地方呢。要不用正经的java接口试试看?
让java同事帮忙启了一个java本地接口,同样等待40s。同样单接口循环20次
可以看到1个等待40s的单接口,同时请求20次,时间总耗时2.7min左右
后来想起来,浏览器貌似有接口并发限制
引用来源
HTTP客户端一般对同一个服务器的并发连接个数都是有限制的。
实际上,浏览器确实使用并行连接,但它们将并行连接的总数限制为少量(通常为四个)。服务器可以自由地关闭来自特定客户端的过多连接。
看看java的接口是不是6个一组呢
可以看到是java接口是非常规范的6个一组
为什么同样的浏览器,同样的前端页面。同样的单接口并发。同样的20次循环。node接口不是6个一组呢。 node是不是不正经呢。而且我每次请求都是重启浏览器(360做测试浏览器,每次重启会清空所有缓存)
后来发现有类似的问题
nodejs的express并发问题?一次只能处理一个请求?
看到了这句,在自动清除缓存的前提下,又勾选了Disable cache
再次请求发现请求node接口也是6个一组了
在查询http并发限制的过程中,发现http2 几乎没有并发限制(有的浏览器限制在100个)。所以线上换成了h2协议。(鉴于这篇已经很长了。所以关于http1.1, h2和server worker 这部分会另起一篇)
测试结果如下:
1个25kb,300个大约 7500 kb = 7.32M; 需要大概10s
和3.1 相比速度提升了不少。
由于项目默认开启了service woker。所以同等条件下。需要大概8s
由于前端几乎没有了上传个数限制。所以和后台确认了一下风险。后台表示会加上上传限制。同时我这边也加了500张的限制。
解决方案2.0 说白了就是单图片单接口循环 + 进度条控制 + http2 协议
如果再采用单图单接口+多图单接口的模式。所需时间可能更短。但是后来客户又提出了做个媒体库的畅想。。。。
这种模式的初步简单假设交互是,客户上传图片和百度网盘一样,每张图片有个进度条。可以断点续传(因为除了图片,试题中可能还有视频)。同时做成异步提醒。即客户可以去做其他事情,图片完全上传完成以后会通过message提醒客户。
随着整套系统经历了近10w同时使用的大考,这部分需求似乎没有进一步优化的动力。也许,同事说的都的对:“他们都没主动说,你着急推什么。新版本需求做完了? 别的项目没事了? 耽误了项目新进度小心扣你绩效“”
比如现在一次性上传百张图片有4种方案,(多图片单接口模式,单图片单接口模式,单图片多接口混合模式, 网盘异步模式)。如果一开始选择了第三种方案,则会省事很多,但是这种马后炮的话,说出来没有意义。如何尽量保持程序扩展性,可以从下面2点探讨
为什么说尽量,因为每个人工作的情况是不一样,比如我们这边有的同事有时候手里有好几个项目在一块开发,有的项目催的很紧(比如下午16点确认的复杂需求,到晚上19点的时候就需要上线到生产环境)。有的同事则一年只负责一个项目。所以说尽量多思考需求还要看有没有那份“闲情雅致”和“时间"
为什么说还是尽量,因为有一些需求的最终来源者可能都不知道需求真正是什么,而“引导”客户的真实需求并跃然纸上的工作非开发者的本职工作 。