当前位置:   article > 正文

微服务架构二、初识微服务、分布式架构案例、eurake、Ribben、nacos_ak server

ak server

一、微服务框架

1、认识微服务,服务架构的演变

 大型项目一定会做分布式架构,降低耦合度 

服务拆分是一方面,将来保证高可用,还要做集群,如何治理?

一些演变如:webService,ESB ,Dubble,Spring Cloud等,目前这些分布式技术也再不断的升级和迭代 (spring Cloud 只是解决服务治理问题)

现在最火的就是微服务了!

最流行的一种就是微服务,跨服务调用-微服务(业务模块对外暴漏业务接口)

微服务架构特征:目的就是实现高内聚,低耦合,降低服务之间的影响

  • 单一职责
  • 面向服务:比如积分服务,需要暴露一个查询积分的接口,将来用户服务就可以去调用该接口,这样就可以获取积分信息了
  • 自治:独立
  • 隔离性强:比如某个积分服务挂了,那么用户服务去调用积分服务的时候发现挂了,需要把故障隔离起来,提前做好容错措施,避免积分服务宕机了导致用户服务也宕机了,即:避免级联问题

 

总结:微服务是分布式架构的一种,分布式架构就是将服务做拆分

2、分布式服务架构案例

微服务这种方案需要技术框架来落地,国内最著名的就是 Spirng Cloud 和 阿里的Dubbo

Spring Cloud 和 Dubbo 他们都需要做服务的拆分形成集群,而集群中的每个服务都要遵循单一职责的原则,而且要面向服务,对外暴露业务接口,这样服务之间就可以做一些相互的调用

这么多服务需要维护,就用到了注册中心,他可以维护微服务里边每个节点的信息,并且去监控这些节点的状态

 微服务技术对比,SpringCloudAlibaba 是 在 SpringCloud的基础上开发的,实现了SpringCloud的技术,并兼容了自己的Dubbo技术 

Spring Cloud :服务调用直接用http协议,就像我们以前编写的Controller 就是http协议的(像Controller里的方法,参数支持HttpServletRequest 等这不是就http模式嘛),只要遵循restful,任何能够发http请求的都可以调用你

Restful风格,就是RestAPI,就是采用http协议,就像大象接口调用利用http协议调用不同模块暴露的接口,或请求保司的接口,因此服务调用就用Feign方式

 像Dubblo如果要升级为SpringCLoudAlibaba+Dubbo 代码是不用动的,动的只是那些外部如注册中心,配置中心等

了解SpringCloud:集成了各种微服务组件,并且基于SpringBoot实现了这些组件的自动装配

Spring Boot 最擅长的事情就是自动装配

Spring Cloud 就是把原生官方开源的组件给整合进来嘞,并且基于Spring Boot做了装配,也就是说我们拿过来就可以用,而不需要复杂的配置

Spring Cloud 底层是基于Spring Boot做了自动装配,所以有版本兼容问题

左边是Spring Cloud版本,右边是Spring Boot版本,也就是说,如果Spring Cloud 用了Greenwich版本,那么SpringBoot就必须用2.1.几的版本,如果用2.0.x的版本,将来可能就会报错,或起不来

SR5用的是2.2.X版本,如果是SR5以上,那就得用2.3.x,我们课程里用的是Hoxton.SR10,所以是SpringBoot版本得是2.3.x

2.1 小节:服务拆分

比如说现在有一个需求,查询订单信息,同时把订单关联的用户信息、商品信息也都查出来

以前的开发模式是 写一个方法去查询订单,在订单查询的过程中得到了用户id,再去数据库里把用户查出来,得到商品id再去数据库里把商品查出来,这些功能全部写到订单模块里,其实是违背了微服务的原则 独立,每个模块是独立的,如果订单模块想要获取用户信息,用户模块需要暴露出一个接口供订单模块去调用

   

导入实用篇的代码cloud-demo,父工程cloud-demo负责管理整个项目的依赖,两个子工程,orderSerivce 和 userService,导入库表,来模拟服务分离

order-service对应的库是cloud_order、user_service对应的库是cloud_user

路径这就是Restful格式,controll 暴露方法遵循http协议,就是用http方式可以请求

所谓restful 风格,就是遵循http协议可以请求

路径里的参数接收可以用 @PathVariable(" ") 来接收 

 两个项目都起来以后,浏览器输入

http://localhost:8081/user/1  请求user服务

http://localhost:8080/order/101  请求order服务

