什么是负载均衡
负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
负载均衡(Load Balance)就是分摊到多个操作单元上进行执行。
负载均衡又分为硬件负载均衡和软件负载均衡。
- 硬件负载均衡:在服务器节点间安装用于负载均衡的设备,比如F5。
- 软件负载均衡:在服务器上安装一些用于负载均衡的软件,比如Nginx,LVS。
客户端负载均衡
Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于 Netflix Ribbon 实现。通过 Spring Cloud 的封装,可以让我们轻松地将面向服务的 REST 模版请求自动转换成客户端负载均衡的服务调用。关于Ribbon详解,请阅Ribbon详解。画个草图:
服务调用-RestTemplate
上一篇博客仅仅介绍了使用Eureka服务注册与发现。但是案例中仅仅只有一个服务(appService),随着业务的壮大,会有更多的服务,那么服务于服务之间如何调用?其实有很多种方法(RestTemplate,HttpClient,OkHttp…),这里使用RestTemplate(RestTemplate + @LoadBalanced 实现负载均衡是配套使用)。
RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 Http 服务的方法。
Spring Cloud Ribbon
@LoadBalanced是Ribbon提供的客户端负载均衡注解
这里展示使用RestTemplate + @LoadBalanced 实现负载均衡。
-
创建eureka-server
这个在上篇博客《1.Spring Cloud 服务注册与服务发现之Eureka》已经讲解过创建过程,这里简单截一些重要的图便于验证。
这里补充一下,如果你已经设置了
spring.application.name
以后,eureka.instance.appname
的设置会失效。在eureka的页面也会显示spring.application.name
的值。每个应用程序一般都会设置spring.application.name
,那么eureka.instance.appname
的设置也没什么意义了。这里eureka-server已经启动。
-
创建微服务作为服务提供者
服务提供者:服务的被调用方,为其他服务提供服务的服务。
这里随便举个例子。以用户管理系统 为例,其他系统均要调用用户管理系统的接口来获取用户信息。
就快速创建Spring Boot项目了。因为要实现负载均衡,老办法,创建一个项目,启3个端口服务。
添加配置
创建实体类User
在启动类添加注解
编写类模拟,这里方便展示,把本地端口放入了用户类的address字段。
修改端口,启动三个,老办法。在上篇博客也做过
分别启动,在eureka中查看注册
-
创建微服务作为服务消费者
服务消费者:服务的调用方,依赖其他服务。
快速创建Spring Boot项目。
勾选
没有勾选则添加maven依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
添加配置
创建实体类User,这里的User类属性是与服务提供者中返回的实体类User是保持一致的。道理很简单,只有保持一致,才能正确接收服务提供者返回的数据。
创建RestTemplate,省事就直接在启动类中添加该方法即可。规范的话就创建配置类来完成。注意:除了添加
@Bean
注解外,还要添加@LoadBalanced
。@Bean @LoadBalanced //Ribbon负载均衡 public RestTemplate restTemplate(){ return new RestTemplate(); }
编写类模拟。RestTemplate提供了调用方法,可以自行点击去查看。这里说个重点:url的拼写为:
http://
+服务名
+接口url
。不要加IP,这很好理解。在eureka中注册了三个user-service服务实例,这样一来Ribbon可以实现负载均衡。这个地方是可以书写user-service的单个服务的完整请求路径,也能调用成功,但请求的永远只是那一个单体服务,实现不了负载均衡。
启动类也不要忘了添加@EnableEurekaClient
注解
-
验证
确保所有的项目均已经正常启动。
查看eureka中 所有的服务已经注册
查看user-service服务提供者的三个服务均正常运行
查看business-service服务消费者的服务正常调用成功
反复调用business-service,查看日志输出
这里可以看到,user-service的三个服务是轮询。这也验证了Ribbon的默认是使用轮询的方式选择服务实例。
Ribbon 七大负载均衡策略
- RoundRobinRule:轮询策略。按照顺序选择server(ribbon默认策略)
- RandomRule:随机策略。随机选择
- RetryRule:重试策略。在一个配置时间段内,当选择server不成功,则一直尝试选择一个可用的server
- BestAvailableRule:最低并发策略。选择一个最小的并发请求的 Server,逐个考察 Server,如果 Server 被标记为错误,则跳过,然后再选择 ActiveRequestCount 中最小的 Server。
- AvailabilityFilteringRule:可用过滤策略。过滤掉那些一直连接失败的且被标记为 circuit tripped 的后端 Server,并过滤掉那些高并发的后端 Server 或者使用一个 AvailabilityPredicate 来包含过滤 Server 的逻辑。其实就是检查 Status 里记录的各个 Server 的运行状态。
- WeightedResponseTimeRule:响应时间加权重策略。根据响应时间分配一个 Weight(权重),响应时间越长,Weight 越小,被选中的可能性越低。(ResponseTimeWeightedRule本质与其一样)
- ZoneAvoidanceRule:区域权重策略。使用 ZoneAvoidancePredicate 和 AvailabilityPredicate 来判断是否选择某个 Server,前一个判断判定一个 Zone 的运行性能是否可用,剔除不可用的 Zone(的所有 Server),AvailabilityPredicate 用于过滤掉连接数过多的 Server。
这是我目前项目版本的的RibbonRule实现类。
如何修改负载均衡的策略?
-
我们可以在配置文件中添加某个服务提供者的负载均衡策略
设置
服务名
+.ribbon.NFLoadBalancerRuleClassName
=策略类。
这里以测试的user-service为例:
server: port: 9001 spring: application: name: business-service eureka: client: service-url: defaultZone: http://localhost:6001/eureka #服务提供者应用名称 user-service: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
策略类的图在上面已经给出。
这里改成随机策略模拟。
-
可以全局设置。全局设置是高于在配置文件中的设置。注意包。
这里设置全局策略为轮询,再测试,从日志查看。已经成了轮询。
补充
RestTemplate提供了多种调用get,post的方法。并对这些方法进行了重载。
当get传递多个参数,可以先将参数放入map中再调用。