(原)
在用ribbon负载均衡取eureka注册中心中的地址时,默认采用循环策略,例如商品服务有3个,分别为URL1,URL2,URL3,那么在客户端第一次取时,会取到URL1,第二次取时取到URL2,第三次是URL3,然后依次循环。
很好奇这种算法是怎么保证永远是顺序取的,如果在高并发下,是否也能按这个顺序,跟一下源码,原来,底层实现是用了一个AtomicInteger来保证原子性的,关键代码在类
com.netflix.loadbalancer.AbstractServerPredicate中
代码如下:
private final AtomicInteger nextIndex = new AtomicInteger(); ... ... private int incrementAndGetModulo(int modulo) { for (;;) { int current = nextIndex.get(); int next = (current + 1) % modulo; if (nextIndex.compareAndSet(current, next) && current < modulo) return current; } }
这里传入的参数modulo为服务列表的数量,如上面的例子为3个,
用了一个自旋,每次会把AtomicInteger里面的值取出来作为URL集合的下标,然后将下一次的下标值存入。
而current < modulo的作用则是为了防止服条减少,下标会越界,比如有10个URL,本次取到了第8个,AtomicInteger里的值为9(下一次的URL列表里的做标),这时挂了9个,只剩1个了,下次再从注册中心取url,这里下标current为9比module1大,这时就不能返回9了,否则会引起下标越界。