原文再续,书接上回,上一个博客讲了怎么用Eureka,这次来讲一下怎么用Ribbon做负载均衡。
直接进入正题,基于上两次的微服务,我们做一些简单的改动就可以使用Ribbon实现负载均衡,首先要在microservicecloud-consumer-dept模块中引入Ribbon相关依赖,在pom.xml中添加如下内容:
<!-- Ribbon配置(需要依赖于eureka) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
然后修改application.yml文件,修改后如下:
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka1:6006/eureka,http://eureka2:6007/eureka,http://eureka3:6008/eureka
之后在ConfigBean中添加@LoadBalanced注解:
package com.sunsy.springcloud.configuration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
把DeptConsumerController中的private static final String REST_URL_PREFFIX="http://localhost:8001"替换成
private static final String REST_URL_PREFFIX="http://MICROSERVICECLOUD-DEPT"。
在主启动类添加@EnableEurekaClient注解,至此对Consumer子工程的改造就初步完成了。
接下来新建一个新的数据库clouddb02,里边一样建一个dept表,表结构也一样,只是数据不一样。
接下来新建一个子工程microservicecloud-provider-dep1,把microservicecloud-provider-dept里的内容复制到新建的工程里,修改一下新建工程的application.yml,如下(和原版的只有三点不同:1.port;2.datasource.url;3.instance-id):
server:
port: 8002
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml
type-aliases-package: com.sunsy.springcloud.entity
mapper-locations: classpath:mybatis/mapper/**/*.xml
spring:
application:
name: microservicecloud-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloudDb02
username: root
password: 413531
eureka:
client:
service-url:
#defaultZone: http://192.168.44.63:6006/eureka
defaultZone: http://eureka1:6006/eureka,http://eureka2:6007/eureka,http://eureka3:6008/eureka
instance:
instance-id: dept-provider-8002 #自己命名instance-id,替代默认值
prefer-ip-address: true #把鼠标放在status上时会在浏览器的左下角显示真实的IP和端口号
至此就大功告成了。启动我们所有的微服务(三个EurekaServer、两个Provider、一个Consumer),之后访问http://127.0.0.1:80/consumer/dept/list,可以得到正确的json数据,刷新一下发现json数据变成了另一个数据库的数据,再刷新又变回来,再刷新再变......(也就是Ribbon默认的负载均衡策略:轮询)。
那么我们怎么修改负载均衡策略呢?Ribbon里有几个已经实现的策略,比如轮询,比如随机,我们也可以自己写负载策略,下面说一下怎么搞。
在Consumer子工程的com.sunsy.springcloud.configuration包下新建类ReluConfig.java,内容如下:
package com.sunsy.springcloud.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.loadbalancer.IRule;
import com.sunsy.springcloud.relu.OwnRelu;
@Configuration
public class ReluConfig {
@Bean
public IRule ownRule() {
return new OwnRelu();
}
}
return new OwnRelu()里的OwnRelu类就是我们自己定义的方法(你也可以改成return new RandomRule(),这个RandomRule方法是Ribbon自己提供的,即随机负载均衡策略,就不多说了)。接下来新建一个包com.sunsy.springcloud.relu,在其下新建OwnRelu.java(模仿一下Ribbon自带的RandomRule类写一下自己的策略),如下:
package com.sunsy.springcloud.relu;
import java.util.List;
import java.util.Random;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
public class OwnRelu extends AbstractLoadBalancerRule {
Random rand;
public OwnRelu() {
rand = new Random();
}
private int repeatValue = 0;
private int currentIndex = 0;
/**
* Randomly choose from all living servers
*/
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
if(repeatValue<5 && currentIndex==0) {
server = upList.get(currentIndex);
repeatValue++;
}else {
repeatValue=0;
currentIndex++;
if(currentIndex>=upList.size()) {
currentIndex=0;
}
server = upList.get(currentIndex);
}
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
我们自己写的这个策略可以第一次调用provider1,然后连续调用6次,再调用provider一次,再调用provider1六次,再调用provider一次...可以重启服务访问http://127.0.0.1/consumer/dept/list验证一下是不是这样。
如果想细化不同的微服务有不同的策略的话,可以在consumer的主启动类上添加注解@RibbonClient(name="MICROSERVICECLOUD-DEPT", configuration=ReluConfig.class)
里面的name就是微服务的名字,configuration就是要使用的策略(不过这个东西我没验证,我电脑不支持我再写俩微服务了)
至此Ribbon的使用示例就演示结束了,想看源码的可以去我的git上看:https://github.com/ssystc/springcloud-demo。每次的博客我都会提交一个版本,可以根据commit信息找到对应的版本去看。
下次应该会说一下feign的使用,谢谢支持点赞。。。溜了溜了