网上有很多写的很好的文章,这里参考他人的文章给出自己的理解。
首先给出结论,有两种说法,是基于不同角度来说的:
1、Nginx是服务端的负载均衡,Ribbon是客户端的负载均衡
2、Nginx是集中式的负载均衡,Ribbon是消费者内部线程实现的负载均衡
对于nginx服务器,所有请求到达nginx服务器后,由nginx服务器进行请求路由的分发,实现负载均衡。
对于Ribbon,是是由客户端主动拉取注册中心的服务列表,然后通过负载均衡算法选取一个可用服务实例(其中通过自旋锁的cas来保证服务不被多个线程重复获取)。
下面是Ribbon的负载均衡服务器选择源码(来源:https://blog.csdn.net/mmmmhello/article/details/112370827):
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
while(true) {
if (server == null && count++ < 10) {
List reachableServers = lb.getReachableServers();
List allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
int nextServerIndex = this.incrementAndGetModulo(serverCount);
server = (Server)allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
private int incrementAndGetModulo(int modulo) {
int current;
int next;
do {
current = this.nextServerCyclicCounter.get();
next = (current + 1) % modulo;
//while 自旋操作
} while(!this.nextServerCyclicCounter.compareAndSet(current, next));
return next;
}
举例说明:
用户下单,假设存在两个模块订单模块和商品模块,两个模块均部署了多个服务用于实现负载均衡,并注册在同一个注册中心。用户发送下单请求后,请求先到达nginx,由nginx进行负载均衡将请求转发给订单服务,订单服务处理业务后,需要调用商品服务扣减库存,内部服务一般使用rpc通信,订单服务调用商品服务扣减库存的时候,通过Ribbon先从注册中心获取所有商品服务,然后通过负载均衡算法选取一个可用服务进行调用,过程结束,这个过程是发生在订单服务内的。
综合上面的例子
一、为什么说Nginx是服务端的负载均衡,Ribbon是客户端的负载均衡呢?
1.用户发送请求到nginx,nginx是服务端。
2.Ribbon是微服务之间通信的负载均衡,订单服务调用商品服务时,订单服务就是客户端,商品服务就是服务端。
二、为什么说Nginx是集中式的负载均衡,Ribbon是消费者内部线程实现的负载均衡呢?
1.nginx是所有请求都会通过nginx进行分发,所以是集中式的负载均衡。
2.订单服务在调用商品服务时,在订单服务内部通过Ribbon的负载均衡算法选出商品服务后进行调用,所以是消费者内部线程实现的负载均衡。