赞
踩
大型项目一定会做分布式架构,降低耦合度
服务拆分是一方面,将来保证高可用,还要做集群,如何治理?
一些演变如:webService,ESB ,Dubble,Spring Cloud等,目前这些分布式技术也再不断的升级和迭代 (spring Cloud 只是解决服务治理问题)
现在最火的就是微服务了!
最流行的一种就是微服务,跨服务调用-微服务(业务模块对外暴漏业务接口)
微服务架构特征:目的就是实现高内聚,低耦合,降低服务之间的影响
总结:微服务是分布式架构的一种,分布式架构就是将服务做拆分
微服务这种方案需要技术框架来落地,国内最著名的就是 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请求
总结:需要注意,http 请求做远程调用,它是与语言和技术无关,因为restful 只要知道对方ip、port、url、param即可
2.3 小节:服务的提供者与消费者
一个服务,既可以是服务的提供者,也可以是服务的消费者
总结:一个服务可以同时是服务的提供者和服务的消费者,如果抛开业务谈服务,那就是在耍流氓
3.1:远程调用的问题
上边案例,我们order调user,url是将ip 和 端口 应用到了代码当中的-硬编码
比如我们开发环境,测试环境,生产环境ip 和端口都不一样,如果采用硬编码,就得每次都去修改吗?如果是集群模式呢端口该写哪个呢?
3.2eureka原理
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、添加配置文件信息
- server:
- port: 10086 # 服务端口
-
- spring:
- application:
- name: eurekaServer # 服务名称,每个服务去注册的时候都要带上名字
-
- # eureka 自己也是一个微服务,所以eureka在启动的时候也会将自己注册到eureka上,
- 这个为了将来集群通讯去用的, 如果有多个eureka 以逗号隔开,将自己注册到eureka里,
- 客户端也需要注册,同样的配置,url是eureka的地址
- 所以,这里的服务名称和地址,其实就是在做服务的注册!!!
- eureka:
- client:
- service-url:
- 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.1、负载均衡原理
@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
即:
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的还是默认轮循机制!
二者不要并存
- userService:
- ribbon:
- NFloadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
- #负载均衡规则,只要把想配的类名配进来即可
4.3、懒加载
eager 渴望的,渴求的
enable 使可能,使能够
我们可以测试一下,重启order 发现第一次请求达到了524毫秒,是因为第一次请求需要去拉取数据
而第二次请求才用了75毫秒,第二次请求缓存已经有了,直接拿
第一次耗时长,是因为访问的时候才会去创建RibbonLoadBanalanceClient,,可以做饥饿加载
项目启动时就会加载进来,配置完重启项目发想速度第一次块了一半,因为还有一些别的配置,如springmvc容器等加载
- ribbon:
- eager-load:
- enabled: true
- clients:
- - userService
- # clents这是一个集合,指定饥饿加载 的 服务名称,如果是一个,直接写在冒号后边就行,
- # 如果有多个m每个都需要加杠 - xx
5.1认识和安装Nacos
下载并注册:
文件里有nacos包,用1.4.x的,mac 下安装与启动Nacos - 拿我格子衫来的代码笔记
安装好后,终端进入bin目录
在浏览器输入地址:http://127.0.0.1:8848/nacos 即可:账号密码都是nacos
5.2Nacos快速入门
1、父工程管理依赖,以后子工程所有alibaba的版本都不需要管理版本号了
- <--!nacos的管理依赖-->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-alibaba-dependencies</artifactId>
- <version>2.2.5.RELEASE</version>
- <type>pom</type>
- <scope>import</scope>
- </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的
- userService:
- ribbon:
- NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
- # 负载均衡规则
这证明了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就是分组,把业务相关度一致的放到一个组了,比如订单和支付
不是强制的要用,也可以不分组
打开nacos配置中心,新建立一个开发空间dev,我们以前的服务都是在默认的空间public里,如何到dev里呢,这就需要再代码里去修改了
需要在代码里加上我们配置的命名空间的id
注意,他们已经是两个世界的人了,就和jekins里的 开发环境,和测试环境一样,一个意思dev不能访问public默认空间的东西,只能访问自己dev空间的东西
Nacos和Eureka对比
注意:消费者每隔30秒回拉取一次,拉取的服务列表缓存就是那个D开头的拦截器
服务注册、拉取、远程调用时一样的
不一样的是健康检测,
还有一种情况不同 ,是消费者
临时实例和非临时实例
临时实例后,服务停掉,nacos里就没有了
改成非临时实例后
再次将服务停掉,一瞬间就发现了,服务会一直在这里,除非手动删除!
再次启动后,发现又健康了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。