本文實(shí)例講述了PHP實(shí)現(xiàn)負(fù)載均衡的加權(quán)輪詢方法。分享給大家供大家參考,具體如下:
1. 負(fù)載均衡算法有哪些?
2.如何用PHP實(shí)現(xiàn)加權(quán)輪詢?
實(shí)現(xiàn)思路:
通過傳入不同的用戶id,然后給他們分配不同的主機(jī)。
首先,需要一個(gè)接收用戶id的數(shù)組。
其次,需要一個(gè)存主機(jī)的數(shù)組,這些主機(jī)有不同的權(quán)重。這里的權(quán)重可以這么考慮:
假設(shè)有abc三臺(tái)主機(jī),權(quán)重分別為3,1,1,那么a的占比為0.6,b和c的占比各為0.2。
直接遍歷主機(jī)的數(shù)組,假如用戶來了100個(gè)人,到a的時(shí)候,a的占比是0.6,就從用戶數(shù)組里隨機(jī)取60個(gè)人分給a;輪到b時(shí),b的占比是0.2,就從用戶數(shù)組里隨機(jī)取20人;同理,c20人,這樣就完成了100個(gè)請(qǐng)求的轉(zhuǎn)發(fā)。
可是真實(shí)場(chǎng)景不是固定一批用戶,而是持續(xù)不斷的用戶請(qǐng)求,由于轉(zhuǎn)發(fā)非???,當(dāng)來的新用戶非常少時(shí),每次從用戶隊(duì)列中取完、轉(zhuǎn)發(fā)后立馬去用戶隊(duì)列中取,很有可能每次只取2條,造成請(qǐng)求全部給了a,b和c一直沒有的情況。這時(shí)候可以考慮按照不同策略從用戶隊(duì)列中取數(shù)據(jù)。假設(shè)以前5ms就處理完一次轉(zhuǎn)發(fā),則現(xiàn)在定義兩種策略,如果用戶隊(duì)列中有100個(gè)用戶時(shí),就取出來,按著主機(jī)占比進(jìn)行轉(zhuǎn)發(fā),如果用戶隊(duì)列中不足100人,但是當(dāng)前時(shí)間和上一次取值時(shí)間相差10ms,就取出來進(jìn)行轉(zhuǎn)發(fā),這樣就可以累積5ms,而這5ms里隊(duì)列中又會(huì)多一些用戶請(qǐng)求,這樣就不會(huì)把所有請(qǐng)求都分給一臺(tái)機(jī)器了。
代碼:
?php // php實(shí)現(xiàn)負(fù)載均衡的加權(quán)輪詢(WRR) class WRR { // 每次取100人 const num = 100; // 上次取值時(shí)間,秒級(jí)時(shí)間戳 public $last_time; // 權(quán)重 machine=>weight public $machines = array( 'a' => 3, // 0.6 'b' => 1, // 0.2 'c' => 1 // 0.2 ); // 占比 public $proportion = array(); // 用戶隊(duì)列 public static $user_ids = array(); public function __construct() { // 各機(jī)器的占比 $total = 0; foreach ($this->machines as $machine => $weight) { $total += $weight; } $this->proportion['a'] = $this->machines['a'] / $total; $this->proportion['b'] = $this->machines['b'] / $total; $this->proportion['c'] = $this->machines['c'] / $total; } public function getUsers() { // 用戶人數(shù) $cnt = count(self::$user_ids); $a_num = 0; $b_num = 0; $c_num = 0; if ($cnt >= self::num) { // 隊(duì)列超過100人 $a_num = round(self::num * $this->proportion['a']); $b_num = round(self::num * $this->proportion['b']); $c_num = $cnt - $a_num - $b_num; } else { // 隊(duì)列不足100人 $last_time = $this->last_time; // 上次訪問時(shí)間 while (true) { $current_time = $this->getMillisecond(); if (($current_time - $last_time) >= 10) { // 當(dāng)前時(shí)間和上一次取值時(shí)間超過10ms $a_num = round($cnt * $this->proportion['a']); $b_num = round($cnt * $this->proportion['b']); $c_num = $cnt - $a_num - $b_num; $this->last_time = self::getMillisecond(); // 更新訪問時(shí)間 break; } } } $a = array_splice(self::$user_ids, 0, $a_num); $b = array_splice(self::$user_ids, 0, $b_num); $c = array_splice(self::$user_ids, 0, $c_num); return array( 'a' => $a, 'b' => $b, 'c' => $c ); } // 獲取毫秒級(jí)時(shí)間戳 public function getMillisecond() { list($t1, $t2) = explode(" ", microtime()); return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000); } } // 測(cè)試 $wrr = new WRR(); for ($i = 0; $i 3; $i++) {// 模擬持續(xù)不斷的用戶請(qǐng)求 $random = rand(10, 120); $user_ids = range(1, $random); WRR::$user_ids = $user_ids; $users = $wrr->getUsers(); print_r($users); }
真實(shí)的算法比這個(gè)復(fù)雜多了,它需要考慮一點(diǎn),就是來過的用戶要保持原來分配的機(jī)器,除非原來的機(jī)器掛了。這樣做的原因是緩存。很多基于內(nèi)存的緩存,都是基于用戶級(jí)別的,所以相同的用戶保持同一臺(tái)機(jī)器,有助于提升性能。
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《PHP數(shù)據(jù)結(jié)構(gòu)與算法教程》、《php程序設(shè)計(jì)算法總結(jié)》、《php字符串(string)用法總結(jié)》、《PHP數(shù)組(Array)操作技巧大全》、《PHP常用遍歷算法與技巧總結(jié)》及《PHP數(shù)學(xué)運(yùn)算技巧總結(jié)》
希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。
標(biāo)簽:白銀 廊坊 太原 衡陽 綏化 崇左 辛集 鄂州
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《PHP實(shí)現(xiàn)負(fù)載均衡的加權(quán)輪詢方法分析》,本文關(guān)鍵詞 PHP,實(shí)現(xiàn),負(fù)載,均衡,的,加權(quán),;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。