我们可以仿照实验二中的框架来搭建我们的服务,首先搭建一个Springboot的项目,随后在这个项目中定义我们的接口规范,并且要按照预期的要求编写业务逻辑代码,实现具体的功能;其次我们可以利用Zookeeper和Dubbo来管理我们的服务,将我们的服务注册到Zookeeper服务中心,利用Dubbo的客户端界面来进行管理;最终我们要选择比较稳定的JDK版本和其他类似的配置环境,确保我们的服务可以稳定的运行,确认后利用IDEA集成的功能将整个项目打包成jar包。在这里可以直接在Windows环境下实现,打开CMD输入java -jar +XXX.jar检测是否可以正常运行,若正常运行,Dubbo是否可以检测到。其次要注意,由于要部署到K8S中,我们的Zookeeper的IP地址要将默认的127.0.0.1更改为服务器的IP,否则服务器上部署的Dubbo将无法识别到容器内的服务程序。
我们可以直接通过Dockerfile来将上一步生成的jar包制作成dubbo镜像,随后生成docker镜像后,我们可以使用docker images指令来查看本地是否生成了镜像;如果需要部署到非本地的服务器集群,那么我们需要将镜像打好标签,push到dockerhub上。随后,我们编写yaml文件来对服务进行部署。这里要注意,yaml文件和dockerfile文件中一定要加入java -jar启动指令,同时要规定好服务暴露的端口以及主机的端口,并且要保持统一。做好这些后,我们将这个deployment apply,利用K8S的指令kubectl get pods -a或kubectl describe pods来详细查看镜像的运行状态。有的时候,即便是status显示running,依然可能发生一些问题。我们一定要进入到容器内部,利用describe来检查容器内镜像是否正常启动并持续提供服务。如果这一切处理得当,我们可以在zookeeper下的bin文件夹下,打开zkCli.sh并运行./zkCli.sh。通过输入ls /dubbo/加服务的UserManager/providers即可查看到提供服务的容器的IP,这些IP是相互独立的,与我们在kubectl describe pods看到的是一致的。此时,我们调用消费者,就可以享用来自不同容器的提供者所提供的的服务了;另外,我们可以直接利用K8S技术直接对容器进行管理。
Dubbo官方提供了轮询负载均衡算法,通常是通过“轮询+权重”来进行实现。
算法步骤
1、计算服务提供者的总权重。
2、每个服务提供者除了始终不变的固定权重以外,需要记录服务提供者当前权重。
3、每次请求,更新所有的服务提供者的当前权重,当前权重 = 当前权重 + 固定权重。
4、从上一步得到的结果中,选择一个当前权重最大的服务提供者用于处理请求,如果存在多个,那么就看遍历的过程中先遇到哪个服务提供者就是哪一个。并且,选中的权重最大的服务提供者更新其当前权重 = 当前权重 - 总权重。
举一个例子
三个服务提供者的固定权重分别是10,20,50,假设其当前权重依次为0,0,0
1、计算总权重 10+20+50 = 80
2、当请求来了,更新三个服务提供者的当前权重,当前权重 = 当前权重+固定权重,依次结果为10,20,50.
3、从中选择最大的一个,也就是第三个用于处理请求,同时将其当前权重更新:当前权重 = 50 - 80 = -30
4、所以此时三个服务提供者的当前权重依次为10,20,-30
5、当第二个请求来的时候,更新三个服务提供者的当前权重,当前权重 = 当前权重+固定权重,依次结果为20,40,20
6、从重选择最大的一个,也就是第二个用于处理请求,同时将其当前权重更新:当前权重 = 40 - 80 = -40.
7、依次类推。
如果我们想使用均衡的轮询策略,那么我们只需要将上述的权重设置为均等的正值即可。具体的算法实现如下所示:
先来看一下WeightedRoundRobin对象,一个服务提供者节点,对应一个WeightedRoundRobin对象,该对象记录了服务提供者的权重,当前的权重以及上一次权重更新的时间。
RoundRobinLoadBalance中的doSelect方法如下:
methodWeightMap 方法权重Map用于保存服务方法提供者集群的WeightedRoundRobin对象集合。一个服务方法提供者对应一个WeightedRoundRobin。key是服务提供者的身份信息,value是WeightedRoundRobin对象。
遍历所有的服务提供者,
根据它的身份信息以及服务提供者的权重。
基于身份信息得到WeightedRoundRobin对象,如果没有的话new一个。
若缓存中的WeightedRoundRobin的权重 不等于刚得到的weight,那么就更新WeightedRoundRobin中的weight。
WeightedRoundRobin中的当前权重自增,当前权重 = 当前权重 + 固定权重,并设置更新的时间。记录当前权重最大的节点的信息,并统计总权重。
若服务提供者列表和map的大小不一致,说明有服务提供者挂了,那么根据WeightedRoundRobin中的lastUpdate字段,判断是否存活,移除挂了的服务提供者。对找到的最大的当前权重的服务提供者进行更新当前权重,它的当前权重 = 当前权重 - 总权重。返回最大的服务提供者节点。
此外,还有一种利用计数器取模的方法:
如果所有服务器的该接口方法的权重一样,则直接内部的序列计数器( sequences ) +1 然后对服务器的数量进行取模来决定调用哪个服务器上的服务;如果服务器的该接口方法的权重不一样(就是说存在预热中的服务器),则找到其中最大的权重,然后将内部的权重计数器( weightSequences ) +1 并对该最大权重数取模,然后再找出权重比该取模后的值大服务器列表,最后通过内部的序列计数器( sequences ) +1 然后对服务器列表数量进行取模来决定调用哪个服务器上的服务。
加入插件
启动类不要放在test下,尽量放在源代码目录下
这个问题实际上就是自己的业务逻辑的问题,一旦发现了,不要去思考到底是为什么,
首先尝试加入一些死循环是否可以保持进程的活性。
一般出现这个问题,主要由以下几个原因:
1.容器假running,实际上根本就没有注册上,他一直就没有成为provider。这种情况通常是由于jar包本身无法正常运行所导致,应当立即检查源代码,或者拉取的镜像是不是你的最新版本。
2.容器跑起来了,但是就是找不找。存在两种可能,第一种,你忘记了将zookeeper注册中心的IP更改为服务器IP;第二种,业务逻辑有问题。程序在注册成功后立即终止,running的进程时间99.99%都是在启动,注册上的一瞬间就崩溃了,dubbo甚至来不 及产生任何反应。这时就应该检查业务逻辑了。
我们可以在provider中添加功能,迫使其自动输出所在容器的IP。我们只需利用java自带的网络工具包即可,具体实现逻辑和代码如下图所示: