首先说一下是 Python 技术栈,现在需求是有大量的文件不断生成在一个目录下(文件几 k 到几百 k 不等,同期数量约 20W ),想做一个服务,使得其它服务来请求的时候能快速地取走该文件,并在取走后删除。
当然,最简单的做法就是 Tornado/Flask 直接写个接口,然后 os.remove
就行,想问下大伙儿还有什么高效率的方法来实现吗?
1
gwy15 2020-06-29 20:27:02 +08:00
zero-copy (sendfile)?
|
2
ipwx 2020-06-29 20:31:48 +08:00
redis
|
3
optional 2020-06-29 20:49:25 +08:00
这样性能并不高啊,包括生成大量文件与删除。
删除是强需求吗,是一定只能取一次,还是过一段时间取不到就好? |
4
chenqh 2020-06-29 20:55:04 +08:00
流程没懂
|
5
Te11UA OP |
9
jugelizi 2020-06-29 22:01:07 +08:00 via iPhone
效率?嫌删除动作慢?改成异步任务呗
|
10
vevlins 2020-06-29 22:07:35 +08:00
不删除直接覆盖写?瞎说一下
|
11
netnr 2020-06-29 22:15:11 +08:00
重命名文件夹,mv folder folder.del
再删除 *.del 文件夹 |
12
makdon 2020-06-29 22:56:02 +08:00
要不换成 SSD ?如果是自己的物理服务器,可以搞 nvme 的,或者组个 raid,应该会更快
等等首先现在你的瓶颈在哪里...是定位到了线程池里面大部分线程都在等 os.remove 吗(个人感觉应该是读文件的成本远远高于删文件吧) 如果不是的话...不要提前优化 我想到的这些: 1. 如果业务上面可以实现的话,在请求到的时候再生成文件,不落硬盘直接发送 2. 按照文件名之类的唯一键,hash 到多台服务器上面处理 3. 只能单机的话,可以调研一下有没有适合这个场景的文件系统... |
13
billlee 2020-06-30 00:52:59 +08:00
别想太多,才 20 万文件而已,只要你不去遍历目录,现代文件系统处理起来不会有问题
|
14
realpg 2020-06-30 01:10:47 +08:00
想要高性能,直接写个简单的文件系统。
计算机科班专业的大佬应该都会,如果上学时候做过相关的作业,估计两三天就能解决这个问题。 发生一次读取内容之后直接标记这个文件的区域释放。 |
15
realpg 2020-06-30 01:16:20 +08:00
而且 20 万这个级别,一个文件不超过 1MB,这种存储的 IOPS 只要高一点,连瓶颈都不会发生啊……
文件系统只要是个稍微现代点的文件系统即可。 不知道你那边用的啥服务器,基础架构层优化一下就完事了。 如果基础架构层没法优化,还想绕开删除慢这个坑,那就用完的改名,加前缀,然后当系统 io 不密集时进行限定写负载的删除 |
16
Vegetable 2020-06-30 01:34:39 +08:00
文件需要鉴权?一定要 python 来处理文件?有点蛇。其实直接 remove 并没有什么性能问题,同步 web 框架控制好流程就行,性能瓶颈不在删除这里。异步的话可以用 redis 之类的把取走的文件标记一下,定时删除就好了。
|
17
0ZXYDDu796nVCFxq 2020-06-30 01:38:07 +08:00 via Android
nginx 提供静态访问,瓶颈就是网络带宽
访问记录输出日志,Python 定时读取日志批量删除 |
18
SlipStupig 2020-06-30 02:05:34 +08:00
Redis 直接使用队列就好了啊。。
|
19
hurrytospring 2020-06-30 02:24:52 +08:00
不要求立即删的话搞个表标记一下删除就行了。。真正删除的时候再搞个定时任务拉表批量删掉完事
|
21
jedihy 2020-06-30 04:07:22 +08:00 via iPhone
19 楼的方案应该是最简单高效的了。
|
22
em70 2020-06-30 05:24:57 +08:00
瓶颈到底在哪里? 最简单方法先实现跑起来再谈优化啊
|
23
GTim 2020-06-30 08:18:49 +08:00
一种不知道可不可行的方案是使用 nginx-lua 中的 `log_by_lua` 在这个脚本文件里删除,我没试验过,不知道可不可行
|
24
dbolo123 2020-06-30 08:27:07 +08:00 via Android
直接 nginx 返回,每天跑个脚本分析是 access log,删掉文件就好?
|
25
yaleyu 2020-06-30 09:00:27 +08:00
@hurrytospring 赞同这个方案,空闲时候比如半夜再删除
|
26
enjoyCoding 2020-06-30 09:04:10 +08:00
两个服务 一个取 取完了通知另一个删除
删除放一个标志位或者存到一个数组里面 一个一个删除 说到底还是异步 |
27
encro 2020-06-30 09:06:37 +08:00
写都没问题,删还会成问题了?所以为什么不取的时候同时删除呢?
或者取的时候写入队列,通过 crontab 或者 supervisord 脚本任何时候想删就删。 |
28
clf 2020-06-30 09:16:03 +08:00
既然这样读写删除性能差,那么为什么要生成文件呢……看上去就是消息队列一样的功能……
|
29
xjmroot 2020-06-30 09:27:58 +08:00
如果是用 Nginx 做代理,访问文件时会有 Nginx 日志,将日志入到 kafka
写个 kafka 消费者消费 Nginx 日志删除文件 |
30
Te11UA OP @SlipStupig @lychs1998 因为内存少昂,你的意思是将文件内容缓存到消息队列是吗 ?
@realpg @billlee 的确不是什么大问题,性能也可以接受,我只是想问下还有什么方式可以去做~当然,这也可能是我过早优化了 |
31
crclz 2020-06-30 09:43:23 +08:00
20w 个文件还是直接用数据库好了,让生产者把文件放数据库里面。传统的关系型数据库都行。
|
32
Huelse 2020-06-30 10:15:03 +08:00
既然时先取后删,建议还是延时删除吧,还可以避开访问高峰
|
33
SlipStupig 2020-06-30 13:22:33 +08:00
@Te11UA 是的啊,队列不是在不停消费嘛,不会占用太多,如果怕占用大,可以压缩后再存
|
34
VictorJing94 2020-06-30 15:55:37 +08:00
取走后给文件加标识?定期统一处理?
|
35
est 2020-06-30 16:30:57 +08:00
高效的方法是建立个删除队列。用一个后台进程慢慢删。
|
36
009694 2020-06-30 16:53:38 +08:00
celery 异步删除
|
37
SjwNo1 2020-06-30 17:09:17 +08:00
消息队列或者 19 楼的做法都行
|
38
no1xsyzy 2020-06-30 17:47:40 +08:00
一致性的要求?是否完整地取走才能被删?取一半对方 RST 了怎么办?取一半 Python 线程 / 进程挂了怎么办?
是否要确认对方确实完全收到?是否要求对方无误地收到? |