源码地址:https://pan.baidu.com/s/1Hmvh1Bbss_Z1w1I7I1mwDw 提取码:e41h
由于微服务数量繁多,一个服务一台服务器显然不够安全,必须配置集群以实现高可用。既然一个服务有多台服务器,那地址、端口也将不同,那么该如何调用服务?服务调用又有哪些策略呢?
下面来看看负载均衡组件 Ribbon 是如何实现的吧。
一、创建一个 servcieA2 服务
这个服务工程与之前的 serviceA1 服务工程一样,只要改一下端口即可,我这里是用的 7072 端口。服务名同 serviceA1 服务工程,都命名为 serviceA。
二、Ribbon + RestTemplate
要使用负载均衡,我们需要在 service-rest 服务加一些东西。
1. pom.xml 文件中加入 Ribbon 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
2. 记得把 service 类中的方法调用改为用服务名调用,因为用主机+端口是调用了一个指定的服务,而用服务名是指定了一个服务的集群。
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ServiceRestService {
@Autowired
private RestTemplate restTemplate;
@SuppressWarnings("unchecked")
public List<String> getServiceA(){
return restTemplate.getForObject("http://serviceA/getList", List.class);
// return restTemplate.getForEntity("http://localhost:7071/getList", List.class).getBody();
}
}
3. 启动类的 restTemplate() 中加入 @LoadBalanced 注解。到这里,就加入了负载均衡功能,负载均衡策略是默认的轮询机制。
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
4. 使用自带的其他负载均衡策略。新建一个 BalanceRule 类,如下:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
@Configuration
public class BalanceRule {
@Bean
public IRule myRule(){
//return new RoundRobinRule();//轮询
//return new RetryRule();//重试
return new RandomRule(); // 随机
//return new DefineRule(); // 自定义策略
}
/* // 同一应用范围不能有多种策略,会报错
@Bean
public IRule myRule2(){
return new RoundRobinRule();//轮询
}
*/
}
Ribbon 已经定义了 7 中负载均衡策略,可直接使用。
策略名 | 策略声明 | 策略描述 |
---|---|---|
BestAvailableRule | public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule | 选择一个最小的并发请求的server |
AvailabilityFilteringRule | public class AvailabilityFilteringRule extends PredicateBasedRule | 过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) |
WeightedResponseTimeRule | public class WeightedResponseTimeRule extends RoundRobinRule | 根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。 |
RetryRule | public class RetryRule extends AbstractLoadBalancerRule | 对选定的负载均衡策略机上重试机制。 |
RoundRobinRule | public class RoundRobinRule extends AbstractLoadBalancerRule | roundRobin方式轮询选择server |
RandomRule | public class RandomRule extends AbstractLoadBalancerRule | 随机选择一个server |
ZoneAvoidanceRule | public class ZoneAvoidanceRule extends PredicateBasedRule | 复合判断server所在区域的性能和server的可用性选择server |
以上总结来自 https://blog.csdn.net/rickiyeat/article/details/64918756
5. 自定义负载均衡策略。新建一个 DefineRule 类
import java.util.List;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
public class DefineRule extends AbstractLoadBalancerRule {
// 每台被调用的次数,当前要求每台被调用3次
private int total = 0;
// 当前提供服务的机器在服务列表的索引
private int currentIndex = 0;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
// 在choose方法中,自定义我们自己的规则,返回的Server就是具体选择出来的服务
// 当前规则:按照轮询的规则,但是每个被轮询到的服务调用3次。
@SuppressWarnings("unused")
@Override
public Server choose(Object o) {
// 获取负载均衡器lb
ILoadBalancer lb = getLoadBalancer();
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) {
return null;
}
// 若调用次数小于3次,一直调用可用服务列表中索引为 currentIndex 的服务
if (total < 3) {
server = upList.get(currentIndex);
total++;
} else {
// 到了3次之后,服务列表中的索引值++,表示下一次调用下一个服务
total = 0;
currentIndex++;
// 当索引大于可用服务列表的size时,要重新从头开始
currentIndex = currentIndex % upList.size();
if (server == null) {
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
server = null;
Thread.yield();
}
}
return server;
}
}
(1)要使用自定义负载均衡策略时,直接在 BalanceRule 类中 return new DefineRule();
即可
(2)也可以在启动类加入注解 @RibbonClient(name="serviceA", configuration=DefineRule.class)
,表示调用 serviceA 服务时使用 DefineRule 自定义负载均衡策略。
(3)可以给其他服务指定不同的负载均衡策略,在启动类加入如下注解:
@RibbonClients(value= {
@RibbonClient(name="serviceA", configuration=DefineRule.class),
@RibbonClient(name="", configuration=xxx.class),
@RibbonClient(name="", configuration=xxx.class)
})
三、Ribbon + Feign
Feign 组件默认集成了 Ribbon 功能,所以引入了 Feign 依赖就可以不引入 Ribbon 依赖了,不过继续引入也不报错。启动类不用另外加注解。
Feign 服务调用使用的负载均衡策略也是默认的轮询机制,当然也可以使用自带的另外 6 种负载均衡策略,也能用自定义的负载均衡策略,用法同 Ribbon + RestTemplate。后面就不赘述了。
博主经验尚浅,也暂无微服务相关项目经验,如果理解不到位甚至理解错误,希望评论区讨论,请多指教!