每个服务有单一的职责,order服务查订单,user服务查用户,并且数据库我们也做了分离

 

导入项目后点几show service 就会显示,启动项目后idea有个好处,直接点击端口,就会访问浏览器了

总结: 

 

2.2 小节:微服务远程调用

根据订单id 查询订单和用户,然后将数据组装起来,自己查自己,服务调用,暴露,面相服务

模块调用:问题:就是如何在java代码中发起http请求 

就是说前端发起http请求访问订单模块,必须由订单模块再发起http请求访问用户模块,前端不能自己去访问用户模块

spring提供了一个工具RestTemplate,这个工具就是用来发http请求的

 注意:bean的注入只能放在配置类里,而Spring Boot的启动类,是带有main函数,还有@SpringBootApplication这个注解,本身它也是个配置类

创建RedisTemplate 并 注入 spring容器里 。(注意,不是Redis的RedisTemplate)

服务之间的调用:在order服务里访问user服务暴露的方法

 以上就实现了跨服务的远程调用

注意:要想实现跨服务的远程调用,其实就是发送一次http请求

  • 注入RestTemplate
  • 利用RestTemplate里边的方法,告诉它请求url的路径,就像浏览器输入的一样,再告诉它返回值类型,该方法就能帮我们把返回值的json转成对应的类型了

 总结:需要注意,http 请求做远程调用,它是与语言和技术无关,因为restful 只要知道对方ip、port、url、param即可

 2.3 小节:服务的提供者与消费者

一个服务,既可以是服务的提供者,也可以是服务的消费者 

总结:一个服务可以同时是服务的提供者和服务的消费者,如果抛开业务谈服务,那就是在耍流氓 

3、eureka注册中心

3.1:远程调用的问题

上边案例,我们order调user,url是将ip 和 端口 应用到了代码当中的-硬编码

比如我们开发环境,测试环境,生产环境ip 和端口都不一样,如果采用硬编码,就得每次都去修改吗?如果是集群模式呢端口该写哪个呢?

3.2eureka原理

  • Eureka-server 服务端,作用是记录和管理这些服务 
  • Eureka-client   客户端,服务的消费者+服务的提供者
  • 我们的user-service 在启动的那一刻,会做一件事情,会把自己的信息注册给eureka,注意:每一个服务在启动时,都会做这件事!只要你是erueka的客户端
  • eureka-server 会记录你的 ip + 端口,所有的服务都起来了,也就是说所有服务的信息都被eureka-server记录在案
  • 此时,有一个服务想要消费,比如说是order-service,那么它不需要自己去记录服务提供者的信息,他会找eureka,和eureka说我想找user-service,看看有没有(拉取user-service信息)
  • 如果eureka一看有,还有好几个,那就会都发给order-service,这样order-service就拿到了地址信息了
  • order-service一看有多个信息,就会负载均衡,从里边挑一个出来,如果挑到了8081,那就会像8081那个机子发送请求了
  • 问题:挑的这个会不会是挂的呢?答案是:不会
    • 因为我们的服务每隔30秒钟都会向eureka-server发送一次心跳,来确认自己的状态,如果有一天不发送了,eureka察觉到了,就会把该服务的信息从列表中剔除
    • 这样拉取的时候就不会拉取挂了的信息
    • 也就是说我们的消费者能够随时监控到服务的状态

Eureka的作用:

注意:服务消费者,也会变成服务提供者,那么久也会去做注册+发送心跳的

---------------------------------------------------------------------------------------------------------------------------------

3.3搭建EureakServer 

Eureak搭建需要创建一个独立的微服务

1、引入eureke的依赖,依赖里有starter 代表属于Spring Boot里的自动装配,只要引入这个依赖,就代表了,我们可以实现0配置,直接拿来就用,都配置好了,这里我们并没有引入版本信息,是因为在父工程中把依赖都管理好了已经

2、这种自动装配也是有开关的,添加注解,@EnableEureakServer,他就是eureka_server的自动开关

3、编写一些配置信息,包括端口信息,服务名称,还有eureka的地址信息,

如下图,看一看见父类pom文件里的spring-boot的版本,spring-cloud的版本,还有spring-cloud的版本库,版本库里的spring-cloud的版本都整理好了已经

 动手实践

在项目里创建一个新的服务 new - module -  maven - 项目名字

1、pom文件添加依赖

2、创建一个启动类EurekaApplication,并创建main函数,添加启动类注解@SpringBootApplication,创建main函数,添加启动方法,SpringApplication.run(类.class, args);  ,并添加eureka的开关

