一分钟多进程百万数据导出到csv并上传到oss
需求
- 产品要导出某个团队某些用户的步行日志到csv文件里,并且要在一个文件内,而且速度要快不能太耗时间。
问题
- 日志往往意味着数据量大。
- 要导在一个文件内,数据量虽然大也能解决,无非就是分页查询并写入csv。
- 速度快时间短,也能解决无非就是多进程导出多个文件,没有什么难的,但是需求是一个文件!
解决思路
- 先查询出要导出的数据总量
- 投入到批次队列里面启动多个消费者查询并写入到多个csv里面。
- 投递队列时记录每个队列写入的csv具体路径和文件名称。
- 利用批次队列的特性在执行完毕时,把上一步记录的多个csv按照顺序合并到一个csv里面
- 合并完成之后,删除合并前的多个csv,保留合并的csv并上传到oss
结果
经过测试50多万数据,批次队列里面每个队列分配5万条数据去处理,走完一个流程耗时不到一分钟,这种方式有多快取决于服务器能启动多少个消费者多少个进程,我测试时用的是自动策略,最高是同时8个消费者在执行。
其实还有一个优化点。那就是OSS不是支持字符串上传嘛。你直接将本地合并的功能,通过OSS来实现,这样不就把本地文件合并的时间给省下来了么。就是不知道这玩意能省下几秒钟了。 :joy:
或许可以换个思路,用python(其他语言也可以,总之是运行在本地电脑)写个客户端脚本实现这个功能。 通过 laravel 广播, 或者 python 直接连线上 Redis 然后通过发布订阅接收消息(不推荐, 这样服务器安全组需要放行 6379 端口, 有一定安全隐患 )。 当导出事件触发时,laravel队列直接发送消息给 python 客户端, 然后 python 处理完之后 通过 ossutil64 或者 OSS python SDK 上传。 这样的好处就是不受服务器性能限制。 而且可以很方便的在客户端再搞一个多线程。 并且办公室加一台电脑的成本比线上加一台服务器成本低的多。
放代码或者写个文档来大家学习一下嘛
用swow哇
你的需求真这么简单的话,我觉得
MySQL
自己的select into outfile
更简单和直接。虽然没测过,但应该效率不会差。好吧,还有一个方案就是,查询数据的sql 也可以在 go func 中执行。 多启几个 go func ,按 id 制去查。每个 go func 查 5万行或者10万行。一般我们的 id 都是顺序的,这样能查全也不会重。 这样分布式的查写传效率应该还能高一点。
用的哪个消息队列,我看官方的queue里面没有开启多消费者一说...代码在码云或者Github分享一下 :joy: :joy:
只能swoole了,redis队列也不行的,也会慢
楼主有没有尝试 xlswriter 这个扩展, 可以对比一下 用时对比 我也是百万数据导出 直接用游标查询 + xlswriter 百万数据也是30s