1.Ribbon是一个基于HTTP和TCP的 客户端负载均衡工具 ,它是基于Netflix Ribbon实现的
2.它不像Spring Cloud服务注册中心、配置中心、API网关那样独立部署,但是它几乎存在于每一个Spring Cloud微服务中。包括Feign提供的声明式服务调用也是基于Ribbon实现的。
3.Ribbon提供了多种 负载均衡 算法,例如:轮询、随机等等。甚至包含自定义的负载均衡算法。
它解决并提供了微服务的 负载均衡 问题
目前业界主流的负载均衡方案可分为两类:
集中式负载均衡:即在consumer和provider中间使用独立的负载均衡设施(可以是硬件,如F5,也可以是软件,如:Nginx),由该设施把访问请求通过某种策略转发到provider
进程内负载均衡:将负载均衡的逻辑集成到consumer,consumer从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择一个合适的provider
Ribbon属于后者,它只是一个类库,集成在consumer中,consumer通过它来获得合适的provider地址。
@Service public class UserService { @Autowired private LoadBalancerClient loadBalancerClient; //ribbon:负载均衡器 public List<User> 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<List<User>> type = new ParameterizedTypeReference<List<User>>() { }; //ResponseEntity:封装了返回值信息 ResponseEntity<List<User>> entity = restTemplate.exchange(sb.toString(), HttpMethod.GET, null, type); return entity.getBody(); } } 复制代码
spring.application.name=eureka-consumer server.port=9091 #设置服务注册中心地址,向所有注册中心做注册 eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8761/eureka/ 复制代码
#!/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 复制代码
使用 RoundRobinRule
类,轮询策略表示每次都顺序取下一个Provider,比如有5个Provider,第一次取第一个,第二次取第二个,第三次取第三个,以此类推。
使用 WeightedResponseTimeRule
类,根据每个Provider的 响应时间 分配一个权重,响应时间越长权重越小,被选中的可能性就越低。
原理:一开始为轮询策略,并开启一个计时器,每30s收集一次每个provider的平均 响应时间 ,当信息足够时给每个provider添加一个权重,并按权重随机选择,权重越高被选中的几率也就越高。
使用 RandomRule
类,从provider列表中 随机选择 一个provider
使用 BestAvailableRule
,选择正在请求中 并发数量小 的provider,除非这个provider在熔断中。
使用 RetryRule
类, “选定的负载均衡策略”这个策略是 轮询策略 RoundRobinRule
该重试策略先设定一个 阈值时间段 ,如果在这个时间段内选择provider不成功,则一直 尝试 采用“选定的负载均衡策略:轮询策略”最后选择一个可用的provider
使用 AvailabilityFilteringRule
类,过滤性能差的provider一共有两种:
第一种:过滤掉Eureka中一直 连接失败 的provider
第二种:过滤掉 高并发 的provider
使用 ZoneAvoidanceRule
类,
以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下区域中选可用的 provider
如果这个 ip 区域内有一个或多 个实例不可达或响应变慢,都 会降低该 ip 区域内其他 ip 被选中的权重 。
springcloud-eureka-consumer-LB
/** * 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); } } 复制代码
#设置负载均衡策略 eureka-provider 为调用的服务的名称 eureka-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule 复制代码
springcloud-eureka-consumer-direct
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.13.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.luyi</groupId> <artifactId>springcloud-eureka-consumer-direct</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springcloud-eureka-consumer-direct</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!--ribbon坐标--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 复制代码
spring.application.name=eureka-consumer-direct server.port=9091 #禁用 eureka ribbon.eureka.enabled=false #指定具体的服务实例清单 eureka-provider.ribbon.listOfServers=192.168.234.132:9090 复制代码
@SpringBootApplication public class ConsumerApplication { // @Bean // public RandomRule createRule() { // return new RandomRule(); // } public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } } 复制代码