Ribbon 服务
Ribbon 提供了负载均衡和重试功能, 它底层是使用 RestTemplate 进行 Rest api 调用
RestTemplate
RestTemplate 是SpringBoot提供的一个Rest远程调用工具
它的常用方法:
之前的系统结构是浏览器直接访问后台服务
后面我们通过一个Demo项目演示 Spring Cloud 远程调用
使用RestTemplate后服务器的负载明显降低,springCloud 的 ribbon 优化RestTemplate后 效果提升了好几倍
接下来使用Ribbon来远程调用和负载均衡
ribbon 负载均衡和重试
Ribbon的底层包含RestTemplate远程调用工具
Ribbon 负载均衡
步骤 :
- 新建 ribbon 项目
- pom.xml 添加依赖
- application.yml 添加配置
- 主程序
- controller
- 启动,并访问测试
1 - 创建项目
创建项目是有两个依赖,如果使用eureka的话 加入eureka的依赖
2 - pom.xml
添加 ribbon 起步依赖(可选)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
3 - application.yml
spring:
application:
name: ribbon
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
4 - 主程序
创建 RestTemplate 实例
RestTemplate 是用来调用其他微服务的工具类,封装了远程调用代码,提供了一组用于远程调用的模板方法,例如:getForObject()、postForObject() 等
@EnableDiscoveryClient
@SpringBootApplication
public class Sp06RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(Sp06RibbonApplication.class, args);
}
@LoadBalanced //负载均衡注解
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
RestTemplate 设置 @LoadBalanced
@LoadBalanced 负载均衡注解,会对 RestTemplate 实例进行封装,创建动态代理对象,并切入(AOP)负载均衡代码,把请求分发到集群中的服务器
5 - RibbonController
访问路径设置为服务id
@RestController
public class RibbonController {
@Autowired
private RestTemplate rt;
@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
//这里服务器路径用 service-id 代替,ribbon 会向服务的多台集群服务器分发请求
return rt.getForObject("http://item-service/{1}", JsonResult.class, orderId);
}
@PostMapping("/item-service/decreaseNumber")
public JsonResult decreaseNumber(@RequestBody List<Item> items) {
return rt.postForObject("http://item-service/decreaseNumber", items, JsonResult.class);
}
6 - 访问测试
启动ribbon服务器
访问测试,ribbon 会把请求分发到 8001 和 8002 两个服务端口上
Ribbon 重试
什么是重试?
重试是一种错机制,如果
请求后台服务出错
,或者服务器故障
,可以向另一台服务器重试访问
依赖 :
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
application.yml 配置 ribbon 重试 :
spring:
application:
name: ribbon
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka,http://eureka2:2002/eureka
ribbon:
MaxAutoRetriesNextServer: 2
MaxAutoRetries: 1
OkToRetryOnAllOperations: true
MaxAutoRetriesNextServer —— 更换实例的次数 (2次就够了)
MaxAutoRetries —— 当前实例重试次数,尝试失败会更换下一个实例 (1次就够了)
OkToRetryOnAllOperations=true —— 默认只对GET请求重试, 当设置为true时, 对POST等所有类型请求都重试
主程序设置 RestTemplate 的请求工厂的超时
@SpringBootApplication
@EnableDiscoveryClient
public class Sp06RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(Sp06RibbonApplication.class, args);
}
@LoadBalanced //负载均衡注解
@Bean
public RestTemplate restTemplate(){
SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
f.setConnectTimeout(1000);
f.setReadTimeout(1000);
return new RestTemplate();
}
}
利用SimpleClientHttpRequestFactory API来设定超时时间
setConnectTimeout(1000) —— 链接超时1000毫秒
setReadTimeout(1000) —— 暂停时间1000毫秒
访问,测试 ribbon 重试机制
为了测试我们在tem-service 的 ItemController 添加延迟代码,以便测试 ribbon 的重试机制(测试好了后删掉)
@Slf4j
@RestController
public class ItemController {
@Autowired
private ItemService itemService;
@Value("${server.port}")
private int port;
@GetMapping("/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) throws Exception {
log.info("server.port="+port+", orderId="+orderId);
///--设置随机延迟
if(Math.random()<0.6) {
long t = new Random().nextInt(5000);
log.info("item-service-"+port+" - 暂停 "+t);
Thread.sleep(t);
}
///~~
List<Item> items = itemService.getItems(orderId);
return JsonResult.ok(items).msg("port="+port);
}
-
通过 ribbon 访问 item-service,当超时,ribbon 会重试请求集群中其他服务器
- http://localhost:3001/item-service/35