一、Ribbon在微服务中的作用
1.什么是Ribbon
1.Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它是基于Netflix Ribbon实现的
2.它不像Spring Cloud服务注册中心、配置中心、API网关那样独立部署,但是它几乎存在于每一个Spring Cloud微服务中。包括Feign提供的声明式服务调用也是基于Ribbon实现的。
3.Ribbon提供了多种负载均衡算法,例如:轮询、随机等等。甚至包含自定义的负载均衡算法。
2.Ribbon解决了什么问题
它解决并提供了微服务的负载均衡问题
二、集中式与进程内负载均衡的区别
1.负载均衡解决方案的分类
目前业界主流的负载均衡方案可分为两类:
- 集中式负载均衡:即在consumer和provider中间使用独立的负载均衡设施(可以是硬件,如F5,也可以是软件,如:Nginx),由该设施把访问请求通过某种策略转发到provider
- 进程内负载均衡:将负载均衡的逻辑集成到consumer,consumer从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择一个合适的provider
Ribbon属于后者,它只是一个类库,集成在consumer中,consumer通过它来获得合适的provider地址。
2.两种负载均衡方式架构图
三、Ribbon入门案例
Ribbon对于集群的服务采用的负载均衡的策略默认是轮询
1.Consumer
@Service
public class UserService {
@Autowired
private LoadBalancerClient loadBalancerClient; //ribbon:负载均衡器
public List getUsers(){
//选择调用的服务的名称
//ServiceInstance:封装了服务的基本信息,如:ip、端口号
ServiceInstance si = loadBalancerClient.choose("eureka-provider");
//拼接访问服务的url
StringBuffer sb = new StringBuffer();
//http://localhost:9090/user
sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/user");
System.out.println(sb.toString());
//SpringMVC RestTemplate
RestTemplate restTemplate = new RestTemplate();
ParameterizedTypeReference> type = new ParameterizedTypeReference>() {
};
//ResponseEntity:封装了返回值信息
ResponseEntity> entity = restTemplate.exchange(sb.toString(), HttpMethod.GET, null, type);
return entity.getBody();
}
}
2.Consumer的配置文件
spring.application.name=eureka-consumer
server.port=9091
#设置服务注册中心地址,向所有注册中心做注册
eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/
3.Provider的集群部署
3.1 将Provider打包,部署到linux环境中
3.2 创建启动脚本
#!/bin/bash
cd `dirname $0`
CUR_SHELL_DIR=`pwd`
CUR_SHELL_NAME=`basename ${BASH_SOURCE}`
JAR_NAME="springcloud-eureka-provider-0.0.1-SNAPSHOT.jar"
JAR_PATH=$CUR_SHELL_DIR/$JAR_NAME
#JAVA_MEM_OPTS=" -server -Xms1024m -Xmx1024m -XX:PermSize=128m"
JAVA_MEM_OPTS=""
#SPRING_PROFILES_ACTIV="-Dspring.profiles.active=eureka2"
SPRING_PROFILES_ACTIV=""
LOG_DIR=$CUR_SHELL_DIR/logs
LOG_PATH=$LOG_DIR/${JAR_NAME%..log
echo_help()
{
echo -e "syntax: sh $CUR_SHELL_NAME start|stop"
}
if [ -z $1 ];then
echo_help
exit 1
fi
if [ ! -d "$LOG_DIR" ];then
mkdir "$LOG_DIR"
fi
if [ ! -f "$LOG_PATH" ];then
touch "$LOG_DIR"
fi
if [ "$1" == "start" ];then
# check server
PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
if [ -n "$PIDS" ]; then
echo -e "ERROR: The $JAR_NAME already started and the PID is ${PIDS}."
exit 1
fi
echo "Starting the $JAR_NAME..."
# start
nohup java $JAVA_MEM_OPTS -jar $SPRING_PROFILES_ACTIV $JAR_PATH >> $LOG_PATH 2>&1 &
COUNT=0
while [ $COUNT -lt 1 ]; do
sleep 1
COUNT=`ps --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}' | wc -l`
if [ $COUNT -gt 0 ]; then
break
fi
done
PIDS=`ps --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}'`
echo "${JAR_NAME} Started and the PID is ${PIDS}."
echo "You can check the log file in ${LOG_PATH} for details."
elif [ "$1" == "stop" ];then
PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
if [ -z "$PIDS" ]; then
echo "ERROR:The $JAR_NAME does not started!"
exit 1
fi
echo -e "Stopping the $JAR_NAME..."
for PID in $PIDS; do
kill $PID > /dev/null 2>&1
done
COUNT=0
while [ $COUNT -lt 1 ]; do
sleep 1
COUNT=1
for PID in $PIDS ; do
PID_EXIST=`ps --no-heading -p $PID`
if [ -n "$PID_EXIST" ]; then
COUNT=0
break
fi
done
done
echo -e "${JAR_NAME} Stopped and the PID is ${PIDS}."
else
echo_help
exit 1
fi
4.启动consumer
四、Ribbon常见的负载均衡策略
1.轮询策略(默认):
使用RoundRobinRule
类,轮询策略表示每次都顺序取下一个Provider,比如有5个Provider,第一次取第一个,第二次取第二个,第三次取第三个,以此类推。
2.权重轮询策略:
使用 WeightedResponseTimeRule
类,根据每个Provider的响应时间分配一个权重,响应时间越长权重越小,被选中的可能性就越低。
原理:一开始为轮询策略,并开启一个计时器,每30s收集一次每个provider的平均响应时间,当信息足够时给每个provider添加一个权重,并按权重随机选择,权重越高被选中的几率也就越高。
3.随机策略:
使用RandomRule
类,从provider列表中随机选择一个provider
4.最少并发数策略:
使用BestAvailableRule
,选择正在请求中并发数量小的provider,除非这个provider在熔断中。
5.在选定的“负载均衡策略”基础上进行重试机制
使用RetryRule
类, “选定的负载均衡策略”这个策略是轮询策略 RoundRobinRule
该重试策略先设定一个阈值时间段 ,如果在这个时间段内选择provider不成功,则一直尝试采用“选定的负载均衡策略:轮询策略”最后选择一个可用的provider
6.可用性敏感策略
使用 AvailabilityFilteringRule
类,过滤性能差的provider一共有两种:
第一种:过滤掉Eureka中一直连接失败的provider
第二种:过滤掉高并发的provider
7.区域敏感性策略
使用 ZoneAvoidanceRule
类,
以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下区域中选可用的 provider
如果这个 ip 区域内有一个或多 个实例不可达或响应变慢,都会降低该 ip 区域内其他 ip 被选中的权重。
五、Ribbon指定其他负载均衡策略
1.修改代码更换负载均衡策略
1.1 创建项目
springcloud-eureka-consumer-LB
1.2 在启动类中添加创建负载均衡策略对象的方法
/**
* Author: LuYi
* Date: 2019/11/5 17:32
* Description: 描述
*/
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApplication {
@Bean
public RandomRule createRule() {
return new RandomRule();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
2. 修改配置文件更换负载均衡策略
#设置负载均衡策略 eureka-provider 为调用的服务的名称
eureka-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
六、Ribbon点对点直连
1.创建项目
springcloud-eureka-consumer-direct
2.去掉Eureka的坐标,添加Ribbon坐标
4.0.0
org.springframework.boot
spring-boot-starter-parent
1.5.13.RELEASE
com.luyi
springcloud-eureka-consumer-direct
0.0.1-SNAPSHOT
springcloud-eureka-consumer-direct
Demo project for Spring Boot
1.8
org.springframework.cloud
spring-cloud-dependencies
Dalston.SR5
pom
import
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.cloud
spring-cloud-starter-config
org.springframework.cloud
spring-cloud-starter-ribbon
org.springframework.boot
spring-boot-maven-plugin
3.修改配置文件去掉与Eureka相关的配置,添加新配置项
spring.application.name=eureka-consumer-direct
server.port=9091
#禁用 eureka
ribbon.eureka.enabled=false
#指定具体的服务实例清单
eureka-provider.ribbon.listOfServers=192.168.234.132:9090
4.修改启动类,去掉报错代码
@SpringBootApplication
public class ConsumerApplication {
// @Bean
// public RandomRule createRule() {
// return new RandomRule();
// }
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}