首先,来到问题:微服务是怎么出现的?
在近年来中,网络用户量的激增,数据的激增,业务的复杂度加大,导致并发量过大,单体项目承受不了这种工作量,后续开发渐渐出现了微服务架构开发,微服务的出现,为目前项目技术上画上了浓重的一笔。
本质:把一个大型的单个应用程序和服务拆分为数个的支持微服务,将功能分离到个个服务中,他们之间通过网络来通信和协调。
好了,话不多说,下面开始介绍下这几年企业里用的比较多的主流框架吧。
Spring-Cloud:
这是一套微服务架构的工具集
它提供服务发现、服务调用、负载均衡、配置管理、服务容错、分布式事务、服务网关等开发工具。
下面介绍下主流的开发工具:
服务发现:使用的是nacos
在微服务架构中,整个系统会按职责能力划分为多个服务,通过服务之间网络通信以及协调实现业务目标。这样在我们的代码
中免不了要进行服务间的远程调用,消费者需要调用生产者,为了调用,消费者需要得到生产者的网络地址信息
负载均衡:使用的是ribbon
Ribbon的内置(比较主流的)负载均衡策略:
BestAvailableRule-最小并发数→优先选择一个并发量最小的server
WeightedResponseTimeRule-响应时间加权→根据响应时间长短分配,响应时间越长被分配到请求的概率越小
RoundRobinRule-轮询→说白了就是轮流着按顺序分配请求
RandomRule-随机→完全随机分配请求
服务调用:使用的是openfeign
openfeign的实现原理是通过spring-aop 代理模式创建响应的代理类
再通过反射获取请求方式,请求方法名,请求参数列表,返回值类型
配置管理:使用的是nacos统一配置管理
简单来说就是约定,例如商业活动中的合同,在签订合同后,双方严格按照合同来执行,
配置也是如此
应用程序在启动和运行的时候往往需要读取一些配置信息,然后按照配置信息来执行程序
bootstrap.yml在启动项目时就会被读取
在nacos控制台中,新建配置:
Data ID:我们本地的配置文件都叫application.yml,如果nacos中都叫这个则不利于维护;所以data-id的命名规则为:服务名-环境.yaml;
nacos配置更改后,微服务可以实现热更新方式:
1、通过@Value注解注入,结合@RefreshScope来刷新
2、通过@ConfigurationProperties注入,自动刷新
分布式事务:使用的是seata
由于是分布式项目,各个项目都是分离的,只操作自己的数据库,加之网络通信问题等,引出了全局事务这个概念
事务协调者:TC Transaction Coodinator 协调各个分支事务,同时提交,同时回滚
事务发起者:TM Transaction Manager 事务管理者,发起全局事务
事务参与者:RM Resource Manager 资源管理者,参与全局事务,维护分支事务
大致原理:TM发起全局事务,TC通知各个RM执行业务操作,各个RM执行后告知TC,TC判断RM全都正常执行则全局事务提交,否则只要有一个以上的RM没正常执行,则全局事务回滚
常见的解决方案:
1.XA协议
多个分布式子项目,都快打开事务,执行业务后,先不提交,等待TC确认状况,全都正常执行则提交
缺点:数据库事务耗性能,比较消耗时间,用户体验差
2.TCC协议
Try→尝试→将要变动的资源锁定
Confirm→确定→执行业务
Cancel→撤销→释放之前被锁定的资源
先锁定资源,如果都成功则执行Confirm,否则执行Cancel
劣势:写代码的难度大大增加
3.SAGAS
适用于长事务,在企业在一般不用这个
4.AT模式
AT模式才是seata所提供的分布式事务
应用场景:
1.不希望对代码进行改造
2.数据库支持事务操作
3.对性能没有特别高的要求
每个数据库都需要先建一张UNDO.LOG表。执行相应的业务,seata代理数据源,拦截所有的SQL,记录业务执行前后操作的镜像,生成相应的SQL插入到UNDO.LOG表中,加入到当前事务中提交,如果都正常提交了,则删除UNDO.LOG中的记录,否则会拿UNDO.LOG中的记录来做补偿,也就是会根据前后的镜像生成回滚用的SQL,执行这个SQL来做到事务回滚
劣势:每个数据库都需要一张UNDO.LOG表
底层实现原理:TM通过@GloBalTransactional开启全局事务,向TC注册并获取返回的XID,TM带着XID去调用其他服务,其他服务带着TM传过来的XID去TC注册并获取返回自己服务的ID,以此类推,TM不断带着XID去调用其他服务,服务执行业务成功或者失败都会通知到TC,如果有服务执行失败,则TC会通知所有分支事务回滚。
服务网关:使用的是gateway
为什么需要网关?
网关作为微服务唯一的入口,需要校验用户是是否有请求资格(认证鉴权),如果没有则进行拦截
一切请求都必须先经过gateway,但网关不处理业务,而是把请求转发到某个微服务,这个过程叫做动态路由。当然路由的目标服务有多个时,还需要做负载均衡。
当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求(限流),避免服务压力过大。
gateway基于Reactive,而不是Servlet,底层实现是通过Netty,所以项目里不能有starter-web的依赖,有则会启动时报错。
跨域问题:因浏览器禁止请求的发起者与服务端发生跨域ajax请求
可以通过@Crossorgin注解解决
可以通过配置yml来解决,允许哪些网站跨域,允许跨域的ajax请求方式,允许在请求头中携带信息,是否允许携带cookie,还可以设置有效时间等
可以通过全局过滤器,用代码实现添加跨域请求头解决
gateway的两种过滤器:
GatewayFilter网关过滤器
GlobalFilter全局过滤器
其中全局过滤器是有顺序的,而路由转发则是通过NettyRountingFilter来做的。
服务容错:使用的是sentinel
在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果某个服务出现问题,这时大量的网络涌入,会形成请求堆积,最后会造成服务血崩
常见的服务容错模式:
超时:
消费者调用下服务时,设置一个最大响应时间,如果超过这个时间,生产者未作出响应,就断开请求,释放掉线程(资源)。
限流:
为了保证分布式系统的稳定运行,需要设置好阈值,且不超过本机的处理能力,来限制请求量的目的。
舱壁模式:
说白了就是隔离性质,将资源隔离起来,出了故障不会影响其他的资源
熔断:
相当于一根智能的保险丝,当请求时发生异常的量达到设置好的阈值,打开熔断器,阻隔请求下发,等过了一个熔断时间窗后,会发探测请求来探测情况,当能正常运作时,熔断器关闭
实际开发中还会用到:fallback
相当于一个后备(替补)的角色,当请求出现异常时便顶上,返回应用应该看到的提示信息
单点登录:Single Sign On
可以基于sa-token框架来实现sso
1)设置不同的域名
2)登录后会生成token并保存在cookie中,需将cookie的父级域名设置好
3)后续会携带这个cookie访问不同的微服务子项目
4)去除cookie去同一个redis中查看登录状态
服务划分:分布式项目中的划分