概述
本文Spring Boot
使用的2.6.3版本
官方文档:https://spring.io/projects/spring-cloud
本文代码示例:https://gitee.com/psvmc/soa-demo
SpringCloud是微服务的集大成者,里面包含了很多技术,而现在SpringCloud进行了一次大更新,很多技术现在已经不再使用,有了别的替代方案。
最后的一行是推荐的方案。
目前我的选择的组合为
- 注册中心 Eureka
- 网关 Getway
- 熔断器 Resilience4j
- 配置中心 Config
配置中心之所以不用Nacos是因为不支持SpringBoot2.6.3。
项目的基本结构
创建项目
接下来我们的注册中心,服务和网关都添加Module即可
选择
注册中心
注册中心添加以下组件
配置文件
1 | server.port=8080 |
注册中心
服务
注意
服务名中支持中划线,如
s-uer
服务名称中不支持下划线,也就是
s_user
这样是不行的考虑到我们最终通过网关访问是要加上服务名的,所以也不建议使用中划线,如
suer
添加依赖
服务1
实体
1 | import lombok.Data; |
控制器
1 | import cn.psvmc.s_user.model.UserModel; |
Application中添加@EnableEurekaClient
1 | import org.springframework.boot.SpringApplication; |
配置文件application.properties
1 | erver.port=8081 |
访问地址
服务2
实体
1 | import lombok.Data; |
控制器
1 | import cn.psvmc.s_book.BookModel; |
Application中添加@EnableEurekaClient
1 | import org.springframework.boot.SpringApplication; |
配置文件application.properties
1 | server.port=8082 |
访问地址
网关
配置文件application.yml
1 | server: |
Application中添加@EnableEurekaClient
1 | import org.springframework.boot.SpringApplication; |
允许跨域
1 |
|
注意:
不配置会出现访问跨域问题。
后端的跨域配置可以去掉也可以不去。
网关访问报错
错误如下
java.net.UnknownHostException: Failed to resolve ‘izhp377icw6ku0oh6tzh27z’
这是因为注册中心中保存的是hostname而不是对应的IP
查看
1 | echo $HOSTNAME |
返回的就是izhp377icw6ku0oh6tzh27z
,所以说网关不能根据hostname找到对应IP了。
解决方法,在网关所在计算机上添加映射
1 | vi /etc/hosts |
添加
1 | 127.0.0.1 izhp377icw6ku0oh6tzh27z |
注意我这里是本机,所以用的127.0.0.1
。
熔断器
造成灾难性雪崩效应的原因,可以简单归结为下述三种:
- 服务提供者不可用。如:硬件故障、程序BUG、缓存击穿、并发请求量过大等。
- 重试加大流量。如:用户重试、代码重试逻辑等。
- 服务调用者不可用。如:同步请求阻塞造成的资源耗尽等。
雪崩效应最终的结果就是:服务链条中的某一个服务不可用,导致一系列的服务不可用,最终造成服务逻辑崩溃。这种问题造成的后果,往往是无法预料的。
解决灾难性雪崩效应的方式通常有:降级、隔离、熔断、请求缓存、请求合并。
下图来自resilience4j官方文档,介绍了什么是断路器:
- CLOSED状态时,请求正常放行
- 请求失败率达到设定阈值时,变为OPEN状态,此时请求全部不放行
- OPEN状态持续设定时间后,进入半开状态(HALE_OPEN),放过部分请求
- 半开状态下,失败率低于设定阈值,就进入CLOSE状态,即全部放行
- 半开状态下,失败率高于设定阈值,就进入OPEN状态,即全部不放行
添加熔断器参数设置类
1 | import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; |
添加降级响应
1 | import org.springframework.web.bind.annotation.GetMapping; |
项目的配置更改如下:
application.yaml
1 | server: |
或者使用application.properties
1 | server.port=8083 |
注意:
discovery
和routes
是不能并存的,discovery
相当于自动生成routes
配置。- 使用
application.properties
的话配置中有些会显示为红色,不用在意,不影响使用。lb:
是从注册中心中取URI。- 注意重写路由规则,路由相当于把请求的URL替换成了我们服务的URL,这时就不再需要服务名了。
启动
启动顺序
注册中心
=>服务
=>网关
注册中心
结果如图
原服务访问地址
通过网关访问
http://localhost:8083/suser/user/detail
配置中心
服务端
添加依赖
application.properties
1 | # port |
这里设置的目录为config,所以我们的配置文件要放在git仓库里的config目录下
创建文件psvmc-dev.properties
1 | name=xiaoming |
注意配置文件名称必须按照以下规则
1 | /{application}-{profile}.properties |
访问时的路径为
1 | 域名/{application}/{profile} |
注意
其中
label
为分支名
Application中添加@EnableConfigServer
1 | import org.springframework.boot.SpringApplication; |
访问地址
http://localhost:8087/psvmc/dev
或者
注意访问地址和psvmc-dev.properties
配置文件的对应关系。
客户端
pom中添加依赖
1 | <dependency> |
不添加会报错
No spring.config.import property has been defined
原因
由于
bootstrap.properties
是系统级的资源配置文件,是用在程序引导执行时更加早期配置信息读取;
而application.properties
是用户级的资源配置文件,是用来后续的一些配置所需要的公共参数。
但是在SpringCloud 2020.*
版本把bootstrap禁用
了,导致在读取文件的时候读取不到而报错,所以我们只要把bootstrap从新导入进来就会生效了。
添加bootstrap.properties
1 | server.port=8088 |
注意
management.endpoints.web.exposure.include=refresh
这个配置是用来刷新项目配置的,添加后就会生成一个URL
http://localhost:8088/actuator/refresh
,但是注意这个URL中要添加actuator
,并且只能用POST请求
。
bootstrap.properties
的优先级比application.properties
优先级高,这里可以只保留bootstrap.properties
,application.properties
可以删掉。
添加控制器
1 | import org.springframework.beans.factory.annotation.Value; |
注意
@RefreshScope 所有加该注解的都会在调用刷新后自动更新注入的配置项,如上面示例中的
name
。
访问地址
刷新配置
使用POST请求
下面的URL
或者在命令行中运行
1 | curl -X POST "http://localhost:8088/actuator/refresh" |
打包
最外层的pom配置
1 |
|
注意其中添加的部分
模块的pom
1 | <!--编译跳过测试文件检查的生命周期--> |
注意
模块中添加该配置会跳过依赖服务的检测,否则只能在服务都启动的前提下才能打包成功。
其它
公共依赖
在创建公用依赖的时候要选择Maven模块
,不建议建SpringBoot模块
如果建的是SpringBoot项目,要修改配置
1 | <build> |