当前位置: 代码迷 >> 综合 >> 微服务的演变以及微服务与微服务之间的通信-----代码示例
  详细解决方案

微服务的演变以及微服务与微服务之间的通信-----代码示例

热度:69   发布时间:2023-09-06 14:23:17.0

接着上一篇博客:

第一步:提供一个服务实例出来:micro-provider(服务提供者),可以单独的去部署到服务器上。

①:建个SpringBoot的项目,需要的依赖如下:
微服务的演变以及微服务与微服务之间的通信-----代码示例
②:配置下mybatis的数据源和相应的驼峰映射:
微服务的演变以及微服务与微服务之间的通信-----代码示例
③:写相应的实体类:
微服务的演变以及微服务与微服务之间的通信-----代码示例
④:写相应的Mapper接口,由于这个mapper是交给Spring容器控制和管理的,所以说在启动类上加一个扫描Mapper接口的注解,然后这个这个接口就会生产接口的代理实现类去交给Spring容器进行管理。
微服务的演变以及微服务与微服务之间的通信-----代码示例微服务的演变以及微服务与微服务之间的通信-----代码示例
⑤:在Mapper接口中写一个根据id查出用户信息的方法:
微服务的演变以及微服务与微服务之间的通信-----代码示例
⑥:由于这个接口要形成映射的,由于现在写的是单表的操作,就不写xml了,直接用注解的方式来进行编写如下:
微服务的演变以及微服务与微服务之间的通信-----代码示例
如果这里用@Autowired的话,它会在Spring容器中会检测是否会有这样的对象动态的已经添加到容器中。这个@Autowired标注的对象不像@Service一样标在类上就能识别。而,在启动类上用的MapperScaner用的注解是在运行的时候才能识别,所以说这里用@Resource注解来注入,@Resource注解不会去找,它相当于使用的是java的东西(import javax.annotation.Resource)。就和Spring不会挂钩,但是它也会去Spring容器中去找。这里会按类型装,不会按名称装。

@Resource注解和@Autowired注解的作用是一样的
微服务的演变以及微服务与微服务之间的通信-----代码示例
⑧:一般我们做项目开发的时候都会为一个实现类提供一个接口
微服务的演变以及微服务与微服务之间的通信-----代码示例
微服务的演变以及微服务与微服务之间的通信-----代码示例
⑨:写个Controller,由于上面的微服务结构图的引出得知,服务提供的API一定是Rest风格的。因为在Spring4.3以后支持一套Rest风格的统一的接口,所以这里用Rest风格的形式给返回,rest风格返回的基本都是json。然后在类里写一个rest的服务,其实就是一个地址。
微服务的演变以及微服务与微服务之间的通信-----代码示例
上面的是简单的SpringBoot的应用就搭建成功了,而不是微服务。

⑩:然后启动下应用,测试下:
微服务的演变以及微服务与微服务之间的通信-----代码示例
上面的就是rest风格的返回结果。因为它默认使用的是jackSon的方式来序列化对象的。在我们的微服务当中,RestAPI来源于Controller中所提供的一些路径。映射的路径就是Rest风格的API。如何去调用micro-provider的Rest服务呢?比如上面写的是后端的服务,micro-consumer是前端服务(服务消费者),消费端可以有很多个,去进行应用。后端服务只需要给前端服务提供一个rest风格的api就行了。

第二步:接下来是web端的服务:
①:因为只是一个web应用,所以只需要web依赖就可以了。
微服务的演变以及微服务与微服务之间的通信-----代码示例
②:既然是前端服务,所以只提供json字符串就可以了,因为整个的项目只暴露出rest风格的API的。所以只能通过rest风格的api来调用,它俩是独立的项目。不能用公共的东西,先提供下实体vo:
微服务的演变以及微服务与微服务之间的通信-----代码示例
在SpringBoot中的通信方式有两种:RestTemplate,Fegin:客户端调用框架(和HttpClient原理一样后面我会写通过Fegin框架来通信)如果通过RestTemplate方式来调用的话,会有三种的调用方式:
第一种方式:创建一个RestTemplate风格的对象的配置类:
①:把restTemplate对象装配到Spring容器中去。因为只要Spring容器中的对象默认都是单例的,在没有装配之前是拿不到restTemplate的。
微服务的演变以及微服务与微服务之间的通信-----代码示例
②:这个方法的意思是为了得到一个对象 第一个参数是URL(必须是rest风格的路径),第二个参数是响应类型。
微服务的演变以及微服务与微服务之间的通信-----代码示例
③:在客户端通过RestTemplate这样的模板完成了对rest服务的调用。
微服务的演变以及微服务与微服务之间的通信-----代码示例
④:测试一波,先把提供服务的服务给启动起来,再把消费端的服务启动起来,然后运行的结果如下:
微服务的演变以及微服务与微服务之间的通信-----代码示例
注意:micro-consumer的实体类的属性名的映射结果的属性名或者不映射的属性名必须和micro-provider的实体类的属性名保持一致,否则为null。
如果像下面这样写的话就可以映射到的:@JsonAlias:配置json字段映射。
微服务的演变以及微服务与微服务之间的通信-----代码示例
运行结果如下:
微服务的演变以及微服务与微服务之间的通信-----代码示例
提出一个疑问:如果有多个相同的服务实例的话,就是API是相同的,也就是前端服务调用后端服务的url地址是相同的。

