《面向服务的软件系统》实验四:微服务综合实验
《面向服务的软件系统》实验报告
——实验四:微服务综合实验
姓名: 石卓凡 学号: 120L021011
目录
1、 如果你要从头开发一个基于微服务架构的项目,项目中的服务最终要部署在k8s管理的镜像环境中,你认为应如何创建项目?与本次实验过程相比,哪些改进可以让开发更加合理高效? 2
2、 如何将实验中多个provider服务实例的负载均衡策略改为轮询调用?即在多次反复调用时轮流调用各个服务实例。 5
4.1.Api和provider的依赖关系,导致无法打包provider 13
4.2.打包为jar,由于启动类在Test文件夹中无法自动找到启动类 14
4.3.provider打包好的镜像的docker的容器自动退出 16
4.4.docker每次都需要进入虚拟机进行打包镜像,有点麻烦,当虚拟机无法连接到时候,无法进行工作 16
如果你要从头开发一个基于微服务架构的项目,项目中的服务最终要部署在k8s管理的镜像环境中,你认为应如何创建项目?与本次实验过程相比,哪些改进可以让开发更加合理高效?
创建项目
采用以下步骤:
- 明确项目的需求和目标,并确定项目中需要包含哪些微服务。
- 建立项目的架构,设计每个微服务的功能和接口,并确定微服务之间的交互方式。
- 根据项目的架构,分别开发各个微服务。
- 将开发的微服务打包成镜像,上传到镜像仓库。
- 在k8s管理的镜像环境中部署项目,并测试各个微服务的功能和性能。
- 如果发现问题,及时调整项目的架构和代码,并重新部署。
这些步骤中,最重要的是明确项目的需求和目标,并设计合理的架构。这样才能确保项目的可扩展性和可维护性,并且能够顺利地部署在k8s管理的镜像环境中。
以springcloud框架,dockerhub镜像仓库为例的具体步骤及注意事项
- 明确项目需求,确定springcloud最终划分模块数量及每个模块功能
- 构建springcloud项目,分为多个模块。每个模块的端口号要写清楚,方便之后部署暴露对应端口
- 使用maven,在maven写好build标签,给每一个模块一个清晰的打包模块名。且maven中利用好parent和child标签,给整个项目有一个root模块可以对所有模块进行管理,并且将公共依赖放入root的pom文件
- 每个模块写dockerfile,dockerfile中的端口号要一一对应
- 先打包为docker镜像,然后在docker中创建容器,通过容器是否成功运行和是否容器中运行有预期结果来进行判断镜像是否打包成功。
- Docker镜像如果有误,则重新检查代码以及打包过程,如果Docker镜像确定无误后,上传dockerhub
- 在k8s服务器中写好deployment,service,volume等yaml文件,根据需求选定service类型,deployment实例个数,volume种类和容量大小,然后使用yaml文件进行部署微服务项目。
- 测试k8s中部署项目是否无误,如果发现问题,及时调整项目的架构和代码,并重新部署。
改进
- 我会明确每个微服务项目的端口,写明使用到的端口,这样方便后续k8s的部署,在本次实验中的项目中需要暴露端口8888没有明确单独写出来,而是得去配置文件搜寻。改进点就是直接写明需要暴露哪些端口,防止端口不正确带来的问题
- 我会通过maven的root根项目来对所有微服务模块进行maven管理,这样可以同时install和package而不用对每个模块再单独依次打包,且避开了因为父子模块依赖而产生的特定打包顺序问题。
- 将公共依赖放入root的pom文件,这样就避免了子模块之间多个重复依赖
图1.1使用root进行管理整个项目
- 选用jenkins自动化部署,可以简化部署流程,也能够使得整个项目的过程更加合理高效
图1.2使用jenkins的控制台
- 可以把dockerhub仓库改为harbor镜像仓库,如果在企业项目不想放入dockerhub中可以自己搭建私有的harbor镜像仓库,保证了项目的私密性和安全性,更加符合实际情况。
如何将实验中多个provider服务实例的负载均衡策略改为轮询调用?即在多次反复调用时轮流调用各个服务实例。
思路:
负载均衡策略可通过 Host 的IPVS(即 K8s 集群节点的IPVS)来实现的
原理
service底层实现主要由两个网络模式组成:iptables与IPVS。他们都是有kube-proxy维护
图service底层概念图
图service工作流程图
k8s的service默认是采用iptables为网络模式:且iptables默认的负载均衡是random随机策略
使用命令可以查看iptables当前的一些规则
iptables-save
k8s的service可以改为ipvs模式
使用命令可以查看ipvs规则
ipvsadm -L -n
而IPVS的负载均衡方式如下
负载均衡方法 | 描述 |
---|---|
round-robin | 轮询调度是一种以轮询的方式依次将一个域名解析到多个IP 地址的调度不同服务器的计算方法 |
least connection | 最小连接调度(Least-Connection Scheduling)算法是把新的连接请求分配到当前连接数最小的服务器 |
source hash | 源地址哈希法是根据请求来源的地址,通过哈希函数计算得到的一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是客服端要访问服务器的序号。采用源地址哈希法进行负载均衡,同一源地址的请求,当服务器列表不变时,它每次都会映射到同一台服务器进行访问。 |
Random(默认) | 随机算法完成负载均衡 |
… | … |
图查看本实验中的iptable的nat表
则本实验中想要采用轮询调用
大致步骤如下:
- service切换为IPVS网络模式
- 切换IPVS使用轮询的负载均衡策略
- 使用命令在master节点上
kubectl edit configmap kube-proxy -n kube-system
图kubeconfig.conf
- 更改配置
然后发现当前我的服务已经默认为ipvs模式(Mode: ipvs),但是负载均衡模式没有指定(默认为随机random)
之后修改为
scheduler: “rr”
- 重新应用新配置
然后需要让kube-proxy重新应用新的配置,这里采用删除等待其自动重建并且应用新的网络模式。
最后重启之后发现服务实例成功改为了轮询调用rr
图:成功示例
实验过程中遇到的主要问题与解决办法。
1.服务器内存问题
服务器内存太小了,然后我部署的东西太多了,导致我后来部署provider时候一直自动重启pod,
导致dubbo无法持续检测到,我还以为是代码问题改了一下午,结果最后反应过来是内存已经不够了。
并且后续内存不够,会导致服务器无法正常关闭,一直显示关闭中。因此为了以防万一,使用快照是很重要的
解决方法:
- 删除一部分自己的deployment
- 取出master的污点,在加入master分担
- 给服务器扩容
图2.1服务器内存和CPU使用率
2.多次显示provider的同一ip问题
由于默认选用的是负载均衡,所以多次consumer都是直接对应的第一个provider,只有快速多次连续输入请求之后才会跳转其他provider
解决方法:设为轮询访问,或者快速多次输入
3.Dubbo-admin部署问题
3.1.部署最新版Dubbo-admin中的问题
参考官方github链接:
最新的dubbo-admin中已经将tomcat集成在dubbo中不需要额外的tomcat运行,所以最开始尝试新版admin
3.1.1github访问失败
图2.2github访问失败
这个还是因为墙的问题
解决方法:服务器上无法使用VPN梯子,因此我选择直接在服务器上借助hosts查找域名ip
3.1.2无法正常cd进入目标文件夹
发现官网给出的cd地址还需要加入/root前缀,代表用户名
解决方法:加入/root
3.1.3最终新版dubbo-admin成功部署,但是root账户权限出错
图2.4dubbo-admin权限出错
猜测可能是新版的dubbo-admin不兼容之类的问题
最终再多次重新部署仍然无法解决之后,我选择放弃新版dubbo
解决方法:更换回老版本dubbo
3.2.部署旧版dubbo-admin
沿用lab2旧版的dubbo,选用的部署方案是
服务器k8s部署zookeeper+本机启动tomcat来配合生成dubbo-admin
3.2.1.单独修改WEB-INF下的properties配置文件发现没有用
图2.5WEB-INF下的properties
发现仅仅修改这个无法改变tomcat部署中的zookeeper地址
原理:tomcat会自动War包可以放在Tomcat下的webapps或者word目录下,随着tomcat服务器的启动,它可以自动被解压。应该从头开始修改War包
解决方案:从dubbo-master开始修改
图2.6dubbo-master项目
修改dubbo-master中的zookeeper地址
去找原来的
D:\360MoveData\Users\86189\Desktop\Service-orientedtechnology development\lab2\dubbox-master
然后在dubbox项目中把127.0.0.1:2181换成zookeeper://47.92.244.182:32273
重新install
4.部署打包provider中的问题
4.1.Api和provider的依赖关系,导致无法打包provider
之前一直使用的是api的package而没有使用install,导致后续打包provider的时候无法找到api的依赖项
原理:
Maven 的 install 命令和 package 命令都可以用于构建项目,但是它们的作用略有不同。
Maven 的 install 命令会将项目的构建结果(如 jar 包)安装到本地仓库中,以供其它项目使用。例如,如果项目 A 依赖于项目 B,那么在构建项目 B 时,可以使用 Maven 的 install 命令将项目 B 的 jar 包安装到本地仓库中,然后在构建项目 A 时,Maven 会自动从本地仓库中查找并加载项目 B 的 jar 包。
Maven 的 package 命令仅会生成项目的构建结果,但不会将其安装到本地仓库中。例如,如果您使用 Maven 的 package 命令来构建项目 B,那么 Maven 会在项目 B 的 target 目录下生成 jar 包,但不会安装到本地仓库中。如果项目 A 依赖于项目 B,则需要手动将项目 B 的 jar 包复制到项目 A 的依赖路径下,或者使用 Maven 的 install 命令来安装项目 B 的 jar 包。
4.2.打包为jar,由于启动类在Test文件夹中无法自动找到启动类
当时使用了两种解决方案,方案1失败,方案2最终成功
方案1失败
在IDEA的项目结构中导入现有模块,然后指定启动类,然后点击构建工件jar
图2.7.1导入现有模块
图2.7.2构建现有模块
方案2成功
修改pom文件,加入build标签内容
- <build>
- <finalName>provider</finalName><!– 导出jar的名字 –>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <version>2.1.5.RELEASE</version>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>repackage</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <includeSystemScope>true</includeSystemScope>
- <mainClass>ProviderApplication</mainClass>
- </configuration>
- </plugin>
- </plugins>
- </build>
然后使用install最终成功
4.3.provider打包好的镜像的docker的容器自动退出
原理:
因为docker中一旦把镜像中的执行完一遍之后就会自动停止,所以容器则会显示退出或者结束
解决方案:
修改provider和consumer的启动类代码,加入一段死循环代码防止自动完成
图2.8修改的代码
4.4.docker每次都需要进入虚拟机进行打包镜像,有点麻烦,当虚拟机无法连接到时候,无法进行工作
自己的虚拟机在中期突然发生NAT模式无法访问到网络,同时也无法被SSH连接,于是我的虚拟机打包docker镜像的方法失效
解决方案:
安装docker desktop,使用win版的docker
并且利用IDEA集成docker的功能直接在IDEA完成docker镜像的打包以及上传
图2.9windows的docker集成
5.如何在后续查看provider的ip
解决方案:
修改provider和consumer的代码
核心修改处:
- public class UserServiceImpl implements UserService {
- public User getUser(Long id) {
- InetAddress addr = null;
- String add =”404”;
- try {
- addr = InetAddress.getLocalHost();
- add = addr.getHostAddress();
- } catch (UnknownHostException e) {
- e.printStackTrace();
- }
- System.out.println(“add = “ + add);
- return new User(id, “当前ip” + add);
- }
- }
6.端口问题
由于我在服务器中已经部署jenkins启动了8080端口
解决方法:所以我将provider等端口都避开8080端口
对整门实验课程有何意见或建议。
四个实验的设计以及对应的实验指导书的建议
实验内容
- lab1中部分的原理和机制,比如说Apache CXF
因为时间问题可能有些无法适应现在的情况,并且在以后的工作中可能也使用和接触的机会较少。
而且lab1完成之后,对于tomcat的机制或者说如何去使用tomcat,其实整个流程下来收获并不是很大。
我认为比如说lab1换成学习和利用tomcat去发布一个helloworld的war包可能会比较合适,能够让同学们接触到tomcat的一些机制及原理。
以及lab1中的spring+tomcat内容也可以换成springboot,因为现在的大类招生以及通识化教育,软工专业的同学没有很好的JavaWeb基础,在经过lab1之后也未必能了解到spring的内容。我认为如果改为让同学们自行新建一个springboot项目,实现最基础的hello_world或简单的增删改查,收获可能会更大一些。毕竟springboot算比spring更主流,并且更适合入门,尽管科班应该系统性地学习spring,但是可能光凭一次实验或者理论讲解可能有所欠缺
- lab2与lab4内容如果可以的话,我认为可以不用限定dubbo的版本
lab2指导书提供的是老版的dubbo,安装老版的dubbo以及一些配置是比较繁琐且实际性价比个人感觉较低。或许可以换成让同学们自行参考github中的官网教程来安装dubbo,这样既可以跟上新版本进行接轨,并且还能锻炼从官网自学安装配置的能力
实验指导书
lab1,lab2的实验指导书已经有不少因为版本过时问题导致配置出错,实验指导书我认为已经可以定期更新一下,因为很多时候刚入门的同学可能遇上这些问题会花费很多时间去纠结这样一些小问题。
我在想,能不能鼓励每一届同学们根据自己实验后的经验对指导书留下一些修改建议,然后再由助教老师们收集整理,然后根据这些改动去修改实验指导书,这样就能很方便地一届一届不断更新指导书,也以便于下一届同学收到改进后的实验书。
前置知识的问题
因为20届属于大类招生,大一大二对于软工专业课个人感觉太少了,从自己的感受上来看,无论是之前的软件构造还是现在的面向服务的软件系统,如果自己在上课之前没有做过项目或者没有一些基础的Java项目知识springboot等知识,就不能切身体会到一些重点.就个人感受,在自己学习过前后端内容和java之后,写过一些代码之后,再去回看教过的知识,才会发现受益匪浅,而自己在没有学习之前,总是无法理解含义。
比如说本课程在介绍面向服务的架构,淘宝技术的演进这一节课的内容中,结合了自己从JavaWeb,JDBC一直到springcloud的知识感受很深,觉得理清了自己之前学习的思路,相当于对以前学过的知识做了一次彻底总结。但是如果自己之前从来没有接触过这些知识,也许会一头雾水。
因此,我希望能够多加入一些前置知识的内容教学,比如说快速上手springboot,springcloud之类的。除了大作业和实验之外,适当的加入一些代码作业任务也是可以的我感觉。