3、添加配置文件信息

  1. server:
  2. port: 10086 # 服务端口
  3. spring:
  4. application:
  5. name: eurekaServer # 服务名称,每个服务去注册的时候都要带上名字
  6. # eureka 自己也是一个微服务,所以eureka在启动的时候也会将自己注册到eureka上,
  7. 这个为了将来集群通讯去用的, 如果有多个eureka 以逗号隔开,将自己注册到eureka里,
  8. 客户端也需要注册,同样的配置,url是eureka的地址
  9. 所以,这里的服务名称和地址,其实就是在做服务的注册!!!
  10. eureka:
  11. client:
  12. service-url:
  13. defaultZone: http://localhost:10086/eureka # eureka的地址信息

  输入地址:http://127.0.0.1:10086/   不要输入eureka,就会打开地址了

浏览eureka可以看到:注册到eureka的实例。up是正常状态,down是挂调了 

将来就可以根据服务的名字,找到ip+端口了,下图可以得知ip是192.168.66.38,端口是10086

 

3.4服务注册,将服务注册到eureka里,两步就够了

服务名称和服务地址,就是服务注册的一个配置,这里是eureka的客户端

 注册到eureka中心

模拟多个实例形成列表 

 相当于集群形成列表,-D 就是参数,server.port=8082 我们在yaml文件里的端口号就是这么配置的

第三个就是实例的列表 

凡是引入依赖,配置地址,就是在做注册,我们在eurekaserver也是在做这个事情 

3.5服务发现

1、我们是根据服务名,来获取服务列表(ip+端口啥的),那就不要写ip 端口了,直接写服务名称,如下图,服务名就代表ip+端口了 

 2、多个实例那就做负载均衡,工具类RestTemplate 添加注解@LoadBalanced,去选一个实例进行访问

orderService修改url代码,不能再写硬编码了,应该写服务的名称

 然后main函数的配置工具类RestTemplate添加负载均衡注解即可

 访问:http://localhost:8080/order/102        ,http://localhost:8080/order/101

发现8081 和 8082 都被访问了一次,实现了负载均衡。即:我们根本不用去关心服务的地址,我只需要把服务的名字往路径里一放就可以了,剩下的事情交给Eureka的工具和负载均衡去做了,这就是服务的发现和拉取

就是用服务名代替ip+port

4、Ribbin负载均衡原理

4.1、负载均衡原理

  • urder-service发送请求,http://userservice/user/1 , 这个请求并不是一个真实的请求,,无法直接访问到后端,
  • 会被Ribbon拦截, 
  • 请求eureka,拉取名字为userservice的服务,发现有服务列表,就返回
  • 轮循

@LoadBalanced,这个标记就标记通过该实例发送的请求要被Ribbon拦截

shift shift,查询class LoadBalancerInterceptor负载均衡拦截器,找到类RibbonLoadBalancerCLient.java

发现获取的是域名 userservice,然后负载均衡.execute执行

根据服务名称,找eureka拉取服务列表,返回一个loadBalancer对象,返回的是一个动态服务列表负载均衡器,里边的参数有个list 是从eureka拉取的服务列表,如下参数allServerLIst

而接下来的代码getServer(),就是在做负载均衡,获取一个server 

这个rule 是一个接口,IRule,接口肯定有实现类,通过ctrl+h查看实现类 

我们可以得知负载均衡的策略是由IRule这个接口来决定的

根据轮循负载均衡规则,获取了一个实例

  获取到了真实的ip+端口号,如:8081用来替代域名名称userservice

即:

  • 请求会被拦截器拦住(负载均衡拦截器)
  • 拦截下来以后会得到请求路径的服务名称
  • 把服务名称交给负载均衡客户端
  • 负载均衡客户端又会把服务交给DBalancer(动态服务列表负载均衡器)
  • D请求eureka,拉取服务列表
  • DBalancer 又回去找IRule
  • IRule又会从列表里边,基于规则选出一个服务来,将值返回RibbonLoadnBanlancerClient
  • 修改url再次发起请求

 

4.2、负载均衡策略IRule规则 

 一般情况下,走默认规则就可以了,它的爷爷是有轮循规则的,它也会有

 修改负载均衡规则

1、注入Bean,修改规则,这里是从轮循变成了随机,返回new RandomRule ()了 

注意:第一种是全局的,orderservice访问任何微服务都是随机负载均衡

第二种是针对某一个微服务的 

注意,默认是轮循机制!没有做任何修改时

