Spring Cloud组件中常用的组件里也包含了Ribbon,做负载均衡功能。
目录
(一)简介
spring Cloud Ribbon 是一个客户端的负载均衡器,它提供对大量的HTTP和TCP客户端的访问控制。
客户端负载均衡即是当浏览器向后台发出请求的时候,客户端会向 Eureka Server 读取注册到服务器的可用服务信息列表,然后根据设定的负载均衡策略(没有设置即用默认的),抉择出向哪台服务器发送请求。
(二)实现
工程基于之前eureka工程基础上继续实现,之前eureka项目
这里为了方便从浏览器和postman工具中查看结果项目中增加了web Controller类。
1.配置多个服务端
SPRING-CLIENT-01服务中增加了一个Controller:
package com.cloud.client.controller;
import com.cloud.client.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/getInfo")
public class Controller {
@Value("${server.port}")
String port;
@Value("${spring.application.name}")
String serviceName;
@RequestMapping("/show")
public String getInfo(){
return "I'm form service:"+serviceName+",port:"+port;
}
@RequestMapping(value = "no/{no}", method = RequestMethod.GET)
public String getPolicyFileByPolicyNo(@PathVariable String no,HttpServletResponse httpServletResponse){
try {
String result = "I'm form service:"+serviceName+",port:"+port;
if (result == null){
httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
return null;
} else
return result;
} catch (Exception e) {
e.printStackTrace();
httpServletResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return e.getMessage();
}
}
@RequestMapping("/port")
public String findInfo(){
return "I'm form service:"+serviceName+",port:"+port;
}
}
启动eureka server,启动 SPRING-CLIENT-01,然后再网页或者postman中输入
http://localhost:10001/getInfo/show
得到结果:
然后在IDEA的edit Configurations里面将Single instance Only 勾选掉,SPRING-CLIENT-01服务的配置端口输入不同的端口号,启动,就可以启动多个不同端口号但服务名都是SPRING-CLIENT-01的服务了。
我这边分别启动了端口号是10001,10002的服务,然后在配置中心可以看到服务列表。
2.配置ribbon
之后就是配置ribbon服务了。
在工程之前新建一个module,建立方式和之前建立eureka server和client相同,只是在选择组件的时候加上ribbon组件。
生成之后对应的pom.xml文件里面也就是多了ribbon的配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
配置文件application.properties的内容,我这边因为配置呢mysql,所以有本地mysql的配置,如果没有选jpa和mysql组件,这部分可以不要。
server.port = 11000
eureka.client.serviceUrl.defaultZone= http://localhost:12345/eureka/
spring.application.name= SPRING-CLIENT-02
SPRING-CLIENT-01.ribbon.NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testmysql
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
ribbon的启动类RibbonserviceApplication:
package com.cloud.ribbonservice;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonserviceApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonserviceApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public IRule ribbonRule() {
return new RandomRule(); //这里配置策略,和配置文件对应
}
}
我这里增加了一个RibbonService和IRibbonService
package com.cloud.ribbonservice.service;
public interface IRibbonService {
}
package com.cloud.ribbonservice.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@Service
public class RibbonService implements IRibbonService {
@Autowired
RestTemplate restTemplate;
@Autowired
LoadBalancerClient loadBalancerClient;
public String port() {
this.loadBalancerClient.choose("SPRING-CLIENT-01");
String info = restTemplate.getForObject("http://SPRING-CLIENT-01/getInfo/port", String.class);
return restTemplate.getForObject("http://SPRING-CLIENT-01/getInfo/port", String.class);
}
}
SpringCloud 里面访问其他服务可以通过RestTemplate来实现。
RestTemplate进行rest请求有很多种方式。这个可以看下RestTemplate类具体的接口。
在Spring Cloud里面RestTemplate中直接加对应微服务的名称然后接对应Controller的Web接口。
这边Ribbon服务中对应的Controller是:
package com.cloud.ribbonservice.controller;
import com.cloud.ribbonservice.service.RibbonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/getInfo")
public class Controller {
@Autowired
RibbonService ribbonService;
private static final Logger logger = LoggerFactory.getLogger(Controller.class);
@Value("${server.port}")
String port;
@Value("${spring.application.name}")
String serviceName;
@RequestMapping("/show")
public String getInfo(){
return "I'm form service:"+serviceName+",port:"+port;
}
@RequestMapping("/hellol")
public String showInfol(){
System.out.println("find port");
logger.info("find port");
return ribbonService.port();
}
}
然后运行 启动RibbonserviceApplication,启动之后可以在eureka服务中心看到对应的Ribbon服务也注册进去了。
然后稍等会(这里应该是将服务注册加入进Ribbon需要少量时间),在浏览器或者postman中输入
http://localhost:11000/getInfo/hellol
调用ribbon服务中的RestTemplate
多刷几次就可以看到结果在端口号10001,10002之间切换,也就是达到负债均衡的效果了。
(三)Ribbon和Nginx对比
从上面的结果可以看出来Ribbon 实现的是客户端负载均衡,它可以在客户端经过一系列算法来均衡调用服务。Ribbon 比 Nginx 更注重的是承担并发而不是请求分发,Ribbon 工作时分两步:
第一步:选择 Eureka Server,它优先选择在同一个 Zone 且负载较少的 Server。
第二步:根据用户指定的策略,在从 Server 取到的服务注册列表中选择一个地址,其中 Ribbon 提供了多种策略,例如轮询 RoundRobinRule、随机 RandomRule等。
以上源码github地址: 源码地址