前言
下面是abtest进行流量分流和保证用户粘性的核心算法代码demo,生产中还需要考虑到指标收集、落库、缓存提高并发,保证高并发高可用高效率。
如果需要集成到网关服务springcloud gateway,请结合我的另一篇文章
首先依旧采用ketemaHash算法,替代默认的hashcode方法,实现分布更加均匀的hash算法:
public class KetamaHash {
private static MessageDigest md5Digest;
static {
try {
md5Digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException var1) {
throw new RuntimeException("MD5 not supported", var1);
}
}
public int getHash(String origin) {
byte[] bKey = computeMd5(origin);
long rv = (long)(bKey[3] & 255) << 24 | (long)(bKey[2] & 255) << 16 | (long)(bKey[1] & 255) << 8 | (long)(bKey[0] & 255);
return (int)(rv & 4294967295L);
}
private static byte[] computeMd5(String k) {
MessageDigest md5;
try {
md5 = (MessageDigest)md5Digest.clone();
} catch (CloneNotSupportedException var3) {
throw new RuntimeException("clone of MD5 not supported", var3);
}
md5.update(k.getBytes());
return md5.digest();
}
}
一个比较简单的ab路由算法
private static String calculation( GroupDto group,String info){
KetamaHash ketamaHash = new KetamaHash();
BigDecimal a = group.getAPercentage().multiply(BigDecimal.TEN);
BigDecimal b = group.getBPercentage().multiply(BigDecimal.TEN);
BigDecimal z = group.getZPercentage().multiply(BigDecimal.TEN);
BigDecimal total = a.add(b).add(z);
int hasCode = Math.abs(ketamaHash.getHash(info));
double v = hasCode % total.doubleValue();
BigDecimal vb = new BigDecimal(v);
if (vb.compareTo(a) < 0){
return "A";
}else if (vb.compareTo(a.add(b)) < 0){
return "B";
}else {
return "Z";
}
}
最后进行测试
public static void main(String[] args) {
long l = System.currentTimeMillis();
KetamaHash ketamaHash = new KetamaHash();
GroupDto groupDto = new GroupDto(BigDecimal.valueOf(0.5),BigDecimal.valueOf(0.3),BigDecimal.valueOf(0.2));
List list = new ArrayList();
for (int i = 0; i < 10000; i++) {
String s = calculation(groupDto, "hello"+Math.random());
list.add(s);
System.out.println(i+":"+s);
}
long l1 = System.currentTimeMillis();
System.out.println(l1-l);
int a = countLetters(list, "A");
int b = countLetters(list, "B");
int z = countLetters(list, "Z");
System.out.println("A出现了:"+a+"次");
System.out.println("B出现了:"+b+"次");
System.out.println("Z出现了:"+z+"次");
}
public static int countLetters(List list,String info ) {
int counts=0;
for(int i=0;i<list.size();i++)
{
if (list.get(i).equals(info))
{
counts++;
}
}
return counts;
}
结果