我们访问101,102,103,104 发现user控制台,8081里有1,3 和 8082有2,4,这显然是轮循

通过以下配置,我们将负载均衡的配置设置为随机

ourder-server添加配置修改负载均衡配置 

次数较少是可能不太均衡,次数多的话,还是均衡的

再次访问101,102,103,104,105,发现可能有4次在8081,1次在8082

2、通过配置文件添加规则

在order-service的yaml文件里配置规则,这个的配置是order请求只针对userService这一个微服务是随机负载均衡,访问微服务的名字不是userService的还是默认轮循机制!

二者不要并存

  1. userService:
  2. ribbon:
  3. NFloadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
  4. #负载均衡规则,只要把想配的类名配进来即可

4.3、懒加载

eager 渴望的,渴求的

enable 使可能,使能够

 我们可以测试一下,重启order 发现第一次请求达到了524毫秒,是因为第一次请求需要去拉取数据

 而第二次请求才用了75毫秒,第二次请求缓存已经有了,直接拿

 第一次耗时长,是因为访问的时候才会去创建RibbonLoadBanalanceClient,,可以做饥饿加载

项目启动时就会加载进来,配置完重启项目发想速度第一次块了一半,因为还有一些别的配置,如springmvc容器等加载

  1. ribbon:
  2. eager-load:
  3. enabled: true
  4. clients:
  5. - userService
  6. # clents这是一个集合,指定饥饿加载 的 服务名称,如果是一个,直接写在冒号后边就行,
  7. # 如果有多个m每个都需要加杠 - xx

5、nacos注册中心

5.1认识和安装Nacos

下载并注册: 

 文件里有nacos包,用1.4.x的,mac 下安装与启动Nacos - 拿我格子衫来的代码笔记​​​​​​

安装好后,终端进入bin目录

  • 启动    sh startup.sh -m standalone (standalone单机启动)
  • 停止,sh shutdown.sh

在浏览器输入地址:http://127.0.0.1:8848/nacos  即可:账号密码都是nacos

5.2Nacos快速入门

1、父工程管理依赖,以后子工程所有alibaba的版本都不需要管理版本号了

  1. <--!nacos的管理依赖-->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  5. <version>2.2.5.RELEASE</version>
  6. <type>pom</type>
  7. <scope>import</scope>
  8. </dependency>

2、在user-service 里把eureka的客户端依赖注释,

添加nacos客户端依赖

3、修改yam文件

nacos服务地址,是spring旗下的,所以配置在spring下,默认是8848;将原来的eureka服务注册调

这样user-service的服务配置就完成了,此时我们启动user-service理论上讲他就会注册到我们的nacos里

order-service也改了,同理:1:引入alibaba的配置,注释掉eureka的依赖,2:修改yam文件 

打开nacos,如下服务注册成功 

经过测试发现,http://localhost:8080/order/104  101。102。013

控制台8081,8082都有日志,证明配置生效了,负载均衡是没有问题的

服务注册和发现,因为springCloud定义了通用Commond 所以只需要引入以来配置地址就可以了 

5.3Nacos服务分级存储模型

一个服务可以有多个实例,可能存放到不同的机房,北京一个,上海一个,北京的机房挂了,还有上海的机房活着。

同在一个机房的多个实例,称为一个集群

在nacos分级存储模型里,一级是服务,往下是集群,再往下是实例

为什么这样呢?直接用服务找实例不好吗?为什么要加一个地域划分形成一个集群的概念?

有 这样一种情况

两个集群,有杭州集群,上海集群

当order-service访问user-service,一种是本地局域网,另一种是访问外边的,肯定优先本地,距离短,速度快,延迟低。

如果是跨越集群去访问从杭州访问上海,那么延迟是比较高的,只有在本地集群不可用的情况下,才会去访问其他集群

 nacos引入集群概念,其实就是防止出现跨集群调用,尽可能的避免这种情况

需要配置集群属性

点击详情,发现集群属性是default 默认,也就是没有集群 

如何配置实例的集群属性?

只需要在yaml文件添加配置配置即可,配置集群名称

 先停掉服务,然后添加配置HangZhou,启动8081和8082,然后再添加一个实例,修改HangZhou为ShangHai,启动8083,发现集群信息如下,user-service的8081和8082属于HZ集群,8083属于SH集群了。

如果此时再重启8081,那么没有改配置的情况下,8081就是SH的集群下了,因为在启动的之前改的配置

 以上就实现了实例的一个集群属性的这样一个配置了

