provider 集群和负载均衡 ribbon
上一篇:Feign 的日志
下一篇:使用zuul 构建微服务网关
provider集群。
我用的是第二种启动方式 。修改application.yml配置文件,还是用—隔开把文件中不同的隔开如下所示:
#当前项目启动端口
#server:
# port: 8000
#连接数据库的信息
# generate-ddl: false 取消让它自动见数据库
# show-sql: true展示sql
spring:
jpa:
generate-ddl: false
show-sql: true
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/cloud?useUnicode=true&characterEncoding=UTF-8&useSSL=true
driver-class-name: com.mysql.jdbc.Driver
#当前启动的名字
profiles:
active: provider2
# application:
# name: springcloud-provider
info:
head: head
body: body
app:
name: @project.artifactId@
encoding: @project.build.sourceEncoding@
java:
source: @java.version@
target: @java.version@
management:
endpoints:
web:
exposure:
#加载所有的端点,默认只加载了info、health
include: '*'
endpoint:
health:
show-details: always
#可以关闭指定的端点
shutdown:
enabled: false
eureka:
client:
service-url:
defaultZone: http://root:root@peer1:8761/eureka/,http://root:root@peer2:8762/eureka/
instance:
prefer-ip-address: true
# virtual-host-name: provider
---
spring:
profiles: provider1
application:
name: provider
server:
port: 8000
---
spring:
profiles: provider2
application:
name: provider
server:
port: 8001
启动好之后
测试提供者是否正常提供服务
http://localhost:8000/user/2
http://localhost:8001/user/2
是不是注册到服务发现组件上面去了,如图所示
负载均衡 ribbon
来一个请求,将请求分配到对应的服务消费者来一个请求,判断一下,交给哪一个提供者获取数据,返回数据?
1 jar包,已经在eureka-client中引入。
2 在启动主类上的restTemplate添加 @LoadBalanced注解
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudConsumerApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(SpringcloudConsumerApplication.class, args);
}
}
修改消费者的访问路径,provider做好集群后配置文件变了,只能通过提供者的应用名字(也叫serviceId)来访问了也就是提供者的如图所示:
修改消费者UserController的中的路径如下所示:
@RequestMapping("/user/{id}")
public User findUserById(@PathVariable("id") Integer id){
//消费者,调用生产者
// User user = restTemplate.getForObject(userServiceUrl+id,User.class);
User user = restTemplate.getForObject("http://provider/"+id,User.class);
return user;
}
测试消费者访问提供者
如下访问了四次:两个提供者各调用两次
默认的负载均衡是轮询(为了更直观一点我把控制台清空了)。跟dubbo的默认的随机不一样。
负载均衡算法种类
Ribbon的核心组件是IRule,是所有负载均衡算法的父接口,其子类有:
RoundRobinRule 轮询
RandomRule 随机
AvailabilityFilteringRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数超过阈值的服务,然后对剩余的服务列表进行轮询
WeightedResponseTimeRule 权重 根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时,如果统计信息不足,则使用轮询策略,等信息足够,切换到WeightedResponseTimeRule
RetryRule 重试 先按照轮询策略获取服务,如果获取失败则在指定时间内重试,获取可用服务
BestAvailableRule 选过滤掉多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
ZoneAvoidanceRule 符合判断server所在区域的性能和server的可用性选择服务
自定义配置负载均衡算法
有两种方式
一、 JAVA配置
配置很简单
public class SpringcloudConsumerApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
/**自定义配置ribbon负载均衡算法
* @return
*/
@Bean
public IRule myRule(){
// return new RoundRobinRule();//轮询
return new RandomRule();
// return new RetryRule();//重试
// return new BestAvailableRule();
}
public static void main(String[] args) {
SpringApplication.run(SpringcloudConsumerApplication.class, args);
}
}
(随机)提供者的控制台输入的结果如下:
访问了八次
其他的就一一列举了。
具体业务需求选择合适的算法即可,当然可以根据具体业务需求自己写一个算法类。
使用配置文件实现负载均衡策略
二、属性配置
在消费者项目中的配置文件中添加
#指定负载均衡策略
springcloud-consumer:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
ribbon配置优先级:Ribbon配置的优先级:属性配置 > JAVA配置
java配置
属性配置
如下所示遵循轮询:
Ribbon配置大致完成了。
日志输出
在消费者项目的controller层使用日志。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RestController
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(User.class);
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private UserFeignClient userFeignClient;
@Autowired
private RestTemplate restTemplate;
@Value("${user.userServiceUrl}")
private String userServiceUrl;
@RequestMapping("user/{id}")
public User findById(@PathVariable("id") Integer id){
return restTemplate.getForObject("http://provider/user/"+id, User.class);
// return restTemplate.getForObject(userServiceUrl+id,User.class);
}
@GetMapping("/log")
public void logUserInstance(){
//虚拟主机名
ServiceInstance serviceInstance = this.loadBalancerClient.choose("provider");
this.logger.info("{}:{}:{}", serviceInstance.getInstanceId(),serviceInstance.getHost(),serviceInstance.getPort(),serviceInstance.getInstanceId());
}
}
测试:
看访问的时候访问那个提供者那个提供者就会打印访问了那个端口主机地址之类的。