接口
/**
* 负载均衡器(消费端使用)
*/
public interface LoadBalancer {
/**
* 选择服务调用
*
* @param requestParams 请求参数(一致性Hash会用到)
* @param serviceMetaInfoList 可用服务列表
*/
ServiceMetaInfo select(Map<String, Object> requestParams, List<ServiceMetaInfo> serviceMetaInfoList);
}
抽象类
/**
* 为了兼顾无需请求参数的负载均衡
* 使用抽象类
*/
public abstract class AbstractLoadBalancer implements LoadBalancer {
@Override
public ServiceMetaInfo select(Map<String, Object> requestParams, List<ServiceMetaInfo> serviceMetaInfoList) {
return select(serviceMetaInfoList);
}
protected abstract ServiceMetaInfo select(List<ServiceMetaInfo> serviceMetaInfoList);
}
具体实现类仅需继承抽象类即可。
实现类
轮询
AtomicInteger
原子计数器,防止并发冲突问题
/**
* 轮询负载均衡器
*/
public class RoundRobinLoadBalancer extends AbstractLoadBalancer {
/**
* 当前轮询的下标(原子类防止并发问题)
*/
private final AtomicInteger currentIndex = new AtomicInteger(0);
@Override
protected ServiceMetaInfo select(List<ServiceMetaInfo> serviceMetaInfoList) {
if (serviceMetaInfoList.isEmpty()) {
return null;
}
// 只有一个服务,无需轮询
int size = serviceMetaInfoList.size();
if (size == 1) {
return serviceMetaInfoList.get(0);
}
// 取模算法轮询
int index = currentIndex.getAndIncrement() % size;
return serviceMetaInfoList.get(index);
}
}
随机
Random 实现随机选取
/**
* 随机负载均衡器
*/
public class RandomLoadBalancer extends AbstractLoadBalancer {
private final Random random = new Random();
@Override
protected ServiceMetaInfo select(List<ServiceMetaInfo> serviceMetaInfoList) {
int size = serviceMetaInfoList.size();
if (size == 0) {
return null;
}
// 只有 1 个服务,不用随机
if (size == 1) {
return serviceMetaInfoList.get(0);
}
return serviceMetaInfoList.get(random.nextInt(size));
}
}
一致性 Hash
可以使用 TreeMap
实现一致性 Hash 环,该数据结构提供了 ceilingEntry
和 firstEntry
两个方法,便于获取符合算法要求的节点。
/**
* 一致性哈希负载均衡器
*/
public class ConsistentHashLoadBalancer extends AbstractLoadBalancer {
/**
* 一致性 Hash 环,存放虚拟节点
*/
private final TreeMap<Integer, ServiceMetaInfo> virtualNodes = new TreeMap<>();
/**
* 虚拟节点数
*/
private static final int VIRTUAL_NODE_NUM = 100;
@Override
public ServiceMetaInfo select(Map<String, Object> requestParams, List<ServiceMetaInfo> serviceMetaInfoList) {
if (serviceMetaInfoList.isEmpty()) {
return null;
}
// 构建虚拟节点环
for (ServiceMetaInfo serviceMetaInfo : serviceMetaInfoList) {
for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
int hash = getHash(serviceMetaInfo.getServiceAddress() + "#" + i);
virtualNodes.put(hash, serviceMetaInfo);
}
}
// 获取调用请求的 hash 值
int hash = getHash(requestParams);
// 选择最接近且大于等于调用请求 hash 值的虚拟节点 【ceilingEntry】
Map.Entry<Integer, ServiceMetaInfo> entry = virtualNodes.ceilingEntry(hash);
if (entry == null) {
// 如果没有大于等于调用请求 hash 值的虚拟节点,则返回环首部的节点 【firstEntry】
entry = virtualNodes.firstEntry();
}
return entry.getValue();
}
@Override
protected ServiceMetaInfo select(List<ServiceMetaInfo> serviceMetaInfoList) {
// do nothing
return null;
}
/**
* Hash 算法,可自行实现
*
* @param key
* @return
*/
private int getHash(Object key) {
return key.hashCode();
}
}