需求:如何将请求按照权值 分配给服务器。
大致思想:需要两个全局变量currentWeight 初始化为最大权值 和currentIndex 初始化为0 。从currentIndex开始遍历 找到索引对应Node权值大于等于currentWeight 时候返回Node的ip,同时若currentIndex = currentIndex + 1 后为服务器总数即越界,那么需要重置currentIndex = 0;同时判断currentWeight = currnetWeight - max 更新后的值是否为0,如果为0 则需要将currentWeight = 最大权值。
public class WeightRoundRobbin {
private static int currentWeight = -1,currentIndex = 0;
private static final List<Node> nodes = new ArrayList<>();
private static int max = -1;//最大公约数
static {
nodes.add(new Node("ip1",4));
nodes.add(new Node("ip2",8));
nodes.add(new Node("ip3",16));
Collections.sort(nodes, (Node o1,Node o2)->{
return o1.weight - o2.weight;
});
currentWeight = nodes.get(nodes.size() - 1).weight;
max = getMaxDivide(nodes);//获取最大公约数
}
public static void main(String[] args) {
for(int i = 0;i<28;i++){
System.out.println(getServer());
}
System.out.println();
}
private static String getServer(){
for(int i = currentIndex;i < nodes.size();i++){
if(currentWeight <= nodes.get(i).weight){
currentIndex = i+1;
if(currentIndex == nodes.size()){
currentIndex = 0;
currentWeight -= max;
if(currentWeight == 0){
currentWeight = nodes.get(nodes.size() - 1).weight;
}
}
return nodes.get(i).ip;
}
}
return null;
}
public static int getMaxDivide(List<Node> nodeList){
int res = nodeList.get(0).weight;
for(int i =1;i < nodeList.size();i++){
res = getResult(nodeList.get(i).weight,res);
if(res == 1){
return 1;
}
}
return res;
}
private static int getResult(int a,int b) {
if(a < b){
int tem = b;
b = a;
a = tem;
}
while(a > b){
a %= b;
if(a == 0){
return b;
}else{
int tem = b;
b = a;
a = tem;
}
}
return 1;
}
static class Node{
String ip;
int weight;
public Node(String ip,int weight){
this.ip = ip;
this.weight = weight;
}
}
}
一致性哈希算法:解决分布式系统的存储中普通余数hash算法伸缩性差的问题。比如普通余数hash会在机器节点删除或者增加的时候所有节点的数据都需要重新hash,才会使得后续请求命中相应的机器节点。而我们使用一致性hash 则在删除或者增加结点的情况下,使得原来的请求更多的命中原来的机器节点。
一致性哈希 解决分布式缓存系统中由于机器数量变化导致的大量缓存失效问题。尽可能减少请求和服务机器的映射关系的变动。一致性哈希算法相比于简单模余哈希,可以将缓存失效的范围控制在“相邻”节点上,相邻指的是哈希值的相邻。具体原理是将哈希值逻辑上定位为0-2^31 - 1的范围圆环,然后将机器哈希值作为环上的节点,当请求经过哈希之后顺时针落到某个机器哈希上,则代表该请求与该机器有映射关系,当某个机器节点失效后,会将之前的请求顺次移到下一个顺时针方向的机器节点上,而不是像模余哈希一样,可能面临大范围的缓存失效。 不过可能面临的一种情况是大量请求打到一台机器上面,导致机器级联down,避免方式是使用虚拟节点。即每个机器其实对应多个哈希环上的结点,这样当某个机器宕机的时候,就会将该机器对应的请求分散到其他机器上面而不是像之前一样堆到一台机器上。
延伸:缓存其实有很多类型,cpu缓存、TLB 关于虚拟地址-》物理地址的缓存,还有redis缓存等等
名词解释:缓存穿透:使用redis 的缓存功能,当查询的key 不在缓存中,并且查询数据库也没有查询到值,那么就不会把null值放入缓存,这样大量的这样的请求就会将数据库打垮。
缓存穿透的解决方案:
使用bloom Filter 来解决,基本思想是使用k个hash函数对每个插入数据库的值的请求key做哈希运算,将位数组中k个值对应的比特位置1。为什么布隆过滤器使用较少的存储空间就可以对数十亿级别的数据进行判重呢?其实就是它存储的不是信息本身,而是信息k个哈希函数对应的哈希值 比特位置1,缺点是判重可能会出现误判的情况。
缓存雪崩:当缓存中的大量的key同一时间过期时,会有大量请求打到数据库中导致数据库压力过大,宕机。
解决办法:
过期时间不要设置成一样的;
当第一个发现缓存中没有数据的线程获取互斥锁,之后所有线程获取不到数据后,也要尝试获取锁,获取不到后阻塞等待。直到缓存被更新。
缓存击穿 和缓存雪崩的区别是:缓存击穿是热点数据失效导致大量请求打到数据库 缓存雪崩是大量请求同时打到数据库。还是有一点区别的。本质是差不多的