一、nacos服务的集群
首先我们要了解到 微服务就是将一个项目中的多个模块拆分成一个个的子项目 子项目在nacos中注册这么一个微服务 方便微服务对所有模块进行管理和相互之间的调用
那么好 一些大公司大厂的项目 就拿黑马课程上的项目举例子 user模块和order模块 如果我只是分别为他们注册一个微服务 服务器的地点放在我的老家江西赣州 那我的所有用户对我的项目进行访问 如果是江西的还好 因为服务器地点就在赣州 访问速度很快 那好如果这时候有个巴西外国友人来访问 服务器距离这么远 访问速度也就慢 而且 如果只有一个服务器的话 在应对高并发的问题时 不管是多nb的服务器也要崩溃 所以大公司大厂通常在 不同的地点 设置多个服务器 这样就解决了这两个问题 那好 同一个地方的多个服务器 就叫做nacos的地域集群
不知道大家有没有玩过永劫无间 游戏里就有很多节点 北京节点 杭州节点 成都节点 广州节点 其实道理是类似的 为什么要设置这些节点 就是 为了平衡游戏玩家的网络延迟 如果只有一个杭州节点 那么住杭州的人打游戏是不是就比住新疆的人打游戏流畅呢 这就违背了游戏的公平
让我们回归代码
我们现在user模块中的yml文件中添加集群
然后userapplication 在nacos平台上查看userservice的详情
集群这块 从一开始 defalut变成了我们自己定义的名字 我这里是BJ
让我们修改一下user模块的yml文件 换一个集群名字 换成NC 然后复制两个userapplication实例 修改端口号 分别为8082 8083
添加好两个不同端口号的实例后分别启动
我们发现 三个user服务 8081和8082在NC集群 8083在BJ集群 这是不是就实现了上面结构图中所描述的呢
诶 其实还差一步 细心的网友可能要问 那你的集群里就只有user服务吗 order服务呢
还是一样 在order模块的yml文件中如上图一样配置集群名字后 order也在BJ集群里了
二、负载均衡
什么是负载均衡呢 假设现在有两个集群 南昌集群和北京集群 分别都有一个user服务和order服务 让南昌周围的用户使用南昌集群的服务 让北京周围的用户使用北京集群的服务 这其实就是负载均衡的一种
负载均衡不止上面的例子那么简单 有时候考虑到服务器体量 能力大小各不相同 还有上述的地域问题 这就产生了很多负载均衡的算法 黑马的课程中让我们实现 优先调用相同集群的服务 的功能 就是说 北京的order优先调用北京的user
在nacos1.x的版本中呢 nacos discovery的依赖包里已经为我们写好了这种同集群优先的算法 我们只需要在yml文件中引入就可以了
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
在上面的代码中 userservice表示了 当模块在调用在nacos上注册过名为userservice的服务时 采用下面写好的算法的负载均衡策略
这里有一个问题 那就是21年黑马的课程中 使用的版本是1.x的 我的nacos是2.x的 所以我发现这样并没用
问题1:在网上找 有评论说是因为nacos2.x的ribbon的负载均衡策略中没有同集群优先了
问题2:在笔记一中 在order的service层中 把端口号写死了 导致只有8081端口的user服务呗调用
所以我是没有成功体现出负载均衡 问题二肯定是直接原因 但如果要改 黑马的课程中也没有体现 课程中 在yml文件中加上配置 就可以实现了 并没有对这块的代码有修改 然后视频中的同集群优先的负载均衡也确实实现了
!!!!!!!!大家是不是以为这篇笔记就要到此为止了
nonono
于是我打开了黑马最新的微服务课程 24年的版本 直接跳到nacos的部分研究了一下发现 24年的版本没有讲这种区域集群 而是直接引入负载均衡 下面就是实现过程
首先还是一样 项目中必须引入nacos的discovery的依赖
然后在queryOrderById方法中修改写死的端口号 既然2.x的版本没有现成的算法用 那我们就自己写嘛
负载均衡有两种最基础的策略 一种是随机策略 一种是轮询策略
随机好理解 轮询呢就是遍历循环的意思 我们先来写随机
@Autowired
private DiscoveryClient discoveryClient;
首先注入一个discoveryClient类的变量 这个变量有个方法可以让我们获取 在nacos上注册过的服务 你只需要提供这个服务的名字 他能将所有这个名字 不同端口号的不同实例化服务打包给你
既然不止一个的话 是不是需要用java很方便的list集合接收一下
List<ServiceInstance> instances = discoveryClient.getInstances("userservice");
到这里 大家有思路了吗 随机随机 生成个随机数再用list的get不就好了吗
if (!instances.isEmpty()) {
ServiceInstance serviceInstance = instances.get(RandomUtils.nextInt(instances.size()));
String url = "http://localhost:" + serviceInstance.getPort() + "/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
order.setPort(serviceInstance.getPort());
}
代码如上 需要注意的是 这个最外层的if是为了防止instances中为空 随机数的取值范围应从0-list集合的最大下标 也就是在list.size()+1中个实例中随便选一个
到此 恭喜大家已经手敲了一个负载均衡算法!!! 简历上可以写 精通负载均衡了
这是24年黑马课程中写的随机负载均衡 我本人觉得轮询也没问题 就尝试着写了一下
轮询就是遍历 再重头来循环 假设现在有三个端口的实例 80 81 82 轮询的策略就是 这次80 下次81 下下次82 下下下次又回到80 了解了需求原理 思路是不是也一下子打开了
我们可以定义一个变量index作为指针记录 当前集合下标 先赋值0 每获取一个实例的时候
index++ 然后对index++用实例的数量取模
回到上面的例子 80的下标是0 以此类推 当用到82的时候 index为 2+1=3 然后3%3=0 又回到了80
if(!instances.isEmpty()){
ServiceInstance serviceInstance=instances.get(serviceIndex);
serviceIndex=(serviceIndex+1)%instances.size();
String url = "http://localhost:" + serviceInstance.getPort() + "/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
order.setPort(serviceInstance.getPort());
}
到这里 轮询负载均衡完成了
为了方便测试 我在order类中加了一个port的属性 用来记录当前调用的user服务的端口号
接着在浏览器中查询订单
不断刷新 你会发现端口号要么是递增 要么是递减的 这取决于list中是由大到小还是由小到大
然后到极值时 又会从头开始 说明成功