<select id="findAllStateWeight" resultType="com.xyc.sms.common.entity.cfg.CfgInterfaceWeight">
SELECT INTERFACE_NAME as interfaceName,WEIGHT as weight
FROM
CFG_INTERFACE_WEIGHT
WHERE STATUS =0 and INTERFACE_TYPE =1
ORDER BY WEIGHT ASC
</select>
权重-随机数-选举算法(重点)
以上业务部分的randomInterFaceWeigth(weights);方法
生成随机数,对应不同数据的权重值按比例瓜分,随机数是在哪个数据的权重瓜分范围,则选举出哪个数据出来
private List<CfgInterfaceConfig> randomInterFaceWeigth(List<CfgInterfaceWeight> weights) {
// map<接口名称, 对应的权重范围>
HashMap<String, RangeStateDTO> map = new HashMap<>();
// 权重总和
double sumWeight = weights.stream().mapToDouble(CfgInterfaceWeight::getWeight).sum();
// 获取随机值,随机数字(0-1) * 所有权重
double random = Math.random() * sumWeight;
// 元素头部索引
int headIndex = 0;
// 元素尾部索引
int tailIndex = weights.size() - 1;
// 范围起始值
Double prevRate = 0d;
// 计算每个接口,对应的权重范围
for (int i = 0; i < weights.size(); i++) {
CfgInterfaceWeight cfgInterfaceWeight = weights.get(i);
if (i == headIndex) {
RangeStateDTO range = new RangeStateDTO(0d, Double.valueOf(cfgInterfaceWeight.getWeight()));
map.put(cfgInterfaceWeight.getInterfaceName(), range);
prevRate = Double.valueOf(cfgInterfaceWeight.getWeight());
} else if (i != tailIndex) {
RangeStateDTO range = new RangeStateDTO(Double.valueOf(prevRate), Double.valueOf(prevRate + cfgInterfaceWeight.getWeight()));
map.put(cfgInterfaceWeight.getInterfaceName(), range);
prevRate = range.getMax();
} else if (i == tailIndex) {
RangeStateDTO range = new RangeStateDTO(prevRate, sumWeight);
map.put(cfgInterfaceWeight.getInterfaceName(), range);
}
}
// 选举出唯一接口
String selectInterfaceName = null;
Set<Map.Entry<String, RangeStateDTO>> entries = map.entrySet();
for (Map.Entry<String, RangeStateDTO> entry : entries) {
RangeStateDTO range = entry.getValue();
if (random > range.getMin() && random <= range.getMax()) {
selectInterfaceName = entry.getKey();
}
}
if (Objects.isNull(selectInterfaceName)) {
return new ArrayList<>();
}
logger.info("接口总权重为[{}],随机数为[{}],各接口对应范围数据[{}],选举出使用的携号转网查询接口为[{}]", sumWeight, random, map.toString(), selectInterfaceName);
return cfgInterfaceConfigMapper.findCfgInterfaceConfigByInterfaceName(selectInterfaceName);
}
算法测试demo类
public class randomNum {
public static void main(String[] args) {
getRange();
}
public static void getRange(){
// map<接口名称, 对应的权重范围>
HashMap<String, Range> map = new HashMap<>();
// 生产随机数字
double randomNum = Math.random() ;
System.out.println(randomNum);
// 获取数据库数据
List<InterfaceRate> interfaceRateList = data();
// 获取最大随机值
double maxRate = maxRate(interfaceRateList);
// 获取随机值,随机数字(0-1) * 所有权重
double actuallRate = randomNum * maxRate;
// 元素头部索引
int headIndex = 0;
// 元素尾部索引
int tailIndex = interfaceRateList.size() - 1;
Double prevRate = 0d;
// 计算每个接口,对应的权重范围
for (int i = 0; i < interfaceRateList.size(); i++) {
InterfaceRate interfaceRate = interfaceRateList.get(i);
if (i == headIndex){
Range range = new Range(0d, Double.valueOf(interfaceRate.getRate()));
map.put(interfaceRate.getInterfaceName(), range);
prevRate = Double.valueOf(interfaceRate.getRate());
}else if (i != tailIndex){
Range range = new Range(Double.valueOf(prevRate) , Double.valueOf(prevRate + interfaceRate.getRate()));
map.put(interfaceRate.getInterfaceName(), range);
prevRate = range.getMax();
}else if ( i == tailIndex){
Range range = new Range(prevRate, maxRate);
map.put(interfaceRate.getInterfaceName(), range);
}
}
System.out.println("所有权重和: " + maxRate);
System.out.println("实际随机权重值: " + actuallRate);
System.out.println("初始化map: "+ map);
// 选举
String selectInteferName = null;
Set<Map.Entry<String, Range>> entries = map.entrySet();
for (Map.Entry<String, Range> entry : entries) {
Range range = entry.getValue();
if (actuallRate > range.getMin() && actuallRate <= range.getMax()){
selectInteferName = entry.getKey();
}
}
System.out.println("调用接口为: " + selectInteferName);
}
/**
* 模拟数据库数据 order by 权重 asc(升序)
* @return
*/
public static List<InterfaceRate> data(){
ArrayList<InterfaceRate> list = new ArrayList<>();
list.add(new InterfaceRate("A",5));
list.add(new InterfaceRate("B",5));
list.add(new InterfaceRate("C",5));
// list.add(new InterfaceRate("D", 25d));
return list;
}
public static double maxRate(List<InterfaceRate> interfaceRateList){
return interfaceRateList.stream().mapToDouble(InterfaceRate::getRate).sum();
}
}