小Demo

提供者

在新版本的SpringCloud中进行接口暴露是很简单的,只需要引入open feign的依赖,然后接口就可以被其它服务引用了。

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

消费者

使用这个接口的系统也要引入open feign,同时启动类中加上@EnableFeignClients注解,再写一个简单的接口就可以在其它类中注入这个类了。

1
2
3
4
5
@FeignClient("CloudClientB")
public interface ClientProviderB {
@GetMapping(value = "/hello")
String hello();
}

可以直接注入Bean进行调用:

1
2
3
4
5
6
7
8
9
10
public class ClientConsumerA {

@Autowired
private ClientProviderB clientProviderB;

@RequestMapping("/hello")
public String hello() {
return clientProviderB.hello();
}
}

这时如何实现的呢?可以肯定的是我们的请求肯定是被代理了,我们本次不讨论它是如何代理的,我们只看它在执行时是如何选择服务的。

一张图了解整个过程

SpringCloudLoadBanlacer流程

拿到实例列表后,具体时是如何选择哪一个实例的呢?这就要看用的是轮询算法还是算计算法了,默认是循环算法的。

轮询算法的原理

其中position是一个AtomicInteger,初始值为一个1000以内的随机数,每次请求时如果实例数大于1,则累计position1。

1
2
3
4
5
6
// position = new Random().nextInt(1000)
// 随机值和Integer.MAX_VALUE做与运算,防止position的值溢出
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;

// 用取余操作实现循环访问列表中的元素。当pos的值大于或等于instances.size()时,取余操作会将其限制在instances.size()范围内,从而避免了数组越界的问题。
ServiceInstance instance = instances.get(pos % instances.size());

随机算法

生成[0, instances.size())的一个随机数,然后将这个随机数当做索引获取instances中的实例。

1
2
3
int index = ThreadLocalRandom.current().nextInt(instances.size());

ServiceInstance instance = instances.get(index);