帶權重值的隨機選擇算法

一個新的功能上線都會走灰度的過程,萬一新功能有問題,則會導致線上的大量的報錯,甚至不可用的嚴重情況。比如我們現在本來接入了2個短信渠道去發送短信,現在接入好了第三個渠道,如果我們直接把代碼上了,那麼萬一這個第三個渠道的代碼寫的有問題,那麼意味着我們有三分之一的短信發送不出去,後果非常嚴重。

解決辦法

我們可以爲每個渠道設置一個權重值,短信發送時,按照權重比例隨機選擇短信渠道。初次上線第三個渠道時,可以將這個渠道的權重設置的比較低,比如1%,  這樣即使有問題 ,也就只有1%的受到影響。那如何實現一個帶權重的隨機選擇算法呢?前面都是廢話,直接上code:

import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import com.google.common.collect.Maps;

/**
 * @Author: liuzhijian on 2018/6/11
 */
public class WeigherTest {
    public static void main(String[] args) {
        Map<User, Integer> result = Maps.newHashMap();
        // 初始化權重配置
        Map<User, Integer> weigh = Maps.newLinkedHashMap();
        weigh.put(new User("1"), 10);
        weigh.put(new User("2"), 10);
        weigh.put(new User("3"), 10);

        for (int i=0;i<100000;i++) { 
            User user = getWeighedInstance(weigh);
            //記錄隨機選擇的結果
            if(result.get(user) == null) {
                result.put(user, 1);
            } else {
                result.put(user, result.get(user)+1); // 這裏不考慮線程安全,因爲只在一個線程裏運行
            }
        }
        System.out.println(result); //將結果打印出來,看看是不是真的按照權重選擇的
    }
    static final class User {
        String id;

        public User(String id) {
            this.id = id;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return "User{" +
                    "id='" + id + '\'' +
                    '}';
        }
    }

    // 先計算總的權重值,判斷隨機數在哪個對象的範圍內,返回對象
    static <T> T getWeighedInstance(Map<T, Integer> weighMap) {
        int totalWeight = 0;
        for (Map.Entry<T, Integer> entry : weighMap.entrySet()) {
            totalWeight += entry.getValue();
        }
        int num = ThreadLocalRandom.current().nextInt(totalWeight);
        for (Map.Entry<T, Integer> entry : weighMap.entrySet()) {
            num -= entry.getValue();
            if(num<0){
                return entry.getKey();
            }
        }
        return null;
    }
}

我們可以修改3個User對象的權重值,然後運行一下看看結果是否正確。

 

歡迎關注我的個人的博客www.zhijianliu.cn, 虛心求教,有錯誤還請指正輕拍,謝謝

版權聲明:本文出自志健的原創文章,未經博主允許不得轉載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章