一般來說,一個項目中總是會有一些較難處理的業務,比如業務復雜花樣繁多的搜索,使用搜索系統如sphinx,lucence等來處理的話,數據源的若是變化過快(如頂、踩、浏覽數之類),則首先推數據的頻率就較難衡量,另外無法精確搜索或排序。所以一般情況下的做法是通過DB進行搜索,並且除了盡量將業務分解到程序層面外,還會在DB前加一層cache。但是這樣做也有不少已知的弊端:
1、實際上很多業務無法放到普通的PHP中處理,如一些較復雜的排序、篩選,通過普通的PHP來實現的話效率還不如MYSQL。
2、cache的命中率也不好保證,特別是對一些使用關鍵詞進行查詢的業務,關鍵詞變化太多。
若是遇到惡意刷的話,DB服務器容易直接掛掉,因此我們可以在程序層面上加一層限制器,限制並發數,該限制器具備以下特點:
1、高效(廢話麼,否則直接刷限制器就刷爆了)。現在是使用memcache進行原子操作計數,可以擴展成使用其他方法。
2、精確到action層。可以單獨限制單個頁面。
3、方便。見仁見智吧
4、成本低廉。包括研發成本與硬件成本。
根據壓測,原先只能100並發的搜索功能,限制100後,壓測800結果正常。
代碼如下:
<?php /** * 搜索 */ public function search(){ //增加計數器功能,超過次數則返回系統繁忙 $viewlimiter = Library::load('viewlimiter'); //訪問限制器的名稱,請用controller+action,盡量單個頁面保持唯一 $limitName = 'search_search'; //最多同時訪問數 $limit = 100; //若是超過數量則直接返回 if(!$viewlimiter->check($limitName, $limit)) { ajaxOutput(0, $this->lang->line('multi_search_limit')); } /*----復雜變態的業務邏輯-----*/ $xxxModel->search($params); } //end func ?>
擴展話題:
1、若是該業務被刷,可能導致正常用戶無法查看內容。 -- 這個問題要解決只能是從系統層面去操作,可見這邊:http://johnsteven.blog.51cto.com/2523007/818209
2、限制數最好能與緩存命中率相結合,一定范圍內自動變更限制數,提高限制的精准度。 -- 這個後期可以進行研究,與緩存類相結合
3、根據服務器負載進行動態控制。 -- 涉及到底層及服務器權限,研究成本較高,有興趣的話可以研究。
注:
本文只說明思路,具體代碼由於一些原因暫時不開放