如何优雅的设计数据导出功能?

6,275 阅读6分钟

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

对于一些报表性的后台,有些会提供数据导出功能。如果查询维度过多又都是耗时操作,那就像是开了潘多拉盒子,会造成比较恶劣的后果。

数据的导出,下载,是和产品的定位息息相关的。许多产品就非常硬核,非常常用的导出功能都不给你提供,但你还是要屁颠屁颠的用着这些系统。因为人家牛X。

然鹅很多的产品,就比较软骨头。客户和老板需要什么,就提供什么,完全把做产品搞成了做项目。很可怜,也很可恨。

这是需求存在的根本。

目标

下载任务通常会占用大量资源,造成系统负载升高,甚至内存溢出。如不合理控制,经常会造成服务超时或者当机,这是不能容忍的。

我们的目标,就是要让下载服务的资源使用达到均衡的状态,拦截一些重复下载需求,尤其是一些大数据量的下载需求。

以下内容更多是思路性的。为啥说是思路性质呢?因为它并没有实现方法,仅作为架构意义的指导思想。

我们将从下面几方面进行优化。

一、异步

收到下载请求后,应该立即返回,然后将本次请求放入处理队列中。处理完毕后,通过通知的功能对用户进行提醒。这通常意味着行为方式的改变,并会引入一些站内信之类的通知。

对于高耗时的下载请求,异步化同时是对产品体验的优化。使用方无需在浏览器前方呆坐,等待下载,ta只需要发起一个请求就好了。

二、文件

数据导出下载,一般都会合并多页的请求,这个普通的展示是不一样的。**生成文件的过程,不要放在内存中。**尤其对于并发性有些规模的,或者结果集很大的。

文件不要载入到内存中,而采用追加的方式,直接对文件进行操作。等文件生成后,将文件传送到存储引擎(比如CDN)进行存储,然后返回上传后的存储地址。

此处有几件事要做。

1、对于时间跨度非常大的请求,是否可以进行文件合并?也就是分别下载,将资源打散,然后再有个合并过程。因为很多次下载,都需要重复载入一些数据,为了避免这方面的计算,可以将文件共享。

2、上传到存储引擎的文件,可以根据类别设置专有的域名,进行解耦。这个主要是用来隔离,可视情况而定。

3、要提供一个下载列表的页面,包括要存储的最大时间。用户需要这些数据时,可以直接进入下载列表直接获取。

三、排队

**排队主要是资源限制。可以有全局排队和单机排队只说。**简单的方案,就是单机排队,负载均衡有外围的nginx进行负责。

收到请求后,请求放入缓冲队列中。这个缓存队列,可以是线程队列,但容易丢;也可以是分布式队列,比如redis或者mq等。处理进程会根据系统负载情况,获取一定的任务进行执行。有了这个队列,我们就能干很多事情。

1、可以对资源利用进行控制,不至于并行处理多个大的请求

2、防重入,一样的参数和范围,不予处理。

3、对系统的下载任务,时长,错误等,进行精细的监控。

4、操作集中,方式统一。

四、预先计算

很多下载操作是可预知的,也就是说可以提前计算。比如按天下载的数据,就可以在晚上定时将文件生成。日终、月终、年终等数据,都可以这种方式进行。

但是要考虑资源占用。如果你的报表数据,访问频率并不是很高,那么这部分的文件生成,就是得不偿失的。

**这通常会引发大量的计算。**所以,到底什么模块适用于此种策略,是值得认真考虑的。

五、触发式

这种方式就比较投巧,投入也是巨大的。具体思路,就是把系统中产生数据的地方,通过消息,或者开放api等,将数据分享出去。

需要的商家,拿着账号密码令牌等,就可以源源不断的接收这些元数据。

具体你拿去干什么,要怎么玩,我的平台不管。

六、产品优化

产品的设计直接决定了实现的复杂度和稳定性,要在查询条件上达成一致。你会发现,即使是非常常用的系统,在数据导出方面,都是进行功能限制的。

比如,社保系统的打印,有些功能,就需要提前预约,因为的请求,可能会耗费他的不少资源。这就是从技术的局限影响产品的设计。

具体在产品设计上,也要这样考虑:

1、查询纬度不需要事无巨细,如果下载的条件有父子关系,占用的资源相差无几,则只提供父类下载即可。客户下载后,自行excel过滤。

2、时间纬度要固定,跨月,任意填这种,是要绝对禁止的。这也影响我们的很多方案的实施。

3、不该提供下载的,要严守红线,比如用户可以通过简单excel公式进行提炼的,不要提供鸡肋功能。客户并不像你想象的那么傻,而你却把他们当傻*一样对待。

End

这个思路,完全是为了大型的系统而设计的,你可千万别硬搬到自己的系统。两三个客户,几千条记录,就想着这么玩,那叫过度设计。

作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,​进一步交流。​