对于一些报表性的后台,有些会提供数据导出功能。如果查询维度过多又都是耗时操作,那就像是开了潘多拉盒子,会造成比较恶劣的后果。
数据的导出,下载,是和产品的定位息息相关的。许多产品就非常硬核,非常常用的导出功能都不给你提供,但你还是要屁颠屁颠的用着这些系统。因为人家牛X。
然鹅很多的产品,就比较软骨头。客户和老板需要什么,就提供什么,完全把做产品搞成了做项目。很可怜,也很可恨。
这是需求存在的根本。
目标
下载任务通常会占用大量资源,造成系统负载升高,甚至内存溢出。如不合理控制,经常会造成服务超时或者当机,这是不能容忍的。
我们的目标,就是要让下载服务的资源使用达到均衡的状态,拦截一些重复下载需求,尤其是一些大数据量的下载需求。
以下内容更多是思路性的。为啥说是思路性质呢?因为它并没有实现方法,仅作为架构意义的指导思想。
我们将从下面几方面进行优化。
一、异步
收到下载请求后,应该立即返回,然后将本次请求放入处理队列中。处理完毕后,通过通知的功能对用户进行提醒。这通常意味着行为方式的改变,并会引入一些站内信之类的通知。
对于高耗时的下载请求,异步化同时是对产品体验的优化。使用方无需在浏览器前方呆坐,等待下载,ta只需要发起一个请求就好了。
二、文件
数据导出下载,一般都会合并多页的请求,这个普通的展示是不一样的。生成文件的过程,不要放在内存中。尤其对于并发性有些规模的,或者结果集很大的。
文件不要载入到内存中,而采用追加的方式,直接对文件进行操作。等文件生成后,将文件传送到存储引擎(比如CDN)进行存储,然后返回上传后的存储地址。
此处有几件事要做。
1、对于时间跨度非常大的请求,是否可以进行文件合并?也就是分别下载,将资源打散,然后再有个合并过程。因为很多次下载,都需要重复载入一些数据,为了避免这方面的计算,可以将文件共享。
2、上传到存储引擎的文件,可以根据类别设置专有的域名,进行解耦。这个主要是用来隔离,可视情况而定。
3、要提供一个下载列表的页面,包括要存储的最大时间。用户需要这些数据时,可以直接进入下载列表直接获取。
三、排队
排队主要是资源限制。可以有全局排队和单机排队只说。简单的方案,就是单机排队,负载均衡有外围的nginx进行负责。
收到请求后,请求放入缓冲队列中。这个缓存队列,可以是线程队列,但容易丢;也可以是分布式队列,比如redis或者mq等。处理进程会根据系统负载情况,获取一定的任务进行执行。有了这个队列,我们就能干很多事情。
1、可以对资源利用进行控制,不至于并行处理多个大的请求
2、防重入,一样的参数和范围,不予处理。
3、对系统的下载任务,时长,错误等,进行精细的监控。
4、操作集中,方式统一。
四、预先计算
很多下载操作是可预知的,也就是说可以提前计算。比如按天下载的数据,就可以在晚上定时将文件生成。日终、月终、年终等数据,都可以这种方式进行。
但是要考虑资源占用。如果你的报表数据,访问频率并不是很高,那么这部分的文件生成,就是得不偿失的。
这通常会引发大量的计算。所以,到底什么模块适用于此种策略,是值得认真考虑的。
五、触发式
这种方式就比较投巧,投入也是巨大的。具体思路,就是把系统中产生数据的地方,通过消息,或者开放api等,将数据分享出去。
需要的商家,拿着账号密码令牌等,就可以源源不断的接收这些元数据。
具体你拿去干什么,要怎么玩,我的平台不管。
六、产品优化
产品的设计直接决定了实现的复杂度和稳定性,要在查询条件上达成一致。你会发现,即使是非常常用的系统,在数据导出方面,都是进行功能限制的。
比如,社保系统的打印,有些功能,就需要提前预约,因为的请求,可能会耗费他的不少资源。这就是从技术的局限影响产品的设计。
具体在产品设计上,也要这样考虑:
1、查询纬度不需要事无巨细,如果下载的条件有父子关系,占用的资源相差无几,则只提供父类下载即可。客户下载后,自行excel过滤。
2、时间纬度要固定,跨月,任意填这种,是要绝对禁止的。这也影响我们的很多方案的实施。
3、不该提供下载的,要严守红线,比如用户可以通过简单excel公式进行提炼的,不要提供鸡肋功能。客户并不像你想象的那么傻,而你却把他们当傻逼一样对待。
End
这个思路,完全是为了大型的系统而设计的,你可千万别硬搬到自己的系统。两三个客户,几千条记录,就想着这么玩,那叫过度设计。