一.微服务技术栈
![](https://i-blog.csdnimg.cn/blog_migrate/a564a12276f466e30bfc1fab5e9c8112.png)
二.服务架构
1.1单体架构
![](https://i-blog.csdnimg.cn/blog_migrate/36e8771fb12e15c7bf47b385ead7af3c.png)
1.2分布式架构
![](https://i-blog.csdnimg.cn/blog_migrate/ccdc3fb16f980de84f0cddb3b7adc9ce.png)
1.3RPC框架
RPC(Remote Procedure Call,远程过程调用)是一种常用的 分布式系统通信协议,它可以 让应用程序像调用本地函数一样调用远程服务,从而实现分布式系统中的服务调用和数据传输。RPC的基本原理是将本地调用封装成网络消息,通过网络传输到远程服务端,再将远程服务端的结果返回给本地调用端,从而实现远程服务调用。
RPC通常包括以下几个组件:
-
调用端(Client):负责发起远程调用请求,将本地调用封装成网络消息发送到远程服务端。
-
服务端(Server):负责接收远程调用请求,解析请求消息并调用相应的服务方法,将结果封装成网络消息返回给调用端。
-
服务接口(Service Interface):定义远程服务接口和方法,包括方法名、参数类型和返回值类型等。
-
通信协议(Communication Protocol):定义消息的格式和传输方式,包括序列化方式、网络协议等。
-
序列化框架(Serialization Framework):将数据对象序列化成网络消息或将网络消息反序列化成数据对象,常用的序列化框架有JSON、XML、Protobuf等。
-
注册中心(Registry):提供服务注册和发现功能,使得客户端可以通过注册中心获取服务提供者的信息,从而调用远程服务。
在RPC中,调用端和服务端可以使用不同的编程语言和框架实现,RPC框架可以屏蔽底层通信细节,使得应用程序可以更加方便和高效地进行远程服务调用。常用的RPC框架包括Dubbo、gRPC、Thrift等。
1.4微服务技术对比
![](https://i-blog.csdnimg.cn/blog_migrate/67d90e5d2ba4d164a2f35d0aca75743f.png)
常见组合
![](https://i-blog.csdnimg.cn/blog_migrate/bf1b609bb065173b5c25d277504909b8.png)
1.5服务提供者与消费者(相对)
![](https://i-blog.csdnimg.cn/blog_migrate/0934a3cbe4e0163e17adf7096da9b66f.png)
-
服务提供者:暴露接口给其它微服务调用
-
服务消费者:调用其它微服务提供的接口
-
提供者与消费者角色其实是相对的
三.Eureka注册中心
1.1Eureka的作用
![](https://i-blog.csdnimg.cn/blog_migrate/b5706889dc269deae43be00b48506189.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e8b3c3f816dc7ffd380b35106f6e65cb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e6f407c39c133a9ff058a3c834768b2b.png)
Eureka自己也是一个微服务,所以Eureka在启动时会将自己也注册到Eureka上,并配上自己的信息地址,以便在Eureka集群之间通信
1.2搭建过程
![](https://i-blog.csdnimg.cn/blog_migrate/5a67d3b4b4b71693c62c9770bf6c8dcc.png)
四.Ribbon负载均衡
1.1负载均衡流程
![](https://i-blog.csdnimg.cn/blog_migrate/440fd27b55abbe991113784c0dc07626.png)
![](https://i-blog.csdnimg.cn/blog_migrate/70761b8eb3ee665f612d7d7d56b88ff1.png)
1.2负载均衡策略
![](https://i-blog.csdnimg.cn/blog_migrate/fc44f59c79d761dcc9dfc797e4c4d774.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4984362c432f025f43b1859c5319e2f5.png)
-
轮询策略(Round Robin):按照请求的顺序依次将请求分配给不同的服务实例,实现简单,适用于服务实例数量较少的场景。
-
随机策略(Random):随机选择一个服务实例进行请求转发,适用于服务实例数量较少且负载相对均衡的场景。
-
最少连接数策略(Least Connection):选择当前连接数最少的服务实例进行请求转发,适用于长连接的场景。
-
IP哈希策略(IP Hash):根据请求的来源IP地址,计算出一个哈希值,选择哈希值对应的服务实例进行请求转发,适用于需要保持会话一致性的场景。
-
权重轮询策略(Weighted Round Robin):根据服务实例的权重值,按照权重比例将请求分配给不同的服务实例,适用于服务实例的性能差异较大的场景。
-
动态权重策略(Dynamic Weight):根据服务实例的负载情况动态调整权重值,使负载更加均衡,适用于服务实例负载波动较大的场景。
-
最低并发策略(Lowest Response Time):选择响应时间最短的服务实例进行请求转发,适用于需要提高系统性能的场景。
1.3修改负载均衡规则
![](https://i-blog.csdnimg.cn/blog_migrate/f6756bdb300936d936c3129cea7cc1b9.png)
-
代码方式:配置灵活,但修改时需要重新打包发布
-
配置方式:直观,方便,无需重新打包发布,但是无法做全局配置
1.4饥饿加载
![](https://i-blog.csdnimg.cn/blog_migrate/65afc9359f52af51d49eeefafe908473.png)
五.Nacos注册中心
国内公司一般都推崇阿里巴巴的技术,比如注册中心,SpringCloudAlibaba也推出了一个名为Nacos的注册中心。Nacos 是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高
1.1搭建过程(需要先安装JDK)
![](https://i-blog.csdnimg.cn/blog_migrate/0d8d3fa500818d5c76abaca55bc94085.png)
启动
在nacos/bin目录中,输入命令启动Nacos:
sh startup.sh -m standalone
关闭
sh shutdown.sh
1.2Nacos服务分级存储模型
![](https://i-blog.csdnimg.cn/blog_migrate/8ae0da43628b657ab71764cf3a090cc5.png)
微服务互相访问时,应该尽可能访问同集群实例,因为本地访问速度更快。当本集群内不可用时,才访问其它集群
![](https://i-blog.csdnimg.cn/blog_migrate/a74c45308b2dca49d4532cea386128c8.png)
在消费者中设置负载均衡的IRule为NacosRule,这个规则优先会寻找与自己同集群的服务
1.3NacosRule的负载均衡策略
-
优先选择同集群服务实例列表
-
本地集群找不到提供者,才去其它集群寻找,并且会报警告
-
确定了可用实例列表后,再采用随机负载均衡挑选实例
1.4加权负载均衡
实际部署中会出现这样的场景:
服务器设备性能有差异,部分实例所在机器性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求。
Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高
①Nacos控制台可以设置实例的权重值,0~1之间
②同集群内的多个实例,权重越高被访问的频率越高
③权重设置为0则完全不会被访问
1.5环境隔离
适用于开发、生产、测试不同环境的变化,我们可以把业务相关度比较高的放到同一个group中,比如订单和支付
![](https://i-blog.csdnimg.cn/blog_migrate/deeec9739ee20b46f79c16f29b48507c.png)
①每个namespace都有唯一id
②服务设置namespace时要写id而不是名称
③不同namespace下的服务互相不可见
1.6Nacos与Eureka的相同点以及区别
![](https://i-blog.csdnimg.cn/blog_migrate/633a0fea27418174685d10add0a48c66.png)
相同点
①都支持服务注册和服务拉取
②都支持服务提供者心跳方式做健康检测
区别
①Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
②Nacos里有临时实例和非临时实例,临时实例心跳不正常会被剔除,非临时实例则不会被剔除
③Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
④Nacos集群默认采用AP方式(强调数据的可用性),当集群中存在非临时实例时,采用CP模式(强调数据的可靠性和一致性);Eureka采用AP方式
六.Nacos配置管理
1.1配置管理和配置拉取
![](https://i-blog.csdnimg.cn/blog_migrate/1e3bbe5f0e18852865cfd8df64f1aeb2.png)
①在Nacos中添加配置文件
②在微服务中引入nacos的config依赖
③在微服务中添加bootstrap.yml(bootstrap.yaml文件,会在application.yml之前被读取),配置nacos地址、当前环境、服务名称、文件后缀名。这些决定了程序启动时去nacos读取哪个文件
![](https://i-blog.csdnimg.cn/blog_migrate/dfef5f8879a932c79d58c7b5a4855cac.png)
如果当前环境不是public,还需要在bootstrap.yml文件的spring.cloud.nacos.config.namespace:配置上命名空间的id
1.2配置热更新
Nacos配置更改后,微服务可以实现热更新,方式:
①通过@Value注解注入,结合@RefreshScope来刷新
②通过@ConfigurationProperties注入,自动刷新(推荐)
注意事项:
不是所有的配置都适合放到配置中心,维护起来比较麻烦
建议将一些关键参数,需要运行时调整的参数放到nacos配置中心,一般都是自定义配置
1.3多环境配置共享
微服务会从nacos读取的配置文件:
①[服务名]-[spring.profile.active].yaml,环境配置,
例如:userservice-dev.yaml
②[服务名].yaml,默认配置,多环境共享
例如:userservice.yaml
无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件
多种配置的优先级:
![](https://i-blog.csdnimg.cn/blog_migrate/5b56a5a4670ca1d2d2052bdd441dcd0b.png)
1.4多服务共享配置
不同微服务共享的配置文件:
①通过shared-configs指定
②通过extension-configs指定
例如:
![](https://i-blog.csdnimg.cn/blog_migrate/954e4d6864b920fb7a1a5034e91213de.png)
多种配置的优先级:
![](https://i-blog.csdnimg.cn/blog_migrate/ce4e224f45274ea5c07b049a109b4994.png)
1.5Nacos集群搭建
①搭建MySQL集群并初始化数据库表
②修改集群配置(节点信息)、数据库配置
③分别启动多个nacos节点
④nginx反向代理
七.Feign远程调用
Feign集成了Ribbon。Feign是一个基于HTTP协议的轻量级的RESTful风格的RPC框架,它可以让开发人员像调用本地方法一样调用远程服务,从而简化了分布式系统中服务调用的复杂度。在Feign中,它默认集成了Ribbon作为负载均衡器,通过Ribbon可以实现对服务实例的选择和流量分配。
1.1使用Feign远程调用
①引入依赖
②添加@EnableFeignClients注解
③编写FeignClient接口
④使用FeignClient中定义的方法代替RestTemplate
1.2自定义配置
![](https://i-blog.csdnimg.cn/blog_migrate/257541bee96807fc94939fea63294607.png)
一般我们需要配置的就是日志级别:
①方式一是配置文件,feign.client.config.xxx.loggerLevel
如果xxx是default则代表全局
如果xxx是服务名称,例如userservice则代表某服务
②方式二是java代码配置Logger.Level这个Bean
如果在@EnableFeignClients注解声明则代表全局
如果在@FeignClient注解中声明则代表某服务
1.3Feign的性能优化
Feign底层的客户端实现:
-
URLConnection:默认实现,不支持连接池
-
Apache HttpClient :支持连接池
-
OKHttp:支持连接池
因此优化Feign的性能主要包括:
-
使用连接池代替默认的URLConnection
-
日志级别,最好用basic或none
1.4Feign常用实践
方式一:继承
![](https://i-blog.csdnimg.cn/blog_migrate/9594c90fce8577e6e1386a325d037199.png)
让controller和FeignClient继承同一接口
缺点:
-
服务紧耦合
-
父接口参数列表中的映射不会被继承
方式二:抽取(推荐)
![](https://i-blog.csdnimg.cn/blog_migrate/6db8a379e232877b3098941d035971c7.png)
将FeignClient、POJO、Feign的默认配置都定义到一个项目中,供所有消费者使用
缺点:
某个服务可能只需要调用一个或几个api却需要引入所有的
1.5Feign和Dubbo的区别
Feign和Dubbo都是用于远程调用的框架,但它们有不同的特点和适用场景。
-
Feign是一个基于HTTP协议的轻量级RESTful风格的远程调用框架,适用于微服务架构中的服务间通信,常用于实现基于HTTP协议的API接口调用。它的优点是简单易用,易于开发和维护。使用Feign可以避免手写HTTP请求和解析响应的繁琐工作,同时也可以充分利用HTTP协议的特性,如缓存、压缩、负载均衡等。
-
Dubbo是一个基于RPC协议的远程调用框架,适用于传统的分布式架构中的服务间通信。它的优点是性能高,支持多种协议和序列化方式,可以满足大规模高并发的场景需求。使用Dubbo可以实现服务的注册和发现、负载均衡、容错等功能。
如果应用是基于微服务架构的,且通信协议采用HTTP协议,那么使用Feign会更加方便快捷。如果应用是需要高性能和高并发,且通信协议支持RPC协议,那么使用Dubbo会更加适合。
八.Gateway统一网关
1.1网关的作用
-
对用户请求做身份认证、权限校验
-
将用户请求路由到微服务,并实现负载均衡
-
对用户请求做限流
网关的技术实现
在SpringCloud中网关的实现包括两种:
-
gateway
-
zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
1.2网关搭建与路由配置
网关搭建步骤:
1.创建项目,引入nacos服务发现和gateway依赖
2.配置application.yml,包括服务基本信息、nacos地址、路由
路由配置包括:
1.路由id:路由的唯一标示
2.路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡,推荐使用lb
3.路由断言(predicates):判断路由的规则,
4.路由过滤器(filters):对请求或响应做处理
在Spring Cloud Gateway中,通过配置uri:lb来实现对服务的负载均衡。这种方式实际上是通过Spring Cloud LoadBalancer来实现的,它可以自动选择可用的服务实例,并进行负载均衡。Spring Cloud LoadBalancer默认集成了Ribbon作为负载均衡器,可以通过在application.properties或application.yml文件中配置Ribbon的相关属性来控制负载均衡策略。
1.3执行流程
![](https://i-blog.csdnimg.cn/blog_migrate/f0c02fd8f767699b568196b585e80cac.png)
1.4路由断言工厂Route Predicate Factory
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。例如Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的
像这样的断言工厂在SpringCloudGateway还有十几个
![](https://i-blog.csdnimg.cn/blog_migrate/0acb0f7b5dc582686af132a17c04b956.png)
1.5路由过滤器
![](https://i-blog.csdnimg.cn/blog_migrate/56c9f2cb0c28870599c56fc34b3a888c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7945b59b9745599fa267b99903bc9445.png)
默认过滤器
如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth
全局过滤器
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
区别在于GatewayFilter通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现。定义方式是实现GlobalFilter接口。
![](https://i-blog.csdnimg.cn/blog_migrate/c618c2bf92cf2bdc066153ad90784889.png)
过滤器执行顺序
![](https://i-blog.csdnimg.cn/blog_migrate/5e96ab087d805ecdeec116f512968a9c.png)
-
每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
-
GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
-
路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
-
当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。
![](https://i-blog.csdnimg.cn/blog_migrate/f86ac77e880be2b791c81eab53072a62.png)
1.6cors跨域配置
跨域:域名不一致就是跨域,主要包括:
域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
域名相同,端口不同:localhost:8080和localhost8081
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方案:CORS,在gateway服务的application.yml文件中,添加下面的配置:
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
1.7限流过滤器
限流:对应用服务器的请求做限制,避免因过多请求而导致服务器过载甚至宕机。限流算法常见的包括四种:
-
计数器算法,又包括窗口计数器算法、滑动窗口计数器算法
-
漏桶算法(Leaky Bucket)
-
令牌桶算法(Token Bucket)