本篇接于上篇《Ribbon配置负载均衡策略》。
我们来自定义一个基于一致性哈希规则的负载均衡策略。
Deme项目结构如下:
- MyRule
@NoArgsConstructor
public class MyRule extends AbstractLoadBalancerRule implements IRule {
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object key) {
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes())
.getRequest();
// 在这里,我们简单的以uri作为哈希的key
String uri = request.getServletPath() + "?" + request.getQueryString();
return route(uri.hashCode(), getLoadBalancer().getAllServers());
}
public Server route(int hashId, List<Server> addressList) {
if (CollectionUtils.isEmpty(addressList)) {
return null;
}
TreeMap<Long, Server> address = new TreeMap<>();
addressList.stream().forEach(e -> {
// 虚化若干个服务节点,到环上
for (int i = 0; i < 8; i++) {
long hash = hash(e.getId() + i);
address.put(hash, e);
}
});
long hash = hash(String.valueOf(hashId));
SortedMap<Long, Server> last = address.tailMap(hash);
// 当request URL的hash值大于任意一个服务器对应的hashKey,
// 取address中的第一个节点
if (last.isEmpty()) {
address.firstEntry().getValue();
}
return last.get(last.firstKey());
}
public long hash(String key) {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
byte[] keyByte = null;
try {
keyByte = key.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
md5.update(keyByte);
byte[] digest = md5.digest();
long hashCode = ((long) (digest[2] & 0xFF << 16))
| ((long) (digest[1] & 0xFF << 8))
| ((long) (digest[0] & 0xFF));
return hashCode & 0xffffffffL;
}
}
- 修改RibbonConnfiguration中的
@RibbonClient
注解
@Configuration
@RibbonClient(name = "eureka-client", configuration = MyRule.class)
public class RibbonConfiguration {
}
到这里,自定义Ribbon负载均衡策略就完成了!