平滑加權(quán)輪詢算法和隨機(jī)訪問

為什么使用平滑加權(quán)輪詢算法

分布式服務(wù)器集群環(huán)境下,每個服務(wù)處理請求的能力不一樣届惋,我們就可以根據(jù)不同服務(wù)器的處理請求能力設(shè)置權(quán)重怯晕,將請求平滑分給各個服務(wù)器進(jìn)行處理,減輕服務(wù)器的壓力
相比隨機(jī)訪問的訪問服務(wù)器方式贩据,可能因為隨即情況導(dǎo)致一個服務(wù)器承受它這個能力范圍內(nèi)不該承受的壓力,宕機(jī)風(fēng)險較大闸餐,而平滑加權(quán)輪詢算法就能大大降低這個風(fēng)險饱亮,嚴(yán)格按照權(quán)重周期性訪問,只要我們的權(quán)重設(shè)置的合理舍沙,可以極大提高系統(tǒng)的抗壓能力

代碼如下:
package algorithm;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author feihong
 * @date 2020-01-03 1:23
 * @description 隨機(jī)訪問服務(wù)器算法
 */
public class RandomAccessToServer {
        //HashMap遍歷時是無序的近上,我們使用隨機(jī)算法時需要有序遍歷
        public static LinkedHashMap<String, Integer> weightMap = new LinkedHashMap<>();
        //記錄某個服務(wù)器的訪問次數(shù)
        static Map<String, Integer> resultMap = new HashMap<>();


        //隨機(jī)訪問,存在隨機(jī)數(shù)集中時某一個服務(wù)器訪問壓力過大的問題
        public static String getServer() {
                int totalWeight = 0;
                for (int i : weightMap.values()) {
                        totalWeight += i;
                }
                int randomVal = new Random().nextInt(totalWeight);
                for (String key : weightMap.keySet()) {
                        int weight = weightMap.get(key);
                        if (randomVal <= weight) {
                                //記錄訪問每個服務(wù)器的次數(shù)
                                if (resultMap.containsKey(key)) resultMap.put(key, resultMap.get(key) + 1);
                                else resultMap.put(key, 1);
                                return key;
                        }
                        randomVal -= weight;
                }
                return null;
        }

        //每次進(jìn)行計算的中間集合
        private static Map<String, Integer> midMap = new HashMap<>();

        //Dubbo拂铡、Nginx 平滑加權(quán)輪詢算法:防止按權(quán)重線性輪詢情況下壹无,某權(quán)重較大的服務(wù)器訪問壓力較大
        public static String getServer2() {
                /**線性周期性循環(huán)
                 * (1)找到midMap中最大值,減去totalWeight(7)
                 * (2)midMap中所有值與weightMap中的值相加
                 * 周期性:
                 * weightMap: 5, 1, 1
                 midMap                                      maxVal - total                            server
                 5,  1, 1    maxWeight = 5    -2 ,  1 , 1(maxWeight - totalWeight)      A
                 3,  2, 2    maxWeight = 3    -4 ,  2 , 2(maxWeight - totalWeight)      A
                 1,  3, 3    maxWeight = 3     1 , -4 , 3(maxWeight - totalWeight)      B
                 6, -3, 4    maxWeight = 6    -1 , -3 , 4(maxWeight - totalWeight)      A
                 4, -2, 5    maxWeight = 5     4 , -2 ,-2(maxWeight - totalWeight)      C
                 9, -1,-1    maxWeight = 9     2 , -1 ,-1(maxWeight - totalWeight)      A
                 7,  0, 0    maxWeight = 7     0 ,  0 , 0(maxWeight - totalWeight)      A
                 新周期開始了
                 5,  1, 1    maxWeight = 5    -2 ,  1 , 1(maxWeight - totalWeight)
                 */
                int maxWeight = 0;
                String server = null;
                //找到權(quán)重最大的服務(wù)器
                for (Map.Entry<String, Integer> entry : midMap.entrySet()) {
                        int weight = entry.getValue();
                        if (weight > maxWeight) {
                                maxWeight = weight;
                                server = entry.getKey();
                        }
                }
                //記錄服務(wù)器訪問次數(shù)感帅,進(jìn)行統(tǒng)計
                if (resultMap.containsKey(server)) resultMap.put(server, resultMap.get(server) + 1);
                else resultMap.put(server, 1);
                //更新midMap
                midMap.put(server, midMap.get(server) - getTotalWeight());
                for (Map.Entry<String, Integer> entry2 : weightMap.entrySet()) {
                        String key = entry2.getKey();
                        midMap.put(key, midMap.get(key) + weightMap.get(key));
                }
                return server;
        }


        public static int getTotalWeight() {
                int totalWeight = 0;
                for (int val : weightMap.values()) {
                        totalWeight += val;
                }
                return totalWeight;
        }


        static {
                weightMap.put("A", 40);
                weightMap.put("B", 10);
                weightMap.put("C", 20);
                weightMap.put("D", 60);
                weightMap.put("E", 30);
                weightMap.put("F", 15);
                weightMap.put("G", 25);
                initialMap();
        }

        //初始化midMap
        public static void initialMap() {
                for (Map.Entry<String, Integer> entry : weightMap.entrySet()) {
                        midMap.put(entry.getKey(), entry.getValue());
                }
        }

        //添加服務(wù)器的方法
        public static void addServer(String ip, int weight) {
                weightMap.put(ip, weight);
        }


        //精確訪問測試
        public static void main(String[] args) {
                for (int i = 0; i < 1000; i++) {
                        getServer2();
                }
                System.out.println("每個服務(wù)器的訪問次數(shù):");
                for (Map.Entry entry : resultMap.entrySet()) {
                        float percent = (Float.parseFloat(entry.getValue() + "") / 1000) * 100;
                        System.out.println(entry.getKey() + ":" + entry.getValue() +
                                ";百分比: " + String.format("%.2f", percent) + "%;" +
                                "實際百分比:" +
                                Float.parseFloat((int) weightMap.get(entry.getKey()) + "") / Float.parseFloat(getTotalWeight() + ""));
                }
        }
}
測試結(jié)果:
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斗锭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子失球,更是在濱河造成了極大的恐慌岖是,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件她倘,死亡現(xiàn)場離奇詭異璧微,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)硬梁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門前硫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荧止,你說我怎么就攤上這事屹电。” “怎么了跃巡?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵危号,是天一觀的道長。 經(jīng)常有香客問我素邪,道長外莲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮偷线,結(jié)果婚禮上磨确,老公的妹妹穿的比我還像新娘。我一直安慰自己声邦,他們只是感情好乏奥,可當(dāng)我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著亥曹,像睡著了一般邓了。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上媳瞪,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天骗炉,我揣著相機(jī)與錄音,去河邊找鬼材失。 笑死痕鳍,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的龙巨。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼熊响,長吁一口氣:“原來是場噩夢啊……” “哼旨别!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起汗茄,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤秸弛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后洪碳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體递览,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年瞳腌,在試婚紗的時候發(fā)現(xiàn)自己被綠了绞铃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡嫂侍,死狀恐怖儿捧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挑宠,我是刑警寧澤菲盾,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站各淀,受9級特大地震影響懒鉴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碎浇,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一临谱、第九天 我趴在偏房一處隱蔽的房頂上張望璃俗。 院中可真熱鬧,春花似錦吴裤、人聲如沸旧找。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钮蛛。三九已至,卻和暖如春剖膳,著一層夾襖步出監(jiān)牢的瞬間魏颓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工吱晒, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留甸饱,地道東北人。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓仑濒,卻偏偏與公主長得像叹话,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子墩瞳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容