2010-10-03 35 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()