盒子
盒子
文章目录
  1. 使用技术栈
  2. 功能
  3. 过程以及遇到一些有趣的问题
  4. 数据库数据表怎么拿?
  5. 权限控制怎么做?
  6. 切库怎么切?
  7. 离线任务是啥?需要哪些东西?
  8. 大数据下载需要注意哪些问题?为什么内存会爆了?
  9. 为什么Laravel的Excel服务搞不定大数据?解决办法是什么?
  10. 浏览器下载文件是怎么做的?最佳实践是什么?
  11. 结合讨论
  12. 最佳实践
  13. 后记

【重构Hue】大数据处理的一些总结

最近做了一个项目,是重构大数据开源查询工具Hue。在这里记下一些重构过程中遇到的问题以及解决思路。

首先,感谢Hue为我们带来如此便利好用的工具。重构的目的只是为了在原来的基础上添加一些额外的功能,比如基于数据库的权限控制、离线导出任务等等。

使用技术栈

依旧是熟悉的Laravel+Vue,框架细节不多说,结合业务来看。

功能

原来Hue有的基本查询、历史查询等等都有,加上我们新增的权限控制、数据导出、离线任务。

过程以及遇到一些有趣的问题

数据库数据表怎么拿?
权限控制怎么做?
切库怎么切?
离线任务是啥?需要哪些东西?
大数据下载需要注意哪些问题?为什么内存会爆了?
为什么Laravel的Excel服务搞不定大数据?解决办法是什么?
浏览器下载文件是怎么做的?最佳实践是什么?
….

数据库数据表怎么拿?

这问题为什么要拿出来讨论,咋一看似乎没有那么难,很容易找出答案,但是,真的没那么简单。玩MySQL玩多了,知道MySQL有个叫infomation_schema的东西,它是一个信息数据库,默认生成,是一个view。通过这个数据库,可以很容易得到所有数据库以及数据库下的数据表,还有表里的信息。然而,在impala里,是没有这么方便的东西的,要想拿到所有数据库,那就show databases,要想拿到表,那就show tables in database,要想拿到所有数据库以及库里的表,那得写个foreach,在内网环境下,我算了下平均时间,我本地获取到并显示到浏览器中约用时6秒,时间随库表的增加而上升。目前没有找到好的解决办法,只能在拿到后做个定时缓存,避免长时间等待。如果有好的办法,请不吝赐教:)

权限控制怎么做?

对数据库做权限控制,也就是说,用户查不到自己没有权限的库。怎么知道用户想查哪个库呢?这里推荐一下PHPSQLParser,在github搜一下就找到了,解析SQL非常强大,数据结构也很清晰。这样一来,我们就可以在用户输入的地方(查询、下载、离线任务)控制权限。

切库怎么切?

这个问题很有趣,刚开始是这么做的,用户点了界面上的数据库,我们就做use database,然后,用户输入SQL点执行,我们就execute。其实这样做是不对的:)
原因在于,每次HTTP请求都是无状态的,而且又不知道FPM分配到了哪个worker进程上,每次执行完PHP脚本即刻释放,进程又进入下一次等待,两次请求相互独立。

解决办法有至少两种,我就说我知道的两种吧:
1、使用缓存,把用户点击的数据库缓存起来,当用户执行SQL时,自动use。
2、把SQL和数据库一起发到服务端。

离线任务是啥?需要哪些东西?

这里的离线任务是指把耗时的下载任务后台执行,下载完后提供给用户下载。

既然是下载任务,那就做一个队列,先进先出,暂时不做优先队列。
后台执行,那就是常驻内存,守护进程,supervisor监控。
守护进程可能需要做一个资源连接池,避免数据库连接超时断开。
下载需要的工具后面会说到。

大数据下载需要注意哪些问题?为什么内存会爆了?

如果有个SQL是查询一万条数据,或许不大,那如果是十万条,一百万条呢?千万级别,亿级别?这么大的数据,一次性加到内存中,肯定会内存溢出,有人说了,把PHP默认限制内存写成无限制,内存买大点,应该可以吧….额,当然啦,有钱说了算,但是不够现实….

那有什么好办法没有,有的,那就是分次读取,分片写入(我自创的说法,看看就好)
分次读取:设置一个分页值,比如,100页数据分10页,每页就是10条数据。在这里,我设置为10000,那么无论查询的数据有多大,我每次只会把1万条加到内存中,也就是分次读取。
分片写入:写文件也是同理,这里我分1000行为一次,逐次追加到文件尾,数据一片一片的,一片1000行,也就是分片写入。

为什么Laravel的Excel服务搞不定大数据?解决办法是什么?

因为导出的数据需要转成csv/xls格式,因此我找到了laravel excel,API非常方便,文档也友好,可是,在这里却用不上。因为在较大数据下,这个工具会爆内存,内部实现的问题吧,只好用原生的写法。再者,xls格式有限制,不管是65535还是多少,也不符合需求。那么就是fputcsv了,实现起来也简单。

浏览器下载文件是怎么做的?最佳实践是什么?

以前都是用工具,用插件,没有思考过这个东西,原来也挺有趣的:)

一开始我们是这么做的,客户端是AJAX,服务端返回一堆二进制,客户端做转换,用了一个插件,实现起来非常恶心。而且,xls格式还乱码,各种格式编码试过了无效,果断弃了。
看了一篇讨论,和我们遇到的问题一样,

结合讨论

2.保存在服务器,然后前端请求下载
未尝试,应该可行。
I was able to solve the problem. I’m using ‘store’ method to save the file on the server, and then I send the response (the path to the file):

export.done(function (data) {
window.location.href = data;
});

And the file can be donwloaded.

3.直接在新窗口打开,可以成功下载 尝试可行,需重新拼接url
window.location.href= queryString;

最佳实践

  1. 保存文件到服务端,返回文件路径
  2. 客户端拿到文件路径,请求API下载

后记

这个系统大致功能已经推出,还有一些优化点需要研究一下

  1. 数据库表获取问题
  2. 大数据查询有没有更好的实现方式
  3. 如果不是队列下载,而是并行下载,会不会更快一点
  4. 如果下载文件发生在hadoop的节点机,然后下载完后去把文件copy过来,会不会更好一点
    …..
请我喝一杯咖啡
扫一扫,支持funsoul
  • 微信扫一扫