何为负载均衡(Load Balance)
其实我也不太了解,先贴一段百度的回答
负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。
通过某种负载分担技术,将外部发送来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。均衡负载能够平均分配客户请求到服务器列阵,借此提供快速获取重要数据,解决大量并发访问服务问题;
然后我大白话说一下吧,其实在字面意思上也好理解,就是对服务负载的均衡处理,比如我们去KFC吃肯德基,肯定会选择离家近的吧(Cluster优先的均衡),有三个窗口,只有中间排队的人很少,正常人都会选择中间吧(最少连接算法),如果三个窗口人数差不多,那我们肯定会随机选择一个窗口(随机算法)
负载均衡算法
上面大概说了一下负载均衡的概念,下面说一下负载均衡的常用算法吧
- 随机算法:负载均衡方法随机的把负载分配到各个可用的服务器上,通过随机数生成算法选取一个服务器,然后把连接发送给它。
- 轮询算法:轮询算法按顺序把每个新的连接请求分配给下一个服务器,最终把所有请求平分给所有的服务器。
- 加权轮询算法:该算法中,每个机器接受的连接数量是按权重比例分配的。
- 动态轮询算法:类似于加权轮询,但是,权重值基于对各个服务器的持续监控,并且不断更新。
- 最快算法:最快算法基于所有服务器中的最快响应时间分配连接。
- 最少连接:系统把新连接分配给当前连接数目最少的服务器。该算法在各个服务器运算能力基本相似的环境中非常有效。
- 观察算法:该算法同时利用最小连接算法和最快算法来实施负载均衡。
- 预判算法:该算法使用观察算法来计算分数,但是预判算法会分析分数的变化趋势来判断某台服务器的性能正在改善还是降低。具有改善趋势的服务器会得到更多的连接。该算法适用于大多数环境
负载均衡的分类
负载均衡按照不同的分类方式有不同的分发,比如根据实现技术不同,可分为DNS负载均衡,HTTP负载均衡,IP负载均衡,链路层负载均衡等,我们按照实现方式的不同分类
- 服务器端负载均衡
比如我们写单体应用时的Nginx等 - 客户端侧负载均衡
本文主角Ribon
实现简单的负载均衡器
上面说了太多的理论知识,现在动手写一个简单的负载均衡吧
动代码之前先说一下要实现的功能
现在又两个为服务,一个是用户模块,服务名称是user-center,一个是内容中心content -center,内容中心有一个接口需要用户中心的用户昵称,所以使用RestTemplate调用,从下面的代码其实是可以看出要实现的具体功能的
/**
* @author luohuiqi
* @Description:
* @Date: 2019/7/2 16:37
*/
@Slf4j
@Service
public class ShareService {
@Autowired(required = false)
private ShareMapper shareMapper;
@Autowired(required = false)
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
public ShareDTO findById(Integer id) {
// 获取分享详情
Share share = shareMapper.selectByPrimaryKey(id);
// 获取服务名称为user-center的所有实例以及url
List<ServiceInstance> instances = discoveryClient.getInstances("user-center");
List<String> targetURLS = instances.stream()
.map(instance -> instance.getUri().toString() + "/users/{id}")
.collect(Collectors.toList());
// 随机取一个url --实现随机算法
int i = ThreadLocalRandom.current().nextInt(targetURLS.size());
UserDTO userDTO = this.restTemplate.getForObject(
targetURLS.get(i),
UserDTO.class,
share.getUserId()
);
// 消息装配
ShareDTO shareDTO = new ShareDTO();
BeanUtils.copyProperties(share,shareDTO);
shareDTO.setWxNickname(userDTO.getWxNickname());
return shareDTO;
}
}
上文就实现了用随机算法实现了负载均衡
使用Ribbon实现负载均衡
What Ribbon ?
Ribbon是Netflix开源的服务端测负载均衡器
其实Ribbon简化版就相当于下面一段代码,它底层有很多不同的负载均衡算法而已
// 获取服务名称为user-center的所有实例以及url
List<ServiceInstance> instances = discoveryClient.getInstances("user-center");
List<String> targetURLS = instances.stream()
.map(instance -> instance.getUri().toString() + "/users/{id}")
.collect(Collectors.toList());
// 随机取一个url --实现随机算法
int i = ThreadLocalRandom.current().nextInt(targetURLS.size());
How to play Ribbon
编写服务
1.写依赖
如图所示在nocas-discovery中Ribbon已存在,故无需添加
2.加注解
@MapperScan("com.itmuch")
@SpringBootApplication
public class ContentCenterApplication {
public static void main(String[] args) {
SpringApplication.run(ContentCenterApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
由于是resTemplate调用服务,所以为其整合Ribbon
3.写配置
没有配置
4.整合代码
所以以上那一串的代码就没用了
/**
* @author luohuiqi
* @Description:
* @Date: 2019/7/2 16:37
*/
@Slf4j
@Service
public class ShareService {
@Autowired(required = false)
private ShareMapper shareMapper;
@Autowired(required = false)
private RestTemplate restTemplate;
public ShareDTO findById(Integer id) {
// 获取分享详情
Share share = shareMapper.selectByPrimaryKey(id);
UserDTO userDTO = this.restTemplate.getForObject(
"http://user-center/users/{userId}",
UserDTO.class,
share.getUserId()
);
// 消息装配
ShareDTO shareDTO = new ShareDTO();
BeanUtils.copyProperties(share,shareDTO);
shareDTO.setWxNickname(userDTO.getWxNickname());
return shareDTO;
}
}
5.启动服务
- 先启动user-center,端口号分别为8089,8087,8086的三个实例
- 然后启动客户端content -center,并访问
我访问了9次,每个实例各被访问三次,看来Ribbon默认应该是用轮循算法
Nacos里的服务为
现在我们的架构图为:
首先三个服务提供者和Ribbon实例注册进Nacos,然后Ribbon就可以直接根据服务名称去调用,以实现负载均衡算法
试着比较这两者的不同
Share share = shareMapper.selectByPrimaryKey(id);
UserDTO userDTO = this.restTemplate.getForObject(
"http://localhost:8086/users/{id}",
UserDTO.class,
);
*******************************************************************************************************
Share share = shareMapper.selectByPrimaryKey(id);
UserDTO userDTO = this.restTemplate.getForObject(
// 注册进Nacos内就可以直接通过服务名称来找到琪实例了,之后实现负载均衡算法
"http://user-center/users/{userId}",
UserDTO.class,
);