负载均衡

这里考虑到SDK如何获取到tcp服务的地址

  1. 可以在SDK上写死一个ip,让这个SDK一直去连接这个地址。如果这个地址挂了,这个服务就会挂掉,这个sdk就得进行修改
  2. 也可以在SDK上写多个ip,如果这四个ip都挂了,才算挂了
  3. 暴露一个http请求,每次用户登录的时候,都会往这个请求,拿一次tcp的连接地址,如果是web端获取到web的地址,如果是tcp就拿到tcp的地址

这里我们要使用上面的第三种方式来实现,所以要在逻辑层导入zk方面的东西

1.随机算法

public String getRandom(List<String> allNode) {
    int size = allNode.size();
    if(size == 0){
        throw new ApplicationException(UserErrorCode.SERVER_NOT_AVAILABLE);
    }
    int idx = ThreadLocalRandom.current().nextInt(size);
    return allNode.get(idx);
}

2.轮询算法

AtomicInteger index = new AtomicInteger();
    public String getLoop(List<String> allNode) {
        int size = allNode.size();
        if(size == 0){
            throw new ApplicationException(UserErrorCode.SERVER_NOT_AVAILABLE);
        }
        int idx = index.incrementAndGet() % size;
        if(idx < 0) {
            idx = 0;
        }
        return allNode.get(idx);
    }

3.Hash一致性算法

Hash一致性的思路就是:

  1. 创建一个TreeMap,即按key排序的HashMap
  2. 往里面加入元素,key是hash(ip),values是ip
  3. 第三步,判断long l = hash(userName)与哪个key最近,就分配到哪个ip上面去
HashRoute hashRoute = new HashRoute();
public String getHash(List<String> allNode, String userInfo) {
    hashRoute.clear();
    for (String s : allNode) {
        hashRoute.add(hashRoute.hash(s), s);
    }
    return hashRoute.getNearest(hashRoute.hash(userInfo));
}
public class HashRoute {
    private TreeMap<Long, String> treeMap = new TreeMap<>();
    private static final int NODE_SIZE = 2;

    public void clear() {
        treeMap.clear();
    }

    public void add(Long key, String s) {
        for (int i = 0; i < NODE_SIZE; i++) {
            treeMap.put( this.hash("node" + key), s);
        }
        treeMap.put(key, s); 
    }

    public String getNearest(Long hash) {
        SortedMap<Long, String> last = treeMap.tailMap(hash);
        if(treeMap.size() == 0){
            throw new ApplicationException(UserErrorCode.SERVER_NOT_AVAILABLE);
        }
        return last.get(last.firstKey());
    }

    // hash运算
    public Long hash(String value){
        MessageDigest md5;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 not supported", e);
        }
        md5.reset();
        byte[] keyBytes = null;
        try {
            keyBytes = value.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Unknown string :" + value, e);
        }

        md5.update(keyBytes);
        byte[] digest = md5.digest();

        // hash code, Truncate to 32-bits
        long hashCode = ((long) (digest[3] & 0xFF) << 24)
            | ((long) (digest[2] & 0xFF) << 16)
            | ((long) (digest[1] & 0xFF) << 8)
            | (digest[0] & 0xFF);

        long truncateHashCode = hashCode & 0xffffffffL;
        return truncateHashCode;
    }
}

回调