简单实现分流功能

逻辑比较简单就是对字符串一顿加解密操作然后hashcode然后取模100,然后看取模结果落在哪个组的区间

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Slf4j
public class Percent {
/**
* 流量切分算法(随机)
*
* @param rid rid
* @param groupMap 对照组
* @return 分组
*/
public static String choose(String rid, Map<String, Double> groupMap) {
if (groupMap == null) {
return null;
}
List<String> groups = new ArrayList<>(groupMap.keySet());
List<Double> rates = new ArrayList<>(groupMap.values());
if (CollectionUtils.isEmpty(groupMap) || CollectionUtils.isEmpty(rates)) {
return null;
}

String digest = DigestUtils.md5DigestAsHex(rid.getBytes());
int hashCode = digest.hashCode();
//百分比
int random = Math.abs(hashCode) % 100;
//murmur3_32算法比较好,分布很均匀
//int random = Math.abs(Hashing.murmur3_32().hashString(rid, Charset.forName("utf-8")).asInt())%100;

double start = 0.0;
double end = 0.0;

for (int i = 0; i < rates.size(); i++) {
end = end + rates.get(i);
if (start <= random && random < end) {
String group = groups.get(i);
for (String tempGroup : groups) {
if (group.equals(tempGroup)) {
log.info("choose [rid]: {} [group]: {} random ;{}", rid, group, random);
return group;
}
}
}
start = start + rates.get(i);
}
return null;
}

}

测试

写个main方法测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

public static void main(String[] args) {
Map<String, Double> groups = new HashMap<>();
groups.put("g1", 15d);
groups.put("g2", 25d);
groups.put("g3", 30d);
groups.put("g4", 30d);
Map<String, Integer> groupCountMap = new HashMap<>();
long total = 100000;
for (long i = 0; i < total; i++) {
String group_super_id = choose(UUID.randomUUID().toString(), groups);
if (!groupCountMap.containsKey(group_super_id)) {
groupCountMap.put(group_super_id, 1);
}
groupCountMap.put(group_super_id, groupCountMap.get(group_super_id) + 1);
}
for (Map.Entry<String, Integer> entry : groupCountMap.entrySet()) {
log.info("group : {} count : {} percent :{}", entry.getKey(), entry.getValue(), new BigDecimal(entry.getValue()).divide(new BigDecimal(total), 4, RoundingMode.UP).multiply(new BigDecimal(100)) + "%");
}
}

结果逼近预设值

image-20231211160804894


简单实现分流功能
https://cason.work/2023/12/11/简单实现分流功能/
作者
Cason Mo
发布于
2023年12月11日
许可协议