OSS庫對頻率訪問的控制
通過學習,讓我們留下點什麼,知其然,知其所以然。
綜述,採用共享記憶體的方法,記錄每個IP、QQ號的超時前的訪問時間、次數,然後定時更新記錄,從而達到控制。原始碼在local_access_limit.h 與 local_access_limint.cpp的類LocalAccessLimit中。
記憶體資料圖:
預設桶的數量:
DEFAULT_BUCKET_NUM = 999983, //至於這個數字具體怎麼選定,我不清楚,請高人指點。我感覺的一個原則應該是比較大的素數,這樣,在下面求模的時候可以減少碰撞。
DEFAULT_NODE_NUM = 1
/*!\brief node結構 */
typedef struct _NODE
{
int iKey; 節點主鍵
int iTimeStamp; 訪問時間戳
int iAccess; 訪問次數
} Node;
單個桶的大小、
_iBucketSize = sizeof(Node) * _iNodeNum;
Hash表的大小
_iHashTableSize = _iBucketSize *_iBucketNum;
具體流程:
1、建立檔案(_sFilePath)目錄,
開啟/建立檔案,
比較檔案大小是否小於_iHashTableSize+1,
如果小於,通過寫入一位元組“”改變檔案檔案大小到iHashTableSize;
2、建立共享記憶體對映檔案mmap(NULL, _iHashTableSize, PROT_READ | PROT_WRITE, MAP_SHARED, iFd,0)
通過這個共享記憶體檔案中來記錄每個IP結點、QQ號結點在一定時間內的訪問次數,從而進行頻率控制。
3、Hash表維護流程:
1、將iKey(IP、qq轉化為整數值後的值)雜湊到不同的桶中間。
int iBucketIndex = (unsignedint)iKey % _iBucketNum;
HASH到某一個桶中間去。
2、鎖檔案。
FileMutex cFileMutex(_sFilePath.c_str(), iOffset);
FileMutex::CommLock cFileLock(cFileMutex);
cFileLock.Acquire();
關於檔案鎖,我們另附檔案分析。
3、最後是重點,維護桶檔案來記錄訪問次數。
預設_iNodeNum = 1;並且採用先進先出的方法將最早的記錄換出去。
遍歷桶內的每個結點。
a 判斷當前結點是否為當前訪問IP\qq,
不相等:判斷當前結點時間是否早於最早的結點時間,如果是,則記錄該結點。
相等:
判斷當前時間是否在規定的訪問時間間隔內,
不是:記錄該結點,並且退出,後面更新時間記錄。
是:
判斷是否超出規定次數。
是:返回false,超出限制。
否:更新訪問次數。
當找到該結點並且超時、或者沒有找到需要的訪問的結點,那麼採用先進先去的原則,將同一個桶內最早的結點記錄更新為當前結點記錄,即更新結點訪問時間、次數。