目录
[1.1 Ribbon简介](#1.1 Ribbon简介)
[1.2 Ribbon负载均衡](#1.2 Ribbon负载均衡)
[1.3 服务调用和Ribbon负载均衡实现](#1.3 服务调用和Ribbon负载均衡实现)
1、Ribbon
1.1 Ribbon简介
Ribbon是一个用于客户端负载均衡的组件,它是Netflix开源的一个项目。在微服务架构中,系统会拆分为多个小型的服务,每个服务都有自己独立的服务器实例。Ribbon所具有的特点:客户端负载均衡,将请求发送到多个服务实例中的一个。多种负载均衡算法:Ribbon支持多种负载均衡算法,如轮询、随机、权重等,可以根据应用的需求选择适合的算法。服务实例自动发现:Ribbon可以与服务注册中心集成,自动发现可用的服务实例。容错和重试机制:如果某个服务实例不可用,Ribbon会自动选择另一个可用的实例进行请求,提高系统的容错能力。
1.2 Ribbon负载均衡
负载均衡原理
服务提供者order-service通过发起请求localhost:8080/order/101远程调用http://user-service/user/1分别轮询转发到服务消费者user-service和user-service1。
//继承客户端请求的负载均衡拦截器
LoadBalancerInterceptor implements ClientHttpRequestInterceptor
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI(); //服务的路径
String serviceName = originalUri.getHost(); // 不同路径的服务名
Assert.state(serviceName != null,
"Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName, // 处理不同服务执行路径
this.requestFactory.createRequest(request, body, execution));
}
//从服务列表中选择一个去执行
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint)
throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer, hint);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server,
isSecure(server, serviceId),
serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId, ribbonServer, request);
}
负载均衡策略
|---------------------------|----------|-------------------------------------------|
| 实现类 | 名称 | 解释 |
| RoundRobinRule | 轮询策略 | 按照轮询的方式选择可用的服务实例,依次轮流分发请求。 |
| RandomRule | 随机策略 | 随机选择可用的服务实例来处理请求。 |
| WeightedResponseTimeRule | 加权响应时间策略 | 根据每个服务实例的响应时间和权重,来计算一个权重值,选择权重值较小的实例处理请求。 |
| RetryRule | 重试策略 | 在选择可用的服务实例时,会在一定次数内进行重试,以提高容错能力。 |
| BestAvailableRule | 最低并发策略 | 会先过滤出并发连接数量最低的服务实例,然后从中选择一个处理请求。 |
| AvailabilityFilteringRule | 可用性过滤策略 | 首先排除因故障而被标记为不可用的服务实例,然后按照轮询的方式选择可用的服务实例。 |
| ZoneAvoidanceRule | 区域感知策略 | Ribbon会根据服务实例所在的区域以及区域的可用性来选择服务实例。 |
Ribbon和Nginx的区别
架构上:Ribbon是一个客户端负载均衡组件,它通常与服务调用客户端集成在一起,通过轮询、随机等算法选择可用的服务实例。而Nginx是一个独立的反向代理服务器,用于将客户端请求转发给后端服务器。
协议上:Ribbon主要用于HTTP、TCP等通信协议的负载均衡,适用于微服务架构中的服务调用。而Nginx支持更多的协议,如HTTP、HTTPS、SMTP、POP3等,可以用于多场景的负载均衡和反向代理。
功能上:Ribbon提供了更灵活的负载均衡策略、重试机制、服务健康检查等功能,且可以与Spring Cloud等技术栈集成,方便在微服务架构中使用。而Nginx不仅具有负载均衡和反向代理的功能,还支持缓存、gzip压缩、SSL/TLS加密等高级特性。
部署管理上:Ribbon通常作为客户端的一部分集成在应用程序中,可以在应用中灵活配置和管理,适合分布式部署。而Nginx是独立的服务器软件,需要单独部署和配置,可以集中管理多个应用的负载均衡配置。
1.3 服务调用和Ribbon负载均衡实现
Ribbon依赖于spring-cloud-starter-netflix-eureka-client包
- 自定义创建远程调用对象
java
/**
* 远程调用和负载均衡
* @return
*/
@LoadBalanced
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
controller发出的请求完成调用并进行负载均衡默认的轮询负载均衡
java
//远程调用
User user = restTemplate.getForObject("http://user-service/user/" + order.getUserId(), User.class);
自定义负载均衡策略对象
java
/**
* 自定义负载均衡策略
*/
@Bean
public IRule randomRule(){
return new RandomRule();
}
application.yml配置负载均衡策略
XML
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
ribbon:
eager-load:
enabled: true
clients: userservice # 饥饿加载
以上是Ribbon完成的负载均衡调用远程微服务。
2、Feign&openFeign
Feign是一个受Retrofit、JAXRS-2.0和WebSocket启发的Java到HTTP客户端绑定。是声明式客户端,通过发送Rest接口进行请求。为了维护请求参数,让编程规范更统一使代码更有可读性。
-
pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
主启动类OrderApplication
加上@EnableFeignClients开启了远程调用。
java
@EnableFeignClients
@MapperScan("com.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
-
自定义Feign客户端接口
@FeignClient("userservice")
public interface UserClient {@GetMapping("/user/{id}") User findById(@PathVariable("id") Long id);
}
controller接口注入UserClient接口并使用Feign发出http的Get请求查询用户。
java
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
Order order = orderService.queryOrderById(orderId);
//远程调用
// User user = restTemplate.getForObject("http://user-service/user/" + order.getUserId(), User.class);
//使用Feign发起http请求,查询用户
User user = userClient.findById(order.getUserId());
order.setUser(user);
return order;
}
这样代码优雅的可读性,成功调用并实现负载均衡~
3、Feign支持的配置
日志功能
日志级别:
BASIC:仅记录请求的方法,URL以及响应状态码和执行时间。
FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
HEADERS:记录请求的方法,URL以及响应状态码和执行时间,额外记录了请求和响应的头信息。
NONE:默认值,不记录任何日志信息。
自定义config/DefaultFeignConfiguration日志级别的配置类
java
@Configuration
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.FULL; //日志级别
}
}
局部定义在远程接口上:
java
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration.class)
全局定义主启动类上:
java
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
application.yml
java
feign:
client:
config: default # 某个微服务userservice设置的日志, default全局日志
loggerLevel: FULL # 日志级别
后台打印日志级别FULL效果:
连接池
- pom.xml
java
<!-- httpclient -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
- application.yml
java
feign:
httpclient: # 连接池
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数,默认200
max-connections-per-route: 50 # 每个路径的最大连接数, 默认 50
feign底层通过httpClient进行负载均衡的过程:
feign-api远程包
- 新建feign-api模块
- pom.xml
java
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
指定feign扫描服务包
java
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class, basePackages = "com.itcast.feign.client")
指定feign加载client服务接口
java
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class, clients = {UserClient.class})