代码之家  ›  专栏  ›  技术社区  ›  Simone Margaritelli

php文件存在性检查vs mysql select服务器加载

  •  1
  • Simone Margaritelli  · 技术社区  · 15 年前

    我正在我的一个项目中实现一个IP禁止功能。 首先,我想避免使用.htaccess,因为CMS可能会在修改后重置它,所以我必须使用php发送头和死解决方案。 显然,每个HTTP请求都将被检查。

    考虑到一个流量很大的站点,我有两个存储IP禁令信息的解决方案:

    1-在一个目录中,比如/bans/,我可以创建n个文件,其中n=被禁止的IP数量,所以:

    /禁令/23.23.23.23.禁令

    会禁止23.23.23.23,在这种情况下,我要做的就是检查我的脚本 文件存在 ,例如:

    <?php
        if( file_exists("bans/".$_SERVER['REMOTE_ADDR'].".ban"){
            header("HTTP/1.0 403 Forbidden");
            die();
        }
        else{
            // Continue surfing ....
        }
    ?>
    

    2-使用一个mysql表,比如cms-ban s,然后对每个HTTP请求执行一个select,以检查IP是否在ban列表中。

    考虑到这两个解决方案,假设禁用了MySQL查询缓存,那么哪个解决方案的过载影响较小(filesystem vs mysql:d)?

    请只回答有动机的问题,而不只是个人喜好。

    谢谢

    7 回复  |  直到 14 年前
        1
  •  1
  •   georgepsarakis    14 年前

    在内存引擎中使用mysql表。每隔一段时间将其转储到另一个永久表中,以便在服务器重新启动后保持IP的存储和持久性。

        2
  •  0
  •   Alex Howansky    15 年前

    我倾向于认为文件_exists()的开销较小,因为没有远程连接,可以通过php缓存。但是如果你有大量的BAN,并且已经为应用的其他部分建立了DB连接,那么MySQL解决方案就开始变得更好,当然也更容易管理。也就是说,我不喜欢这两种方法,我建议通过防火墙/代理/负载均衡器将BAN移动到网络层。

    或者,如果您没有大量的BAN,并且它们不经常更改,那么最好将列表直接存储为一个php数组,在代码中包含(),然后使用in_array()扫描BAN:

    $banned = array(
        '1.2.3.4',
        '2.3.4.5',
        '3.4.5.6'
    );
    if (in_array($ip, $banned)) { baninate(); }
    
        3
  •  0
  •   Jürgen Steinblock    15 年前

    我更喜欢MySQL数据库。您可以在表中存储其他数据,如 banned_by , banned_on , bann_reason access_count .

    在你的代码中你只做一个

    SELECT COUNT(1) FROM banns WHERE ip = '23.23.23.23' 
    

    假设您在IP列上有一个索引,那么应该非常快。如果有人打的是禁令,你就做一个

     UPDATE banns SET access_count = access_count + 1 WHERE ip = '23.23.23.23'
    
        4
  •  0
  •   Codeacula    15 年前

    为什么一个接一个?

    我将建立一个基于MySQL的BAN表,我可以轻松地扩展它。MySQL是一个快速的系统,并且更加灵活地记住未来。

    但是,您也可以将结果自己缓存在一个文件中并从中读取。现在,任何熟悉MySQL的人都可以直接添加BAN,他们不需要知道您的特殊格式就可以直接使用它(在您的BAN系统扩展的情况下,使用它等等)。那么,这里的问题是文件权限。所以,您只需要添加一点额外的代码来弥补这一点。

    如果他们需要更新缓存,给他们能力。

        5
  •  0
  •   My name is Richard    15 年前

    你没有说你在使用什么CMS,但是如果是开源的或者你自己的,为什么不修改它来使用.htaccess来禁止?

        6
  •  0
  •   Your Common Sense    15 年前

    我不认为这个问题与性能有关。
    与应用程序的其他部分相比,这种简单的键值查找永远不会成为瓶颈。
    这是一个经常犯的错误:人们倾向于优化网站中资源消耗较少的部分,没有任何特殊的原因,但因为这只是他们的想法。

    这就是为什么 问题应该是有动机的,而不仅仅是出于个人喜好。

        7
  •  -2
  •   stevendesu    15 年前

    就你原来的问题而言,用 file_exists() 对于少量BAN(大约1000个BAN),使用MySQL更快。与数据库的连接只进行了一次,而返回的答案只发送了一次,因此MySQL的“瓶颈”只增加了一组恒定的时间来进行查询。MySQL(和其他数据库)软件的伸缩性非常好,因为每行有一个恒定的字节宽度,所以只需要检查nRx到nRx+y的字节数是否是n的整数倍。

    在旧的文件系统中,操作系统可以 做这样的假设,因为文件的长度是可变的。因此,它会扫描 end_of_file 比特。较新的操作系统在分区的开始创建每个文件的数据库(“文件分配表”),它只需要搜索这个。问题是-计算机上的文件越多,搜索此表所需的时间就越长。此外,驱动器的碎片化会使查找文件是否仍然存在变得更加困难。这些小的减速不等于连接到SQL数据库所需的时间…对于少量的禁令。

    一个更好的解决方案是让一个文本文件每行包含一个禁令。

    bans.txt:
    23.23.23.23
    192.168.1.42
    200.200.200.200
    

    那你就用 strpos($file_contents, $_SERVER["REMOTE_ADDR"] . 注意,PHP的行数越少,最终运行的速度就越快,因为PHP的C后端比解释快100倍。因此,我们可以用两条线 get_file_contents() (将内容转储到RAM)和 strpos() (在RAM中搜索一个字符串)它完全由C后端处理,C后端非常快速地迭代。

    如果您愿意编写自己的数据库来保持BAN的数字列表(允许二进制搜索),那么还有更快的方法来实现这一点。

    尽管正如一些人所说,这是 在您的服务器中会出现任何主要瓶颈。优化网站的“禁止检查”部分将使整个网站的速度提高0.01%。您真正需要小心优化的是运行100次的循环、对远程服务器的调用以及返回要分析的数据库多行的查询。

    另外,不要编写函数来执行已经有内置PHP函数的操作。我花了一年时间手工分析字符串 substr(strpos()) 在我学会使用之前 preg_replace()