相当于micro-provider部署了三台服务器,考虑下:如果现在用前端服务区调用的话,会调用哪一个微服务实例呢?如果按照上面写就出现了问题,这就出现了多服务实例部署的情况,这里就会出现负载均衡,如果按照上面的写法是做不了负载均衡的。

负载均衡:简单的说就是让很多的服务实例去减少原有服务的压力,让他们部署了多个节点上。比如说有10个服务实例,现在又100次请求心跳过来,平均分的话,1个服务实例处理10条请求。或者说某个节点处理的请求很强的话,先交给它来处理,然后最侯处理不了的。再分发给其他的节点来处理剩下的请求,这就称之为负载均衡。

在程序中如何去搞呢?
①:在micro-provider的服务端定义一个服务的名称,也就是应用的服务实例名称。
微服务的演变以及微服务与微服务之间的通信-----代码示例
②:配置多个应用服务的实例的端口,分别为8081,8082,8083。
微服务的演变以及微服务与微服务之间的通信-----代码示例
③:在micro-provider的application.yml文件中加个打印sql的配置:值为mapper包的路径。
微服务的演变以及微服务与微服务之间的通信-----代码示例
④:然后分别启动micro-provider的三个微服务实例:
微服务的演变以及微服务与微服务之间的通信-----代码示例
因为第一种写的是调用后端服务的端口是8080,是写死的,用如果按照上面的写法,是客户端直接知道了服务端的API端口,而且为了保证服务端的API的地址得安全,所以说这里需要通过另外一种方式来实现。如果想要负载均衡的话,需要这三个微服务实例是有注册的,然后才能发现,需要有一个路由,来路由这三个服务实例的路径才行。需要换种做法:加个服务注册中心,要把服务发现组件加进来,因为客户端不知道拿的是服务端的哪一个服务实例的端口,在Cloud中有很多的服务注册中心,但是常用的就是两种eureka和zookeeper,eureka已经闭源了,所以这里选用zookeeper的服务注册中心.zookeeper实际上是一个协调服务的一个组件,它的功能类似于我们的大脑,比如我们的大脑可以协调我们的手和脚,zookeeper没有什么具体的业务功能实现,它只是用来做协调的。zookeeper的存储结构实际上是一个树形的结构,所有的微服务实例注册到注册中心上面去。zookeeper中有 个根节点service,然后下面的节点是项目名称,然后下面的三个节点竖

着排列的是三个微服务实例,里面存储的是UUID的字符串,UUID对应着是服务端的服务实例注册到服务注册中心的ip地址。服务注册中心里面有对应的对象,对象里面是以项目名称为key,集合的服务列表为value,然后客户端会动态的检测,如果服务注册中心里的内容发生改变的话,可以马上通知客户端,因为服务注册中心是一种发布和订阅的模式,服务端把一些服务发布到服务注册中心上面去。那么客户端这里订阅的一些东西,服务注册中心就会通知下面所有的客户端我的服务地址已经发生变化了,那么客户端再调用的时候就是新的服务地址,客户端调用是不受影响的。

在zookeeper中有 Watcher机制,有点类似于javaWeb中的监听器,现在的zookeeper做的就是服务注册中心,就是按照这种方式来注册的,后面会写到把这些东西,配置交给统一的配置中心来进行管理的。
微服务的演变以及微服务与微服务之间的通信-----代码示例
代码实现如下:
⑤:加上SpringCloud的管理的依赖
微服务的演变以及微服务与微服务之间的通信-----代码示例
⑥:然后引入zookeeper的依赖:
微服务的演变以及微服务与微服务之间的通信-----代码示例
⑦安装zookeeper的话很简单的,相信各位大佬们都会的,这里先用本地安装的zookeeper。启动本地安装的zookeeper:双击zkServer.cmd,如果是linux系统的话,直接运行zkServer.sh的shell脚本就行了。
微服务的演变以及微服务与微服务之间的通信-----代码示例
微服务的演变以及微服务与微服务之间的通信-----代码示例
然后启动下客户端zkCli.cmd
微服务的演变以及微服务与微服务之间的通信-----代码示例
这样说明就成功了,现在有一个节点zookeeper。

