2010-10-03 69 views
1

我在一个项目中实施了我的IP禁止功能。 首先,我想避免.htaccess这个目的,因为CMS可能会在修改时重置它,所以我必须使用PHP-send-header-and-die解决方案。 很明显,每个HTTP请求都会被检查。PHP文件存在检查与MySQL选择服务器负载

考虑的高度trafficated网站,我有两个解决方案,存储IP禁令的相关信息:

1 - 在一个目录,假设/禁止/,我可以创建N个文件,其中N =禁止的IP数,所以:

/bans/23.23.23.23.ban

将禁止23.23.23.23,在这种情况下,所有我从我的脚本做的是检查与file_exists,例如:

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

2 - 使用MySQL表,比如说cms_bans,并为每个HTTP请求执行一次SELECT以检查IP是否在禁止列表中。

考虑到这两个解决方案,哪一个对过载影响较小(文件系统vs mysql:D),假设MySQL查询缓存被禁用?

请只激发答案,而不仅仅是个人喜好。

感谢

+0

您是否在制作CMS,或者您在使用预制的吗? – Codeacula 2010-10-03 15:21:22

+0

显然,如果我做了一个预制的CMS,我没有问题使用.htaccess :) – 2010-10-03 15:24:41

+0

你有没有想过使用APC?你可以使用'apc_exists()'方便地检查IP是否被禁止,并且它会很快。这会更复杂一点,因为APC数据存储在RAM中。如果服务器恰好重新启动或清除APC存储,您必须在MySQL(或基于文件)中保存禁用的“永久”副本,并将禁止从该处加载到APC。更多的代码,但肯定比两种解决方案都要快。 – MartinodF 2010-10-03 17:11:30

回答

1

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

0

我会倾向于认为file_exists()开销较少,因为没有远程连接进行,它可以通过PHP缓存。但是,如果你有大量的禁令,并且数据库连接已经被应用程序的其他部分所使用,那么MySQL解决方案开始看起来更好,并且更容易管理。也就是说,我不是这两种方法的粉丝,并且会建议通过防火墙/代理/负载均衡器将禁令移至网络层。另外,如果你没有大量的禁止而且他们不经常改变,那么你最好直接把列表存储为一个PHP数组,include()在你的代码中,然后使用in_array()来扫描禁止:

$banned = array(
    '1.2.3.4', 
    '2.3.4.5', 
    '3.4.5.6' 
); 
if (in_array($ip, $banned)) { baninate(); } 
+0

我有很多禁令,无法管理防火墙/代理/等(共享主机),我也必须管理禁止时间戳(禁止持续时间)...所以PHP解决方案,即使它真的很性感(是我的第一个尝试),可能会消耗太多的内存:(是的,我有一个预先制作的MySQL连接 – 2010-10-03 15:26:28

+0

我认为我们会期望有人问这个问题,而不是微优化将有很多他们需要处理的禁令 – 2010-10-03 15:36:35

+0

好的,给出这个信息,听起来像MySQL选项是你唯一的选择。除非你有一些其他低开销的连接,也可以像Memcache或MongoDB一样准备好。 – 2010-10-03 15:40:00

0

我更喜欢mysql数据库。您可以在表格中存储其他数据,例如banned_bybanned_onbann_reasonaccess_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' 
+0

我不需要这些信息,我只是需要性能:) – 2010-10-03 15:28:12

+2

@Simone - 如果你对性能感到困扰,最好的方法就是测试它。平均计算添加禁令需要多长时间,并使用这两种方法检查禁令。那么你肯定会知道的。 – chigley 2010-10-03 15:31:11

+1

@Simone我怀疑你真的需要它。 – 2010-10-03 16:21:14

0

为什么坚持一个在另一个?

我会建立一个基于MySQL的禁止表,我可以轻松扩展。 MySQL是一个快速系统,考虑到未来,它更加灵活。

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

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

+0

更简单和更好的想法:) – 2010-10-03 15:35:09

+0

您甚至可以通过实施memcached或其他缓存引擎解决方案进一步增强它。 – Codeacula 2010-10-03 15:36:47

+0

我有一段时间以前的缓存解决方案,如果它在服务器上可用,我可以使用该缓存解决方案...无论如何,让我们等待其他答案;) – 2010-10-03 15:39:30

0

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

0

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

这就是为什么问题应该被激励,而不是只出于个人喜好。

+0

我实际上管理一个网站,其中添加一个'file_exists'调用每页加载都会使服务器跪下。我仍然同意,它很可能比网站的许多其他部分“消耗资源更少”,但您不能肯定地说这是否是这种情况。而且,I/O性能和网络延迟都可能迅速成为瓶颈。 – MartinodF 2010-10-03 17:18:15

+0

@MartinodF得到了关于这个膝盖情况的任何细节?我有很多类似函数的调用(尽管is_readable()是我喜欢的),并且从未看到由此函数引起的任何问题。至于网络延迟,请记住经常用于加速的memcache服务器,通常是通过网络分开的服务器。这让我担心普通网络不是问题的原因。让我再次提醒你,不仅是我们存储在数据库中的这些愚蠢的IP地址。 – 2010-10-03 17:28:54

+0

他在谈论共享主机,所以我不确定如何执行他的I/O或MySQL服务器。我也不知道他要处理多少个请求,或者他的应用程序是否需要大量磁盘访问等等。我管理的是一个客户端的严重动力不足的网站,在这个网站上,硬件非常接近极限,因此改变PHP包括从绝对路径到相对路径都会影响性能。这不是一个日常的情况,但我总是喜欢寻找最好的解决方案,即使是像这样一个明显的次要问题:) – MartinodF 2010-10-03 19:00:10

-2

就你原来的问题而言,使用file_exists()对于少量禁止(约< 1000禁令)更快,而使用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后端处理,它很快地进行迭代。

如果你愿意编写你自己的数据库来保持数字列出的禁令(允许二进制搜索),甚至还有更快的方法来做到这一点。

虽然正如几个人已经指出,这是而不是其中任何主要瓶颈将发生在您的服务器。优化您的网站的“禁止检查”部分将为您的整个网站提高0.01%的速度。你想要非常小心的优化是循环运行100次,调用远程服务器以及查询返回数据库的几行数据以进行分析。

另外,不要编写函数来执行已经具有内置PHP函数的内容。我花了一年手动解析字符串数百substr(strpos())线之前,我学会了如何使用preg_replace()