服务消费者:
导入依赖:
<!--ribbon依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
application.yml配置文件:
eureka:
client:
register-with-eureka: false #不注册自己
service-url: #随机访问,实现负载均衡
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
启动类:
Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
}
}
configBean:
配置负载均衡,使用注解@LoadBalanced
package com.stt.springcloud.config;
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;
@Configuration
public class ConfigBean {
// 配置负载均衡实现RestTemplate
// IRule 接口
// RoundRobinRule 轮询
// RandomRule 随机
// AvailabilityFilteringRule 会先过滤掉,跳闸,访问故障的服务,对剩下的进行轮询
// RetryRule 会先按照轮询获取服务,如果服务获取失败,则会在指定的时间内进行重试
@Bean
@LoadBalanced // 加上这个注解就实现了负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller:
不使用硬绑定具体的url地址,使用服务名称来访问
// Ribbon,这里地址,应该是一个变量,通过服务名来访问
// private static final String REST_URL_PREFIX = "http://127.0.0.1:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
服务提供者:
创建sprigcloud-provider-dept-8002与sprigcloud-provider-dept-8003:
application.yml配置文件中:服务名不用改,都通过这个名称进行访问。
spring:
application:
name: springcloud-provider-dept
替换默认轮询策略
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced // 加上这个注解就实现了负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@Bean
public IRule myRule(){
// 显示声明要使用的策略(随机算法)
return new RandomRule();
}
}
自定义Ribbon负载均衡算法
启动类添加@RibbonClient注解
@SpringBootApplication
@EnableEurekaClient
// 在启动该微服务的时候就能加载我们自定义的Ribbon配置类,从而使配置生效
// 主要是针对服务名称:MICROSERVICELOUD-DEPT这个服务作得定制负载均衡策略
@RibbonClient(name="服务名称:MICROSERVICELOUD-DEPT", configuration=MySelfRule.class)
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class, args);
}
}
注意:
官方文档明确给出警告:
自定义配置类MySelfRule.class不能放在@ComponentScan所扫描的当前包及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是达不到特殊定制的目的了。
@Configuration
public class MySelfRule{
@Bean
public IRule myRule(){
/*
RandomRuleZDY类内部实现我们自定义的策略
*/
return new RandomRuleZDY();
}
}
RandomRuleZDY.class
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
/*
轮询、随机等策略继承的抽象父类AbstractLoadBalancerRule,
我们同样继承并模仿轮询或其他算法策略源码,定制自己需要的策略
以下根据随机算法策略源码改造,可以每个服务都执行5次
*/
public class RandomRuleZDY extends AbstractLoadBalancerRule{
// total = 0 // 当total==5以后,我们指针才能往下走,
// index = 0 // 当前对外提供服务的服务器地址,
// total需要重新置为零,但是已经达到过一个5次,我们的index = 1
// 分析:我们5次,但是微服务只有8001 8002 8003 三台,OK?
//
private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
private int currentIndex = 0; // 当前提供服务的机器号
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;
}
// int index = rand.nextInt(serverCount);// java.util.Random().nextInt(3);
// server = upList.get(index);
// private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
// private int currentIndex = 0; // 当前提供服务的机器号
if(total < 5)
{
server = upList.get(currentIndex);
total++;
}else {
total = 0;
currentIndex++;
if(currentIndex >= upList.size())
{
currentIndex = 0;
}
}
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)
{
// TODO Auto-generated method stub
}
}