图片导入导出优化记录
图片导入
功能描述:本系统需要将A平台的图片转存到B平台中,流程是下载A中的图片,调用B的上传接口上传。
问题点:排查发现每张图片都要耗时150ms,多张图片是并行执行,但是3000张图片要传10多分钟。其实一张图片也就600kb左右。
数据流程:梳理流程发现,
1、定时任务每次处理200个后,不再继续处理。也就是等到下1分钟,才会执行后面的下载任务,这样计算,3000张的上传主要就是受到这个影响。
2、每次子任务上传成功后,更新总任务的成功个数。在并发场景下,数据库单条数据频繁更新,也会导致等待时间长,计数不准的情况。
3、下图更新所有图片为上传中的状态,是串行进行。
优化方案
1、每次传完之后就轮询搜索下200个进行上传。并且把任务改为上传进行中,这样,就算到下一分钟,也不会查到本次任务查到的所有待上传的素材。
2、后续将此计数过程,由缓存记录。等到所有任务处理完毕,再将缓存更新到数据库。
3、图片的上传状态互不影响,可以改为并行处理。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
图片导出
功能描述:勾选多个图片,点击导出,在浏览器上下载图片包zip文件。
问题点:下载3000张图片,需要耗时3分钟。
数据流程:3000张按照500一个批次去处理,但是500个是串行下载,下载一个用zipoutputstream写一次流。使用arthas验证了,一张170ms,两张 282ms,说明是串行执行,如果是3000张,约300s也就是5分钟。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
优化方案:并发下载,每500个的缓存下载的数据,一起交给zipoutputstream输出。
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
for (Map.Entry<String, byte[]> picMap : rstMap.entrySet()) {
String name = picMap.getKey();
zos.putNextEntry(new ZipEntry(name));
int data = 0;
ByteArrayInputStream bais = new ByteArrayInputStream(picMap.getValue());
byte[] buffer = new byte[2 * BisConstants.MULTIPLE_10 * BisConstants.MB_SIZE];
while ((data = bais.read(buffer, 0, BisConstants.MULTIPLE_10 * BisConstants.MB_SIZE)) != -1) {
zos.write(buffer, 0, data);
}
}
// 导出到浏览器
zos.flush();
zos.closeEntry();
picMap是下载好的数据<String, byte[]>
优化效果:1000张耗时20s内。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
方法执行的工具:
https://arthas.aliyun.com/doc/