遇到问题:
在使用Spring Cloud Eureka的时候就已经接触到了ribbon, 在RestTemplate的bean上加@LoadBalanced注解,彦江哥说加了它就实现了负载均衡,非常不理解这是为什么。所以Spring Cloud Ribbon到底是什么作用呢?ribbon和这个注解之间有是什么关系呢?
1、Spring Cloud Ribbon是什么?
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。
Spring Cloud Ribbon是一个工具框架,不像服务注册中心那样需要部署,它几乎存在于每个Spring Cloud构建的微服务和基础架构中,因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon完成的。后续要介绍的Feigin,也是基于Ribbon实现的工具。
思考:客户端为什么需要负载均衡?Ribbon又是如何实现客户端的负载均衡的?
(回答:通过下面知道客户端的负载均衡维护的是服务端清单,而不是所谓的客户端清单; 具体实现过程见第。。节)
2、什么是客户端负载均衡?
负载均衡的好处:对系统的高可用、网络压力的缓解、处理能力扩容的重要手段。
我们通常说的负载均衡都是服务端的负载均衡,其中可以分为硬件的负载均衡和软件负载均衡。硬件的负载均衡就是再服务器节点之间安装用于负载均衡的设备,比如F5; 软件负载均衡则是再服务器上安装一些具有负载均衡功能的模块或软件来完成请求分发的工作,比如nginx。服务端的负载均衡会在服务端维护一个服务清单。
客户端负载均衡:所有的客户端都维护着自己要访问的服务端清单(是服务端实例清单)。而这些服务端清单来自服务注册中心。客户端负载均衡也需要心跳检测维护清单服务的健康性,只不过这个工作要和服务注册中心配合完成。
思考:服务端和客户端都有负载均衡,会冲突吗?
3、客户端负载均衡如何使用?
通过Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡非常简单, 两步:
- 服务提供者启动服务实例并注册到服务注册中心
- 服务消费者直接通过调用被@LoadBalanced注解修饰的RestTemplate来实现面向服务的接口调用
(RestTemplate的使用方式相对简单,就先不整理了, 其使用过程在Eureka整理时的代码部分已经实现了)
思考:这么简单么?RestTemplate和Ribbon的客户端负载均衡有什么关系呢?底层就是做了什么样的工作呢?详细分析见Ribbon的源码分析。
4、Ribbon基本原理(Ribbon是如何工作的?)
(参考链接 http://cmsblogs.com/?p=12852)
思考:Ribbon既然实现了负载均衡的功能,类比nginx, 那么Ribbon应该包含的功能包括:
- 存在服务列表
- 服务健康检测
- 负载策略
4.1 Ribbon获取服务列表的方式
两种方式:
1、在配置文件中配置
。。。。
2、和eureka集成
在eureka客户端中初始化一个EurekaRibbonClientConfiguration类,其中的ribbonServerList()方法,就是初始化服务列表的方法。
每一个ribbon客户端都有一个RibbonClientConfiguration配置,初始化RibbonClientConfiguration配置的时候初始化了一些信息,包括是否ping,ribbonclient,还初始化了一个ILoadBalancer对象,调用到了DynamicServerListLoadBalancer方法的enableAndInitLearnNewServersFeature()开启了每30秒去更新一次,eureka服务器的定时任务定时更新BaseLoadBalancer#upServerList对象。
4.2 服务健康检查
在ribbon负载均衡器中,提供了ping机制,每隔一段时间,就会去ping服务器,由 com.netflix.loadbalancer.IPing 接口去实现。
单独使用ribbon,不会**ping机制,默认采用DummyPing(在RibbonClientConfiguration中实例化),isAlive()方法直接返回true。
ribbon和eureka集成,默认采用NIWSDiscoveryPing(在EurekaRibbonClientConfiguration中实例化的),只有服务器列表的实例状态为up的时候才会为Alive。
|
|
4.3 负载策略:
在ribbon负载机制中包括 随机、轮询、连接数最少、权重
- RoundRobinRule(轮询):当eureka列表为10个的话,list为10的话,取服务的顺序为: 1234567890;这是使用取模来实现。// int next = (current + 1) % modulo;
- RandomRule(随机):随机算法,比较简单// int index = rand.nextInt(serverCount);
- BestAvailableRule(当前连接数最少):
使用ribbon客户端负载均衡器的时候,选用了一个客户端,去请求的时候,会让一个线程安全的Integer自增一个值。在请求完毕之后在减少一个值。在feign和ribbon集成请求的代码中,在LoadBalancerCommand#submit()的final ServerStats stats = loadBalancerContext.getServerStats(server);是自增,loadBalancerContext.noteRequestCompletion(stats, entity, exception, tracer.getDuration(TimeUnit.MILLISECONDS), retryHandler);是自减。
- WeightedResponseTimeRule(权重分配):在feign请求得时候会得出一个请求时间,在DynamicServerWeightTask线程中会定时去计算这个服务相应得平均时间。总时间减去每个服务得平均时间就是每个服务得权重。权重越大越容易被选中。如果服务没有开始请求,权重为0的时候默认执行RoundRobinRule策略。
- AvailabilityFilteringRule(服务状态):随机选一台服务,判断服务器的状态。
5、Ribbon的配置
5.1 自动化配置
在没有引入Spring Cloud Eureka等服务治理框架的时候,引入Spring Cloud Ribbon的依赖后,能够自动构建下面这些接口的实现;在同时引入Rureka和Ribbon依赖时,自动化配置会有些不同。
针对个性化的需求,我们可以替换上面的默认配置。
Brixton版本:使用@RibbonClient注解,具体过程可以参考书中内容(没有实践过)
Camden版本:在配置文件中配置,可以通过<clientName>.ribbon.<key>=<value>的形式配置,示例:
hello-server.ribbon.NFLoadBalancerPingClassName=com.netflix.loadbalancer.PingUrl
其中hello-service为服务名,NFLoadBalancerPingClassName参数用来指定具体的IPing接口实现类。
5.2 参数配置
两种参数配置方式:全局配置、指定客户端配置
1、全局配置,只需使用ribbon.<key>=<value>格式进行配置,示例:
ribbon.OkToRetryOnAllOperations=false ribbon.ConnectTimeout=1000 ribbon.ReadTimeout=10000 ribbon.MaxAutoRetriesNextServer=0
2、客户端配置,采用<client>.ribbon.<key>=<value>的形式配置,为客户端指定具体的实例清单,示例:
hello-server.ribbon.listOfServers=localhost:8001,localhost:8002, 其中hello-service为服务名
(没有服务治理框架的帮助,这样设置)(思考:实现一个不和eureka结合的直接通过ribbon配置调用服务的示例)
6、Ribbon与Eureka的结合
6.1 ribbon配置交给eureka
当Spring Cloud的应用中同时引入了Spring Cloud Ribbon和Spring Cloud Eureka依赖时,会触发Eureka中实现的对Ribbon的自动化配置。(一切将会变得简单了。。。)
- Ribbon本来要自己维护的服务实例清单ServerList<Server>, 这是将会被com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList的实例所覆盖,该实现将会将服务清单列表交给Eureka服务治理机制来维护(Eureka将会为我们维护所有服务的实例清单)。
(目的是为了让实例维护策略更加通用,所以使用物理元数据进行负载均衡,而不是使用原生的AWS AMI元数据)
- IPing实现将被 com.netflix.niws.loadbalancer.NIWSDiscoveryPing的实例覆盖,该实现将实例检查的任务交给服务治理框架来维护。
另外也可以通过配置,两者结合使用时也可以禁用Eureka对Ribbon服务实例的维护实现,只需要在配置文件中加入参数: ribbon.eureka.enabled=false
Spring Cloud Ribbon默认实现了区域亲和策略, 所以,我们可以通过Eureka实例的元数据配置来实现区域化的实例配置方案。
6.2 重试机制
思考:为什么需要重试呢?
Spring Cloud Eureka实现的服务治理机制强调了CAP(Consisitency、Availability、Parition tolerance )原理的AP(可用性、可靠性),而Zookeeper这类强调了CP(一致性、可靠性),这也是两者最大的区别。
说明:Eureka为了实现更高的服务可用性,牺牲了一定的一致性,宁愿接受故障实例也不会丢掉健康实例。
5、源码分析(Ribbon底层实现的过程?)