Sprint Cloud
常用组件表
功能 | 组件 |
---|---|
服务的注册和发现 | eureka、nacos、consul |
服务的负载均衡 | ribbon、dubbo |
服务的相互调用 | openFeign、dubbo |
服务的容错 | hystrix、sentinel |
服务网关 | gateway、zuul |
服务配置的统一管理 | config-server、nacos、apollo |
服务消息总线 | bus |
服务安全组件 | security、Oauth2.0 |
服务监控 | admin、jvm |
链路追踪 | sleuth+zipkin |
服务注册与发现
eureka
@EnableEurekaClients与@EnableEurekaServer
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
fetch-registry: false # 应用是否去拉取服务列表到本地,要不要去注册中心获取其他服务的地址 , 解决eureka启动时报错
registry-fetch-interval-seconds: 10 # 为了环节服务列表的脏读问题,时间越短脏读越少,性能消耗大
register-with-eureka: true # 是否当前客户端要注册到eureka
service-url:
defaultZone: http://localhost:8761/eureka # 注册的目标服务器
server:
eviction-interval-timer-in-ms: 10000 # 服务端间隔多少毫秒做定期删除操作
renewal-percent-threshold: 0.85 # 续约百分比,超过85%的应用没有续约,那么eureka会保护服务,不会删除一个服务
instance:
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port} # 实例对象的id
hostname: localhost #主机名称或者服务的ip
prefer-ip-address: true # 以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 5 # 服务实例的续约的时间间隔
nacos
nacos install
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DYUXQHAy-1655741309620)(https://cdn.jsdelivr.net/gh/l1727894442/image/20220620160613.png)]
-
解压后进入目录打开cmd运行命令
startup.cmd -m standalone
- 配置修改
通过修改conf/application.properties文件来修改nacos的配置
服务注册
注意:加入eureka依赖一定要去掉,否则运行会有冲突(就算没有使用到eureka)
-
加入@EnableDiscoveryClient注解
-
spring: application: name: provider cloud: nacos: server-addr: localhost:8848
临时实例与非临时实例
spring.cloud.nacos.discovery.ephemeral=false #设置为非临时实例,默认为临时实例
nacos与eureka
![](https://cdn.jsdelivr.net/gh/l1727894442/image/20220620170913.png)
负载均衡与组件调用
Ribbon
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具
帮我们发送一个远程调用,同时完成负载均衡的任务
有两种使用方法
- 和RestTemplate结合使用
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
//全局负载均衡
@Bean
public IRule getIrule(){
return new RandomRule();
}
// 使用
@Resource
RestTemplate restTemplate;
// ribbon会根据serviceName部分来替换ip和port,替换信息在服务注册
// fetch-registry: true拉取服务列表信息到本地
// 当有多个同样的serviceName服务注册时,ribbon会使用负载均衡交替调用服务
restTemplate.getForObject("http://{serviceName}/hello",String.class);
- 与OpenFeign相结合,OpenFeign已经默认集成了Ribbon,所以基本不怎么单独使用ribbon
更改负载均衡的算法规则
# 具体服务的算法,provider为应用名称
provider:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ribbon:
eager-load:
enabled: true # 是否懒加载,ribbon需要去eureka中获取服务列表,true就是服务一开始就拉取服务列表
eureka:
enabled: true
http: # 我们使用restTemplate发送请求,java原生java.net.HttpUrlConnection发的请求,但不支持连接池
client: # 发请求的工具很多,如httpClient,他支持连接池,效率更好,如果你想改请求的工具,记得加这个依赖
enabled: true
okhttp: # 这也是请求工具,移动端用的比较多,轻量级的请求
enabled: true
nacos
集群
集群是nacos特有的功能,在设置集群后,我们的服务调用会优先本地集群,在本地集群中随机访问
spring:
application:
name: provider
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: 集群名 # 一般为机房位置
# 要使用nacos的集群功能,我们要修改负载均衡的规则
# 具体服务的算法,provider为应用名称
provider:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
命名空间
使用命名空间后,不同的命名空间的服务会环境隔离,不能互相调用
spring:
application:
name: provider
cloud:
nacos:
server-addr: localhost:8848
discovery:
namespace: [如下,是命名空间的id] #命名空间设置
OpenFeign
-
启动项上加注解@EnableFeignClients
-
创建接口并加入注解
@FeignClient(value="[服务的应用名称]")
public interface UserOrderFeign{
//这里填写要调用的应用的controller方法的签名
//ps如下
@GetMapping("/obj")
public Object getObject(@RequestParam String a);//这里最好不要直接传Date类,时间会有改变
}
- 自动注入接口类,调用方法即可实现远程调用
ribbon:
ReadTimeout: 3000 # 给3s超时时间
ConnectTimeout: 3000 # 链接服务的超时时间
日志配置
feign.client.config.xxx.loggerLevel=basic
#xxx是default就是全局
#是服务名就是代表某个服务
feign连接池
feign-api依赖
服务配置
nacos
配置获取的一般流程:
- 通过nacos服务器添加配置
- 加入nacos config依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
- 在服务的Resource中创建bootstrap.yml,他的优先级高于application.yml
# application里的同样配置不写
# 通过spring.application.name spring.profiles.active spring.cloud.nacos.config.file-extension来定位nacos的服务器配置
spring:
application:
name: userserver
profiles:
active: dev # 环境
cloud:
nacos:
config:
file-extension: yaml # 文件后缀名
discovery:
server-addr: localhost:8848
由于spring-cloud-dependencies 2020.0.0 版本不在默认加载bootstrap 文件,如果需要加载bootstrap 文件需要手动添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
配置自动更新
方法一:
在@Value注解上的类中加入@RefreshScope注解就能启动热更新
方法二:
使用@ConfigurationProperties注解把配置属性注入到一个类的属性中,要用的地方调用这个类的Bean 对象
多环境配置
在配置了application.name profiles.active nacos.config.file-extension后
不但会读取服务名-profile.yaml,后面也会读取服务名.yaml
也就是说设置不同的profiles.active后的同名服务都会读取这个配置文件
这么多配置文件,他们同时设置了一个属性,那么以谁的为准呢?优先级如下图
服务容错
Hystrix
- 加入maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- @FeignClient注解fallback属性指定熔断类
@FeignClient(value="[服务的应用名称]",fallback=UserOrderFeignHystrix.class)
public interface UserOrderFeign{
//这里填写要调用的应用的controller方法的签名
//ps如下
@GetMapping("/obj")
public Object getObject(@RequestParam String a);//这里最好不要直接传Date类,时间会有改变
}
- 写一个@FeignClient注解的接口实现类,重写方法即可
@Componet
public class UserOrderFeignHystrix implements UserOrderFeign{
//这里填写要调用的应用的controller方法的签名
//ps如下
@Override
public Object getObject(@RequestParam String a){
return new Object();
}
}
- 加入配置
feign:
hystrix:
enable: true
hystrix:
command:
default: # default是全局控制,也可以换成单个方法控制,吧default换成方法名即可
circuitBreaker:
enable: true # 开启断路器
requestVolumeThreshold: 3 # 失败次数(阈值)
sleepWindowInMilliseconds: 20000 # 窗口时间
errorThresholdPercentage: 60 # 失败率
executino:
isolation:
Strategy: semaphore # 隔离方式 thread线程隔离集合和semaphore信号量隔离级别
thread:
timeoutInMilliseconds: 3000 # 调用超时时间
fallback:
isolation:
semaphore:
maxConcurrentRequests: 1000 # 信号量隔离级别最大并发量
链路追踪
sleuth+zipkin
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1 # 配置采样率,默认为0.1,只在0-1之间,1表示全部采集
rate: 10 # 选择美妙间隔接受的trace量,最小数字为0
服务网关
gateway
spring:
application:
name: gateway-server
cloud:
nacos:
server-addr: localhost:8848
gateway:
enabled: true
routes:
- id: login-service-route # 路由id,保持唯一即可
uri: http://localhost:8080 # uri统一资源定位符
#uri: lb://userserver
predicates:
- Path=/login/** # 匹配规则,只要匹配上了/login就往uri转发
- After/Before/Between=2022-03-22T09:43:55.521+08:00[Asia/Shanghai] //在指定日期之后才能访问
- Method=GET,POST
- Query=name,[0-9]{3}
default-filters:
- AddRequestHeader=truth,xxx
discovery:
locator:
enabled: true # 开启动态路由,通过应用名称,找到服务的功能
lower-case-service-id: true # 开启服务名称小写
跨域问题
过滤器
过滤器执行顺序
过滤器执行顺序
- 每一个过滤器都必须指定一个int类型的orderf值,orderf值越小,优先级越高,执行顺序越靠前。
- GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
- 路由过滤器和defaultFilter的orderE由Spring指定,默认是按照声明顺序从1递增。
- 当过滤器的orderf值一样时,会按照defaultFilter>路由过滤器>GlobalFilter的顺序执行。
@Configuration
public class DemogatewayApplication {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/get")
.uri("http://httpbin.org"))
.route("path_route", r -> r.path("/get")
.uri("lb://login-server"))
.route("host_route", r -> r.host("*.myhost.org")
.uri("http://httpbin.org"))
.route("rewrite_route", r -> r.host("*.rewrite.org")
.filters(f -> f.rewritePath("/foo/(?<segment>.*)", "/${segment}"))
.uri("http://httpbin.org"))
.route("hystrix_route", r -> r.host("*.hystrix.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd")))
.uri("http://httpbin.org"))
.route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org")
.filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback")))
.uri("http://httpbin.org"))
.route("limit_route", r -> r
.host("*.limited.org").and().path("/anything/**")
.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
.uri("http://httpbin.org"))
.build();
}
}
全局过滤器
nacos集群搭建
- 进入conf目录将cluster.conf.example改为cluster.conf
- 填入所有的nacos结点信息
- 修改application.properties
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=nacos
db.password.0=nacos
- 把上面配置的数据库建好,使用conf目录下的nacos-mysql.sql文件配置
- 多份端口互不相同但配置相同的nacos一起启动
startup.cmd
- 通过nginx反向代理
upstream nacos_cluster{
server localhost:8848;
server localhost:8849;
server localhost:8850;
}
server{
listen 80;
server_name localhost;
location /nacos{
proxy_pass http://nacos_cluster;
}
}