1. 负载均衡Ribbon
1.1 ribbon概述
- 什么是Ribbon?
ribbon是基于netfilx ribbon实现的一个工作在consumer端的负载均衡工具,提供了很多负载均衡策略:轮询策略、随机策略...
- Ribbon的启动器
nacos已经集成了ribbon,故无启动器。
1.2 Ribbon入门案例
- ConfigBean
@Configuration
public class BeanConfig {
/**
* 负载均衡工作原理:
* 1.Ribbon会给RestTemplate添加一个拦截器,RestTemplate通过服务名“ribbon_provider”获取到List<ServiceList>
* 2.通过负载均衡算法得到serviceInstance
* 3.通过serviceInstance把url中的服务名“ribbon_provider”替换成ip和port
* @return
*/
@Bean
@LoadBalanced // 开启负载均衡,默认为轮询策略
public RestTemplate restTemplate(){
return new RestTemplate();
}
// 使用随机策略调用服务提供者
@Bean
public IRule iRule(){
return new RandomRule();
}
}
- Controller
@RestController
@RequestMapping(value = "/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/getUserById/{id}")
public User getUserById(@PathVariable Integer id) {
//不使用ribbon:ip:port
//String serviceUrl = "127.0.0.1:9090";
//使用ribbon:不再使用ip:port的方式,而是改成了serviceId(即Nacos中注册的服务名称)
String serviceUrl = "ribbon-provider";
return restTemplate.getForObject("http://" + serviceUrl +
"/provider/getUserById/" + id, User.class);
}
}
- 测试
分别使用轮询和随机策略调用服务提供者
2. 声明式服务调用Feign
2.1 feign介绍
- 什么是feign
Feign是Spring Cloud提供的声明式、模板化的HTTP客户端, 它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可。
Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解;Feign默认集成了Ribbon,所以Fegin默认就实现了负载均衡的效果。总结来说:ribbon + restTemplate = feign。
- feign的启动器
spring-cloud-starter-openfeign
2.2 feign的入门案例
1. 创建feign_provider
复制一个nacos_provider即可。
2. 创建feign_interface
- pom.xml
<!--Spring Cloud OpenFeign Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.sanjin</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- feign接口
package com.bjpowernode.feign;
@FeignClient(value="feign-provider") // 调用指定服务,@FeignClient("服务名")
@RequestMapping(value = "/provider")
public interface UserFeign {
@RequestMapping(value = "/getUserById/{id}")
public User getUserById(@PathVariable(value="id") Integer id);
}
3. 创建feign_consumer
- pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.sanjin</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--feign接口-->
<dependency>
<groupId>com.sanjin</groupId>
<artifactId>feign_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- application.yml
server: port: 80 spring: cloud: nacos: discovery: server-addr: 192.168.75.131:8848 #nacos注册地址 namespace: dev group: springcloud_parent application: name: feign-consumer
- controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserFeign userFeign;
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable("id") Integer id){
return userFeign.getUserById(id);
}
}
- APP
package com.sanjin;
@SpringBootApplication
@EnableDiscoveryClient // 向注册中心注册该服务并发现其他服务
//@EnableFeignClients(basePackages = "com.bjpowernode.feign") 扫描指定包
@EnableFeignClients // 开启feign注解扫描
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}
2.3 feign工作原理
1、扫描feign接口生成代理类并交给spring容器去管理
@EnableFeignClient开启feign注解扫描:FeignClientsRegistrar.registerFeignClients()扫描被@FeignClient标识的接口并生成代理类,再把代理类交给spring的容器去管理。
2、为接口的方法创建requestTemplate
当consumer调用feign接口的代理类时,会调用SynchronousMethodHandler.invoke()创建RequestTemplate(HttpMethod、UriTemplate、Body)。
3、发送请求
代理类会通过requestTemplate创建request对象,然后client(HttpClient、URLConnect、OkHttp)使用request发送请求。
2.4 feign传参方式
restful风格:
feign接口:@PathVarible("id")
?传参:
feign接口:@RequestParam("id")
pojo:
feign接口:@RequestBody
案例:
- ConsumerController
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserFeign userFeign;
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable("id") Integer id){
return userFeign.getUserById(id);
}
@RequestMapping("/delUserById")
public User delUserById( Integer id){
return userFeign.delUserById(id);
}
@RequestMapping("/updateUser")
public User updateUser(User user){
return userFeign.updateUser(user);
}
@RequestMapping("/addUser")
public List<User> addUser(){
List<User> userList = new ArrayList<>();
userList.add(new User(1, "ljx", 18));
userList.add(new User(2, "mxx", 18));
return userFeign.addUser(userList);
}
@RequestMapping("/delUserByIds")
public Integer[] delUserByIds(Integer[] ids){
return userFeign.delUserByIds(ids);
}
}
- UserFeign接口
@FeignClient("feign-provider") // 调用指定服务,@FeignClient("服务名")
@RequestMapping("/provider")
public interface UserFeign {
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable("id") Integer id);
@RequestMapping("/delUserById")
public User delUserById(@RequestParam("id") Integer id);
@RequestMapping("/updateUser")
public User updateUser(@RequestBody User user);
@RequestMapping("/addUser")
List<User> addUser(@RequestBody List<User> userList);
@RequestMapping("/delUserByIds")
Integer[] delUserByIds(@RequestParam("ids") Integer[] ids);
}
- ProviderController
@RestController
@RequestMapping("/provider")
public class ProviderController {
@Autowired
private UserService userService;
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
return userService.getUserByUserId(id);
}
@RequestMapping("/delUserById")
public User delUserById(Integer id){
return userService.delUserById(id);
}
@RequestMapping("/updateUser")
public User updateUser(@RequestBody User user){
return userService.updateUser(user);
}
@RequestMapping("/addUser")
public List addUser(@RequestBody List<User> userList){
return userService.addUser(userList);
}
@RequestMapping("/delUserByIds")
public Integer[] delUserByIds(Integer[] ids){
return userService.delUserByIds(ids);
}
}
- UserService
public interface UserService {
User getUserByUserId(Integer id);
User delUserById(Integer id);
User updateUser(User user);
List addUser(List<User> userList);
Integer[] delUserByIds(Integer[] ids);
}
- UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Override
public User getUserByUserId(Integer id) {
return new User(id, "ljx-1", 18);
}
@Override
public User delUserById(Integer id) {
return new User(0-id, "ljx", -18);
}
@Override
public User updateUser(User user) {
return user;
}
@Override
public List<User> addUser(List<User> userList) {
return userList;
}
@Override
public Integer[] delUserByIds(Integer[] ids) {
return ids;
}
}
2.5 feign优化
1. 开启feign日志
feign: client: config: # default: # 所有服务都生效 feign-provider: #指定服务生效 loggerLevel: full # 输出feign远程调用的详细信息 logging: level: com.sanjin.feign: debug
2. http连接池
仅需添加依赖即可
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
效果图:
3.GZIP 压缩
server:
port: 80
compression:
enabled: true #开启浏览器<---->consumer的gzip压缩
feign:
compression: #开启feign<---->provider的gzip压缩
request:
enabled: true
response:
enabled: true
效果图:
4. feign超时
注意:当开启feign日志后,feign调用的时间会被延长,在一定时间内不会超时。
方式一:
ribbon:
ConnectionTimeout: 5000 #请求连接的超时时候
ReadTimeout: 5000 #请求响应的超时时间
方式二:
feign:
client:
config:
#default:
feign-provider:
ConnectionTimeout: 5000 #请求连接的超时时候
ReadTimeout: 5000 #请求响应的超时时间