V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
solaro
V2EX  ›  问与答

PHP 如何读取大文件( 1G 文本文件),并且正则匹配查找内容

  •  
  •   solaro · 2017-08-09 14:38:29 +08:00 · 4795 次点击
    这是一个创建于 2665 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题 现在实际业务项目中,目前只能想到用切割 并且参照了如下的文章,读取速度是挺快的,但是要怎么正则匹配出我想要的内容(说白了就是全文搜索) http://blog.csdn.net/jinxingfeng_cn/article/details/52042834

    现在的业务需求是:尽量保证扫一遍 1G 文件得在 3 秒内响应。 preg_match_all。。。这个直接用到文件上,好卡好卡好卡

    求大神给个思路或者实现方式

    22 条回复    2017-08-11 13:24:23 +08:00
    mhycy
        1
    mhycy  
       2017-08-09 14:45:48 +08:00   ❤️ 1
    1G 文件 3 秒内响应,假设文件为 1GB
    不计算运算时间以及 IO 等待耗时,平均每秒读取速度 1024/3=341.333333333MB/S
    首先需要一个 SSD。。。。
    a591826944
        2
    a591826944  
       2017-08-09 14:50:03 +08:00
    1G 嘛。。也不算太大。。服务器内存怕啥。。拉到内存里面搞啊。
    solaro
        3
    solaro  
    OP
       2017-08-09 14:50:31 +08:00
    @mhycy。。。SSD 有了,硬盘不是问题,主要还是思路,难道真的要切割吗?
    solaro
        4
    solaro  
    OP
       2017-08-09 14:50:56 +08:00
    @a591826944 就是不能直接放到内存里面的。。。瞬间内存没了一个 G
    a591826944
        5
    a591826944  
       2017-08-09 14:54:54 +08:00
    @solaro 你家服务器多大的啊? 一个 G 没多少啊。
    a591826944
        6
    a591826944  
       2017-08-09 14:55:43 +08:00
    @solaro 我们连 docker 容器 都有 20 个 G 的内存。供后台跑数据。
    gouchaoer
        7
    gouchaoer  
       2017-08-09 15:07:27 +08:00
    你的 php 程序是一个 php-fpm 还是 php-cli 呢,1G 的文本读进内存也就是个 1G 的 string 而已,如果是 php-cli 的话我认为内存不是问题,如果是 php-fpm 显然是不能读 1G 文本文件的
    有 2 个方案,第一个就是用 yaconf 扩展把文本文件读入共享内存,这样 php-fpm 共享一个 string 副本,每次 get 配置的时候应该会得到一个共享内存的字符串(我不太确定会不会发生 string 复制,发生了复制的话这个办法就不行了: https://github.com/laruence/yaconf/blob/master/yaconf.c#L376,@sagaxu

    第二个就开一个 php-cli 常驻内存专门接受请求

    你这个正则是搜索敏感关键词的话,php 有对应的库: https://github.com/imaben/php-akm
    gouchaoer
        8
    gouchaoer  
       2017-08-09 15:09:19 +08:00
    你应该把搜索 1G 文本需求细说一下,否则不知道怎么优化
    zenxds
        9
    zenxds  
       2017-08-09 15:11:09 +08:00
    模式不复杂的化估计用 awk 就能搞定
    solaro
        10
    solaro  
    OP
       2017-08-09 20:06:29 +08:00
    @a591826944 VPS 就 2G 内存啊哥哥
    solaro
        11
    solaro  
    OP
       2017-08-09 20:06:44 +08:00
    @a591826944 你土豪,VPS 就 2G 内存
    R18
        12
    R18  
       2017-08-09 20:14:24 +08:00
    @solaro #11 上报加内存啊,我们内存 60G
    sagaxu
        13
    sagaxu  
       2017-08-09 23:52:38 +08:00 via Android
    yaconf 是 zero copy 的,不会复制那个 string。但是一秒跑 300M 正则,未必做得到,因复杂度不同而异。
    geelaw
        14
    geelaw  
       2017-08-09 23:55:42 +08:00 via iPhone
    对于固定的表达式把它编译成固定的代码就好了
    msg7086
        15
    msg7086  
       2017-08-10 04:13:13 +08:00
    首先你对于正则的要求也没说清楚。如果正则本身就可能匹配超长内容的话,切割也是没用的。如果是小段匹配的话,找分隔符切割再匹配就好了。
    baelish
        16
    baelish  
       2017-08-10 07:55:05 +08:00
    可以调用 linux 的 grep 命令来解决。
    sofs
        17
    sofs  
       2017-08-10 08:20:28 +08:00 via Android
    1g,3 秒,除了提前放内存里,没其它方法
    lianxiaoyi
        18
    lianxiaoyi  
       2017-08-10 09:17:46 +08:00
    楼上哥们说的没错。。。直接用 linux 命令 grep 吧 。。。。这也是支持正则的。。。。
    nullen
        19
    nullen  
       2017-08-10 09:48:11 +08:00
    看看能否讲一下具体的需求?可以考虑重新设计方案。
    mrgeneral
        20
    mrgeneral  
       2017-08-10 10:41:29 +08:00
    记不记得有一招直接执行命令行的操作?

    exec('grep ...')
    solaro
        21
    solaro  
    OP
       2017-08-11 13:23:30 +08:00
    @nullen 实际业务需求是这样的:公司存在大量的业务日志文件,每个日志文件的大小在生成的时候就设定为 1G,超出之后会再创建新的,由于系统被攻击,现在需要找出大量攻击 IP (全文搜索),preg_match_all 搜索,全都在阿里云上的生产环境里面,所以日志多达几百 G,需要对所有所有日志进行文本搜索,找出攻击者,并屏蔽
    solaro
        22
    solaro  
    OP
       2017-08-11 13:24:23 +08:00
    @nullen 除了找出攻击者,还要看攻击者都发送了什么命令进行攻击。想看它都干了什么
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5589 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 08:00 · PVG 16:00 · LAX 00:00 · JFK 03:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.