虽然集群有了 但是我们的目order-service在访问时,优先选用本地集群

因此我们还要给order-service也配置一个集群属性,这里本地设置成HangZhou

重启后测试order-service将来会不会优先选用本地集群,HangZhou的,8081和8082 

http://localhost:8080/order/103 测试得知 8081、8082、8083 都被访问了,也就是说order-service发起远程调用的时候并不会优先选用本地集群,依然采用的是轮循

这是因为依然是轮循模式,IRule规则是默认的,轮循,所以三个都会被执行

要想实现有限本地集群,需要修改负载均衡规则

 修改完后,重启order-service 然后测试,发现已经可以优先选用本地集群了只有8081和8082有日志,8083没有日志,8083是ShangHai的

  1. userService:
  2. ribbon:
  3. NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
  4. # 负载均衡规则

这证明了NacosRole确实具备优先选用本地集群

问题:在优先选用本地集群的情况下,本地集群的实例8081和8082又该如何选择呢?

  • 没有轮循,是随机的,也就是说本地集群内的多个实例,随机的形式来负载均衡

如何把8081和8082停掉,也就是把HangZhou的集群停掉会怎么样呢?可以看到下图HangZhou的集群已经没有实例了

 此时再发起请求 刷新,依然可以访问,没有问题,说明本地集群没有服务也能访问

 因为8083还活着,这次请求被8083给拿到了,而在order当中出现了一个警告信息

一次跨集群访问发生了,谁呢?userservice,想访问的是HZ,实际访问的是SH 

通过这个我们可以知道NacosRule优先访问本地集群,本地没有才会跨集群访问,跨集群访问会有一个警告,将来运维人员就可以看到这么一个警告信息,知道发生了什么问题了,就会及时重新启动挂掉的服务,解决这个问题

NacosRule 规则:随机负载均衡 

 

 以上就是Nacos的一种负载均衡规则NacosRule,是集群优先,内部实例随机的

根据权重来负载均衡

权重值一般是在0-1之间的 ,比如8081设置为0.1

如果权重调成0时,那么该服务就永远不会访问,这可以给该服务做优化升级,方便很多了,升级好后,还可以权重降低逐渐的看看访问有无问题

 

5.4Nacos环境隔离

nacos首先是一个注册中心,但是其实它也是一个数据中心

为了做数据和服务的管理,它会有一个隔离的这么一个概念

而环境隔离有这么几个东西

  • namespace命名空间(隔离空间)
  • group(同一个空间多个东西还可以分组)
  • service(组内的东西)

环境隔离其实就是对服务做隔离,可知不同环境的服务,将来不能互相访问

比如开发环境,测试环境的划分,那么namespace就是来做这个事情的

group就是分组,把业务相关度一致的放到一个组了,比如订单和支付

不是强制的要用,也可以不分组

 打开nacos配置中心,新建立一个开发空间dev,我们以前的服务都是在默认的空间public里,如何到dev里呢,这就需要再代码里去修改了 

需要在代码里加上我们配置的命名空间的id 

 注意,他们已经是两个世界的人了,就和jekins里的 开发环境,和测试环境一样,一个意思dev不能访问public默认空间的东西,只能访问自己dev空间的东西

Nacos和Eureka对比

注意:消费者每隔30秒回拉取一次,拉取的服务列表缓存就是那个D开头的拦截器

 服务注册、拉取、远程调用时一样的

不一样的是健康检测, 

  • nacos注册的时候有 临时实例(默认)心跳检测,没有就的话 nacos就给你干掉,从列表中剔除
  • 非临时实例,是由nacos主动发送请求询问,如果有一天发现非临时实例挂了,那么nacos不会给你剔除,仅仅是标记该服务不健康了,等着该服务恢复健康

还有一种情况不同 ,是消费者

  • 消费者定时拉取服务,每隔30秒一次,那么如果在30秒内有服务挂了,消费者知道吗?如果不知道直接去消费,就有问题了---eureka采用的是pull
  • eureka更新不会有那么及时,而nacos主动做了一件事:消息推送---nacos采用的是pull+push
  • nacos如果发现有服务挂了,会立即推送消息给服务的消费者,赶紧更新,效率高

 临时实例和非临时实例

临时实例后,服务停掉,nacos里就没有了

 改成非临时实例后

 再次将服务停掉,一瞬间就发现了,服务会一直在这里,除非手动删除!

 再次启动后,发现又健康了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/566769
推荐阅读
相关标签
  

闽ICP备14008679号