一、Ribbon是什么?
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具。
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。我们在配置文件中列出负载均衡所有的机器,Ribbon会自动的帮助我们基于某种规则(如简单轮询、随机连接等等)去连接这些机器。Ribbon客户端组件提供了一列完善的配置项(如连接超时、重试等等),我们也能很容易的使用Ribbon实现自定义的负载均衡算法。
二、负载均衡
负载均衡(Load Balance,简称LB),在微服务或分布式集群中经常用到的一种功能,就是将用户的请求以某种规则平摊到多个服务器上,从而达到系统的高可用。
常见的负载均衡有软件例如Nginx、LVS等等,硬件F5等等。
相应的在中间件,例如Dubbo和Spring Cloud中均给我们提供了负载均衡,Spring Cloud的负载均衡算法可以自定义。
集中式负载均衡:即在服务的消费方和提供方之间使用独立的负载均衡设施(可以是硬件,如F5。也可以是软件,如Nginx),由该设施负责把请求通过某种策略转发至服务的提供方。
进程内负载均衡:将负载均衡逻辑集成到服务消费方,由消费方从服务注册中心获取有那些服务地址可用,然后消费方从这些地址中选择一个合适的服务器。(Ribbon属于进程内负载均衡,它只是一个类库,集成于服务消费方进程,消费方通过它来获取到服务提供方的地址)。
三、Ribbon的使用
1. 服务提供者
(1) 对外提供的方法
@Controller @PropertySource(value = {"classpath:application.properties"}) public class TestApplicationServiceController { @Autowired private Environment environment; @RequestMapping("/test") @ResponseBody public List<Map<String, Object>> test(){ List<Map<String, Object>> result = new ArrayList<>(); for(int i = 0; i < 3; i++){ Map<String, Object> data = new HashMap<>(); data.put("id", i+1); data.put("name", "test name " + i); data.put("age", 20+i); data.put("server.port",environment.getProperty("server.port") ); result.add(data); } return result; } }
(2) 启动类
@EnableDiscoveryClient @SpringBootApplication public class AppService { public static void main(String[] args) { SpringApplication.run(AppService.class, args); } }
(3) 三个服务提供者
8862/8872/8888服务提供者的spring.application.name应用名必须是相同的(即对外暴露的统一的服务实例名)。它们区别于端口不同、实例名称不同。
8862端口:
# 定义SpringBoot应用的名称,建议必须提供。在SpringCloud中,对服务的最大粒度的管理是使用应用命名的 # 最好是一个应用一个名称,在Consumer角色开发的时候,比较容易查找Provider spring.application.name=appService-name server.port=8862 #eureka微服务实例名称修改,不采用默认的, 默认是spring.application.name的大写 eureka.instance.instance-id=appService-minsoft-8862 # 配置Eureka Server的地址信息,如果是Eureka Server集群,多个节点使用逗号','分割。 # 注意:多个地址之间不要有多余的空格, 只有一个逗号 eureka.client.serviceUrl.defaultZone=http://admin:1234@192.168.178.5:8761/eureka/,http://admin:1234@192.168.178.6:8761/eureka/ #启动所有端点, 也可以设置部分启动, 如:env,beans。默认是health, info management.endpoints.web.exposure.include=* ## 启用shutdown,优雅停服功能,配置actuator的优雅关闭 ## actuator 组件监听shutdown请求地址的时候,要求请求的method必须是POST ## shutdown的请求地址是使用:@PostMapping或@RequestMapping(method=RequestMethod.POST) management.endpoint.shutdown.enabled=true #访问信息可以使用IP地址 eureka.instance.prefer-ip-address=true # 对该微服务进行简单的信息介绍, 随便配置 info.app.name=appService-name info.app.port=${server.port} info.company.name=myApplication info.build.artifactId=$project.artifactId$ info.build.version=$project.version$
8872端口:
# 定义SpringBoot应用的名称,建议必须提供。在SpringCloud中,对服务的最大粒度的管理是使用应用命名的 # 最好是一个应用一个名称,在Consumer角色开发的时候,比较容易查找Provider spring.application.name=appService-name server.port=8872 #eureka微服务实例名称修改,不采用默认的, 默认是spring.application.name的大写 eureka.instance.instance-id=appService-minsoft-8872 # 配置Eureka Server的地址信息,如果是Eureka Server集群,多个节点使用逗号','分割。 # 注意:多个地址之间不要有多余的空格, 只有一个逗号 eureka.client.serviceUrl.defaultZone=http://admin:1234@192.168.178.5:8761/eureka/,http://admin:1234@192.168.178.6:8761/eureka/ #启动所有端点, 也可以设置部分启动, 如:env,beans。默认是health, info management.endpoints.web.exposure.include=* ## 启用shutdown,优雅停服功能,配置actuator的优雅关闭 ## actuator 组件监听shutdown请求地址的时候,要求请求的method必须是POST ## shutdown的请求地址是使用:@PostMapping或@RequestMapping(method=RequestMethod.POST) management.endpoint.shutdown.enabled=true #访问信息可以使用IP地址 eureka.instance.prefer-ip-address=true # 对该微服务进行简单的信息介绍, 随便配置 info.app.name=appService-name info.app.port=${server.port} info.company.name=myApplication info.build.artifactId=$project.artifactId$ info.build.version=$project.version$
8888端口:
# 定义SpringBoot应用的名称,建议必须提供。在SpringCloud中,对服务的最大粒度的管理是使用应用命名的 # 最好是一个应用一个名称,在Consumer角色开发的时候,比较容易查找Provider spring.application.name=appService-name server.port=8888 #eureka微服务实例名称修改,不采用默认的, 默认是spring.application.name的大写 eureka.instance.instance-id=appService-minsoft-8888 # 配置Eureka Server的地址信息,如果是Eureka Server集群,多个节点使用逗号','分割。 # 注意:多个地址之间不要有多余的空格, 只有一个逗号 eureka.client.serviceUrl.defaultZone=http://admin:1234@192.168.178.5:8761/eureka/,http://admin:1234@192.168.178.6:8761/eureka/ #启动所有端点, 也可以设置部分启动, 如:env,beans。默认是health, info management.endpoints.web.exposure.include=* ## 启用shutdown,优雅停服功能,配置actuator的优雅关闭 ## actuator 组件监听shutdown请求地址的时候,要求请求的method必须是POST ## shutdown的请求地址是使用:@PostMapping或@RequestMapping(method=RequestMethod.POST) management.endpoint.shutdown.enabled=true #访问信息可以使用IP地址 eureka.instance.prefer-ip-address=true # 对该微服务进行简单的信息介绍, 随便配置 info.app.name=appService-name info.app.port=${server.port} info.company.name=myApplication info.build.artifactId=$project.artifactId$ info.build.version=$project.version$
2. 服务消费者
Ribbon一般集成于服务消费方。
(1) 依赖引入
<!-- ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
(2) application.properties
# 定义SpringBoot应用的名称,建议必须提供。 spring.application.name=app-client server.port=8111 # Eureka Server注册地址, 任何Eureka Client都必须注册。 # 注意:多个地址之间不要有多余的空格, 只有一个逗号 eureka.client.serviceUrl.defaultZone=http://admin:1234@192.168.178.5:8761/eureka/,http://admin:1234@192.168.178.6:8761/eureka/ # 设置负载均衡策略 appservice-name为调用的服务的名称 # 没有配置全部服务的负载均衡策略的方式。因为不是每个服务都可以使用相同负载均衡策略的。 # 如:搜索服务和注册服务就不能使用相同的负载均衡策略。 # appservice-name.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule # 配置服务列表,其中appservice-name代表要访问的服务的应用名,如果有多个服务结点组成集群,多个节点的配置信息使用逗号','分隔。 # 配置服务列表,需要配置要调用的服务的名字和服务所在的位置。 # 服务的名字,就是Application Service(服务提供者)中配置的spring.application.name。 # 服务的位置,就是服务的所在ip和端口。 # 如果服务位置有多个,也就是服务集群,那么使用逗号','分割多个服务列表信息。 appservice-name.ribbon.listOfServers=192.168.178.5:8888,192.168.178.5:8872,192.168.178.5:8862
(3) 启动类
@EnableDiscoveryClient //开启服务发现功能 @SpringBootApplication public class AppClient { public static void main(String[] args) { SpringApplication.run(AppClient.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
(4) 调用服务接口
@RestController @RequestMapping("/demo") public class TestAppController { @Autowired private RestTemplate restTemplate; @GetMapping("/test") public Object test() { String url = String.format("http://%s/test", "appService-name"); //appService-name为服务的应用名称,最终的请求路径为:http://APPSERVICE-NAME/test List<Map<String, Object>> list = restTemplate.getForObject(url, List.class); return list; } }
(5) 启动eureka,注册服务
(6) 访问服务消费者:http://192.168.178.6:8111/demo/test
可以看到每刷新一次,端口就变化。
注:默认负载均衡算法为轮询算法。