代码在gitee: rengerpc: rrpc远程方法调用框架开发
负载均衡的前置代码和介绍在我的这篇博客
http://t.csdn.cn/NW3qq
其他的就不多介绍了,之前的文章都有写
以下直接进行代码实现
1、最短响应时间的负载均衡策略
@Slf4j
public class MinimumResponseTimeLoadBalancer extends AbstractLoadBalancer {
@Override
protected Selector getSelector(List<InetSocketAddress> serviceList) {
return new MinimumResponseTimeSelector(serviceList);
}
private static class MinimumResponseTimeSelector implements Selector {
public MinimumResponseTimeSelector(List<InetSocketAddress> serviceList) {
}
@Override
public InetSocketAddress getNext() {
Map.Entry<Long, Channel> entry = RrpcBootstrap.ANSWER_TIME_CHANNEL_CACHE.firstEntry();
if (entry != null) {
if (log.isDebugEnabled()){
log.debug("选取了响应时间为【{}ms】的服务节点.",entry.getKey());
}
return (InetSocketAddress) entry.getValue().remoteAddress();
}
// 直接从缓存中获取一个可用的就行了
System.out.println("----->"+Arrays.toString(RrpcBootstrap.CHANNEL_CACHE.values().toArray()));
Channel channel = (Channel)RrpcBootstrap.CHANNEL_CACHE.values().toArray()[0];
return (InetSocketAddress)channel.remoteAddress();
}
}
}
2、一致性hash 的负载均衡策略
@Slf4j
public class ConsistentHashBalancer extends AbstractLoadBalancer {
@Override
protected Selector getSelector(List<InetSocketAddress> serviceList) {
return new ConsistentHashSelector(serviceList,128);
}
/**
* 一致性hash的具体算法实现
* 将服务列表缓存进去
*/
private static class ConsistentHashSelector implements Selector{
//hash环存储服务器节点 SortedMap中增加了元素的排序,这意味着可以给SortedMap中的元素排序
private SortedMap<Integer,InetSocketAddress> circle = new TreeMap<>();
//虚拟节点的个数
private int virtualNodes;
public ConsistentHashSelector(List<InetSocketAddress> serviceList,int virtualNodes) {
this.virtualNodes = virtualNodes;
for (InetSocketAddress inetSocketAddress : serviceList) {
//把每一个节点放入hash环中
addNodeToCircle(inetSocketAddress);
}
}
@Override
public InetSocketAddress getNext() {
//1.hash环已经建立,需要rrpcRequest
//使用ThreadLocal获取请求内容
RrpcRequest rrpcRequest = RrpcBootstrap.REQUEST_THREAD_LOCAL.get();
//根据请求的一些特征来选择服务器
String requestId = Long.toString(rrpcRequest.getRequestId());
//请求的id做hash,String默认的hash算法不够散列,是连续的内存地址
int hash = hash(requestId);
//判断hash值是否能直接落在一个服务器上,和服务器的hash一样
if (!circle.containsKey(hash)){
//寻找最近的节点,返回一个tailmap 红黑树
SortedMap<Integer, InetSocketAddress> tailMap = circle.tailMap(hash);
//判断是否为空,为空则表示树内没有比它的hash值更大的了,因此返回最小节点
hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
}
return circle.get(hash);
}
/**
* 将虚拟节点进行挂载
* @param inetSocketAddress
*/
private void addNodeToCircle(InetSocketAddress inetSocketAddress) {
//为每一个节点生成匹配的虚拟节点进行挂载
for (int i = 0; i < virtualNodes; i++) {
//计算hash值,原有的hash内存是连续的,而我们需要散列的地址
int hash = hash(inetSocketAddress.toString() + "-"+i);
//挂载到hash环上
circle.put(hash,inetSocketAddress);
if (log.isDebugEnabled()){
log.debug("hash为【{}】的节点,已经挂载到了哈希环上",hash);
}
}
}
/**
* 删除节点
* @param inetSocketAddress
*/
private void removeNodeToCircle(InetSocketAddress inetSocketAddress) {
for (int i = 0; i < virtualNodes; i++) {
//计算hash值,原有的hash内存是连续的,而我们需要散列的地址
int hash = hash(inetSocketAddress.toString() + "-"+i);
//删除节点
circle.remove(hash);
}
}
/**
* 具体的hash算法
* @param s
* @return
*/
private int hash(String s) {
//使用md5生成hash值
MessageDigest md;
try {
md=MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
byte[] digest = md.digest(s.getBytes());
//将字节数组转化为int
int res = 0;
for (int i = 0; i < 4; i++) {
//4个字节组成int
res = res << 8;
if (digest[i] < 0){
res = res | (digest[i] & 255);
}else {
res = res | digest[i];
}
/* System.out.println("d--> " + toBinary(digest[i]));
System.out.println("r--> " + toBinary(res));*/
}
return res;
}
/**
* 二进制补零函数
* @param i
* @return
*/
private String toBinary(int i){
//如果二进制数不到32位 其余位置补零
String s = Integer.toBinaryString(i);
int index = 32 - s.length();
StringBuilder stringBuilder = new StringBuilder();
for (int j = 0; j < index; j++) {
stringBuilder.append(0);
}
stringBuilder.append(s);
return stringBuilder.toString();
}
}
}
3、随机轮询的负载均衡策略
@Slf4j
public class RandomRobinLoadBalancer extends AbstractLoadBalancer {
@Override
protected Selector getSelector(List<InetSocketAddress> serviceList) {
return new RandomRobinSelector(serviceList);
}
/**
* 选择器
* 将服务列表缓存进去
*/
private static class RandomRobinSelector implements Selector{
private List<InetSocketAddress> serviceList;
public RandomRobinSelector(List<InetSocketAddress> serviceList) {
this.serviceList = serviceList;
}
@Override
public InetSocketAddress getNext() {
if (serviceList == null || serviceList.size() == 0){
log.error("进行负载均衡选取节点时,发现服务列表为空");
throw new LoadBalanceException();
}
//随机轮询
Random random = new Random();
int rand = random.nextInt(0,serviceList.size());
InetSocketAddress address = serviceList.get(rand);
return address;
}
}
}