⑧:然后配置zookeeper,然后把服务注册上来,我们三个微服务实例都需要注册。
微服务的演变以及微服务与微服务之间的通信-----代码示例
⑨:然后去运行三个微服务实例,然后看zookeeper的服务上看是否注册成功:下面的结果是三个节点上有三个微服务实例,说明注册上去了。
微服务的演变以及微服务与微服务之间的通信-----代码示例
也可以看节点的信息:最终要的信息是服务列表和端口号。
微服务的演变以及微服务与微服务之间的通信-----代码示例
⑩:如果这个服务想要被客户端发现的话,需要加一个注解,启用服务发现的注解。
微服务的演变以及微服务与微服务之间的通信-----代码示例
下一个步骤:同样想要让客户端调用的话,也需要加入zookeeper的依赖:
微服务的演变以及微服务与微服务之间的通信-----代码示例
如果客户端引入了zookeeper的话,因为zookeeper是服务发现的组件,在客户端就可以通过ribbon的负载均衡机制就把数据给拿出来。

在zookeeper中有服务的发现,和服务的配置:
微服务的演变以及微服务与微服务之间的通信-----代码示例
而在发现组件里面有客户端的负载均衡ribbon组件,这就是核心,而不是服务端的负载均衡,因为它是从客户端拉取到可用的地址,通过筛选用到可用的服务连接地址。然后进一步去处理,通过负载均衡的策略算法来让处理哪个url。

客户端的负载可以直接封住入口
微服务的演变以及微服务与微服务之间的通信-----代码示例
而ribbon其实是httpClient组件:客户端调用 或者是loadbalancer组件:负载均衡器,有了他们就可以做负载均衡了。
微服务的演变以及微服务与微服务之间的通信-----代码示例
加一个组件:loadBalancerClient,通过这个组件可以晒选出注册到注册中心上的服务列表的信息,这个组件自动有负载均衡策略的,不需要自己再去调用的。这个组件是针对spring Cloud所有的服务发现组件都可以来做的。
微服务的演变以及微服务与微服务之间的通信-----代码示例
组装相应的url。这时就不要担心是哪台服务器了。
微服务的演变以及微服务与微服务之间的通信-----代码示例
为了启动的时候发现我们的注册中心的组件,也需要在消费端配置相应的配置信息:discovery enabled默认的是true的,如果为true的话,会把这个服务注册到注册中心zookeeper上,这里没有去注册到注册中心上去,所以为false,我只需要从zookeeper发现服务列表就可以了。
微服务的演变以及微服务与微服务之间的通信-----代码示例
然后再消费端的启动类上也需要加上启动服务发现的注解:
微服务的演变以及微服务与微服务之间的通信-----代码示例
想要看这里有没有负载均衡的话,先开启三台服务端的服务,然后再启动消费端的服务。
微服务的演变以及微服务与微服务之间的通信-----代码示例
既然是三台服务器,所以所我这里刷新6次。
微服务的演变以及微服务与微服务之间的通信-----代码示例
后台显示的结果如下:
微服务的演变以及微服务与微服务之间的通信-----代码示例
这就是轮巡负载的。再点三次仍然是8081,8082,8083,而且每台的服务器打印的都是两条sql语句:
微服务的演变以及微服务与微服务之间的通信-----代码示例
所以说上面的做法可以做到负载均衡。

第三种方法:在获取RestTemplate的对象上面加一个@LoadBalanced就能做到负载均衡。
微服务的演变以及微服务与微服务之间的通信-----代码示例
url中端口号和ip地址换成服务的名称就可以了。第二种的方式其实就是注解@LoadBalanced在做的事情。
微服务的演变以及微服务与微服务之间的通信-----代码示例
它的方式都是轮巡的方式的,这回我刷新9次,这种方式的运行结果如下:这种方式可以看到服务列表,这些内容都是从zookeeper里面提取的。
第三种方式也是微服务中最主流的一种方式。
微服务的演变以及微服务与微服务之间的通信-----代码示例
负载均衡策略:在这个接口里面
微服务的演变以及微服务与微服务之间的通信-----代码示例
在该接口的实现类:RandomRule是随机的负载均衡策略,RetryRule:重试的负载均衡的策略。RoundRobinRule:轮询的负载均衡的策略。WeightedResponseTimRule:权重的负载均衡的策略,根据响应的时间来做的
微服务的演变以及微服务与微服务之间的通信-----代码示例
如何去更改负载均衡的策略呢?下一次分享会说到,希望大家多关注,因为ribbon这个组件在cloud中充当了重要的角色。

欢迎加群,咨询原创作者,下载源码工程包:797853299

  相关解决方案