簡單輪詢算法
這種算法比較簡單,舉個例子就是你有三臺服務器
第一臺服務器 | 192.168.1.1 |
第二臺服務器 | 192.168.1.2 |
第三臺服務器 | 192.168.1.3 |
第一個請求過來之后默認訪問第一臺,第二個請求過來訪問第二臺,第三次請求過來訪問第三臺,第四次請求過來訪問第一臺,以此類推。以下是我代碼實現簡單得算法:
public?class?simplepolling?{ ??/** ???*?key是ip ???*/ ??public?static?list?<string>?ipservice?=?new?linkedlist?(); ??static?{ ????ipservice.add("192.168.1.1"); ????ipservice.add("192.168.1.2"); ????ipservice.add("192.168.1.3"); ??} ??public?static?int?pos?=?0; ??public?static?string?getip(){ ????if(pos?>=?ipservice.size()){ ??????//防止索引越界 ??????pos?=?0; ????} ????string?ip?=?ipservice.get(pos); ????pos?++; ????return?ip; ??} ??public?static?void?main(string[]?args)?{ ????for?(int?i?=?0;?i?<p>模擬執行4次執行結果是<br></p> <p><img src="https://img.php.cn/upload/article/000/887/227/168467659564255.png" alt="nginx如何實現輪詢算法"></p> <p>此時如果我有一臺服務器性能比較好(比如192.168.1.1),我想讓這臺服務器處理多一點請求,此時就涉及到了權重得概率,這種算法就不能實現,請看我后面描述的輪詢升級版算法。</p> <p><strong>加權輪詢算法</strong></p> <p>此時我需要把我前面3臺服務器都設置權重,比如第一臺設置5,第二臺設置1,第三臺設置1</p> <table><tbody> <tr class="firstRow"> <td>第一臺服務器</td> <td>192.168.1.1</td> <td>5</td> </tr> <tr> <td>第二臺服務器</td> <td>192.168.1.2</td> <td>1</td> </tr> <tr> <td>第三臺服務器</td> <td>192.168.1.3</td> <td>1</td> </tr> </tbody></table> <p>此時前5個請求都會訪問到第一臺服務器,第六個請求會訪問到第二臺服務器,第七個請求會訪問到第三臺服務器。</p> <p>以下是我給出的代碼案例:</p> <pre class="brush:Java;">public?class?weightpolling?{ ??/** ???*?key是ip,value是權重 ???*/ ??public?static?map<string>?ipservice?=?new?linkedhashmap(); ??static?{ ????ipservice.put("192.168.1.1",?5); ????ipservice.put("192.168.1.2",?1); ????ipservice.put("192.168.1.3",?1); ??} ??public?static?int?requestid?=?0; ??public?static?int?getandincrement()?{ ????return?requestid++; ??} ??public?static?string?getip(){ ????//獲取總的權重 ????int?totalweight?=0; ????for?(integer?value?:?ipservice.values())?{ ??????totalweight+=?value; ????} ????//獲取當前輪詢的值 ????int?andincrement?=?getandincrement(); ????int?pos?=?andincrement%?totalweight; ????for?(string?ip?:?ipservice.keyset())?{ ??????if(pos?<p>此時運行結果是<br></p> <p><img src="https://img.php.cn/upload/article/000/887/227/168467659592116.png" alt="Nginx如何實現輪詢算法"></p> <p>可以看的第一臺服務器執行了5次,后面2臺依次執行一次,依次類推??赡苣阌X得這種算法還不錯。其實這種算法有一個缺點是,如果我第一臺服務器設置權重過大可能我需要很多次請求都執行到第一臺服務器上去,這樣的情況分布是不均勻的,會造成某一臺服務器壓力過大導致崩潰。所以我后面要引入第三種算法來解決這個問題</p> <p><strong>平滑加權輪詢算法</strong></p> <p>這種算法可能比較復雜,我第一次看也有點不太明白,后面看過相關資料在結合我自己的理解給大家圖文解釋一下,這里我舉例的服務器配置和權重還是和上面一樣</p> <table width="654" height="190"> <thead><tr class="firstRow"> <th>請求</th> <th>當前權重 = 自身權重+選中后當前權重</th> <th>總權重</th> <th>當前最大權重</th> <th>返回的ip</th> <th>選中后當前權重=當前最大權重-總權重</th> </tr></thead> <tbody> <tr> <td>1</td> <td>{5,1,1}</td> <td>7</td> <td>5</td> <td>192.168.1.1</td> <td>{-2,1,1}</td> </tr> <tr> <td>2</td> <td>{3,2,2}</td> <td>7</td> <td>3</td> <td>192.168.1.1</td> <td>{-4,2,2}</td> </tr> <tr> <td>3</td> <td>{1,3,3}</td> <td>7</td> <td>3</td> <td>192.168.1.2</td> <td>{1,-4,3}</td> </tr> <tr> <td>4</td> <td>{6,-3,4}</td> <td>7</td> <td>6</td> <td>192.168.1.1</td> <td>{-1,-3,4}</td> </tr> <tr> <td>5</td> <td>{4,-2,5}</td> <td>7</td> <td>5</td> <td>192.168.1.3</td> <td>{4,-2,-2}</td> </tr> <tr> <td>6</td> <td>{9,-1,-1}</td> <td>7</td> <td>9</td> <td>192.168.1.1</td> <td>{2,-1,-1}</td> </tr> <tr> <td>7</td> <td>{7,0,0}</td> <td>7</td> <td>7</td> <td>192.168.1.1</td> <td>{0,0,0}</td> </tr> </tbody> </table> <p>由上圖可以看出第一臺服務器雖然權重設置的是5,但并不是第五次請求過來都是第一臺服務器執行,而是分散執行,調度序列是非常均勻的,且第 7 次調度時選中后當前權重又回到 {0, 0, 0},實例的狀態同初始狀態一致,所以后續可以一直重復調度操作。</p> <p>可能有的人還不能清楚的明白上一張圖表示的含義,我這里大概描述一下:</p> <p>1.首先總權重不會變,默認就是當前設置的權重之和</p> <p>2.在第一次請求進來的時候我默認初始化當前權重選中值是{0,0,0},所以當前權重的值就是{5+0,1+0,1+0},這里的5,1,1就是我們前面每臺服務器設置的權重。</p> <p>3.這里我們可以得出第一次請求過來的最大權重是5。然后返回第一臺服務器ip</p> <p>4.然后我們設置選中后當前權重,這里就是當前最大權重減去總權重(5-7),沒有選中的權重不變,這時候得到當前權重選中權重的值{5-7,1,1}</p> <p>5.在第二次請求過來的時候我們延續上面的2,3,4步驟執行.</p> <p>如果這里還有不懂得我下面會提供我自己用java代碼實現的算法:</p> <pre class="brush:java;">public?class?polling?{ ??/** ???*?key是ip,value是權重 ???*/ ??public?static?map?<string>?ipservice?=?new?linkedhashmap?(); ??static?{ ????ipservice.put("192.168.1.1",5); ????ipservice.put("192.168.1.2",1); ????ipservice.put("192.168.1.3",1); ??} ??private?static?map<string>?weightmap?=?new?linkedhashmap?(); ??public?static?string?getip(){ ????//計算總的權重 ?????int?totalweight?=?0; ????for?(integer?value?:?ipservice.values())?{ ??????totalweight+=value; ????} ????//首先判斷weightmap是否為空 ????if(weightmap.isempty()){ ??????ipservice.foreach((ip,weight)->{ ????????weight?weights?=?new?weight(ip,?weight,0); ????????weightmap.put(ip,weights); ??????}); ????} ????//給map中得對象設置當前權重 ????weightmap.foreach((ip,weight)->{ ??????weight.setcurrentweight(weight.getweight()?+?weight.getcurrentweight()); ????}); ????//判斷最大權重是否大于當前權重,如果為空或者小于當前權重,則把當前權重賦值給最大權重 ????weight?maxweight?=?null; ????for?(weight?weight?:?weightmap.values())?{ ??????if(maxweight?==null?||?weight.getcurrentweight()?>?maxweight.getcurrentweight()){ ????????maxweight?=?weight; ??????} ????} ????//最后把當前最大權重減去總的權重 ????maxweight.setcurrentweight(maxweight.getcurrentweight()?-?totalweight); ????//返回 ????return?maxweight.getip(); ??} ??public?static?void?main(string[]?args)?{ ????//模擬輪詢7次取ip ????for?(int?i?=?0;?i?<p>這里代碼得執行結果是:<br></p> <p><img src="https://img.php.cn/upload/article/000/887/227/168467659543814.png" alt="Nginx如何實現輪詢算法"></p> <p>可以看出此處執行結果和表格里描述得結果一致。</p></string></string>
? 版權聲明
文章版權歸作者所有,未經允許請勿轉載。
THE END