# spring-cloud-nacos **Repository Path**: shang2-8-5/spring-cloud-nacos ## Basic Information - **Project Name**: spring-cloud-nacos - **Description**: springCloud+nacos整合 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-10-12 - **Last Updated**: 2023-11-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # spring-cloud-nacos ## 父依赖 ```xml com.alibaba.cloud spring-cloud-alibaba-dependencies 2.2.5.RELEASE pom import ``` ## 子模块依赖 ```xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery ``` ## yml 配置 ```yml spring: cloud: nacos: server-addr: localhost:8848 # nacos服务地址 ``` # Nacos 服务分级存储模型 * 一级是服务: 例如userserver * 二级是集群: 例如:上海,杭州 * 三级是实例,例如杭州机房的某台部署了userserver的服务器 ## 服务跨集群调用问题: 服务调用尽可能选择本地集群的服务,跨集群调用延迟较高本地集群不可访问时,再去访问其他集群 ## 服务集群属性 修改application.yml添加以下内容 ```yml spring: cloud: nacos: server-addr: localhost:8848 # nacos服务地址 discovery: cluster-name: HZ # 配置集群名称,也就是机房位置 ``` 将order-server中设置负载均衡的IRule为NacosRule,这个规则优先会寻找与自己同集群的服务 ```yml userserver: ribbon: NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则 ``` ## 根据权重负载均衡 实际部署中会出现这样的场景:
* 服务器设备性能有差异,部分实例所在及其性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求
Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高权重(0~1之间) ![](image/img.png) ## 环境隔离 - namespace Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离 ![](image/img_1.png) 修改order-server的application.yml,添加namespace: ```yml spring: cloud: nacos: server-addr: localhost:8848 # nacos服务地址 discovery: cluster-name: HZ # 配置集群名称,也就是机房位置 namespace: # 填写命名空间: 填ID ``` *不同namespace下的服务不可见* ## Nacos与Eureka对比 1. Nacos与Eureka的共同点 * 都支持服务注册和服务拉取 * 都支持服务提供者心跳方式做健康检测 2. Nacos与Eureka的区别 * Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式 * 临时实例心跳不正常会被剔除,非临时实例则不会被剔除 * Nacos支持服务列表变更的消息推送模式,服务列表更新更及时 * Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式,Eureka采用AP方式 # Nacos 统一配置管理 ![](image/img_2.png) 配置获取步骤 ![](image/img_3.png) 1. 引入Nacos的配置管理客户端依赖(导入到需要在nacos配置的模块) ```xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config org.springframework.cloud spring-cloud-starter-bootstrap 3.0.1 ``` 2. 在微服务中添加bootstrap.yml配置文件,配置nacos地址,当前环境,服务名称,文件名和后缀。这些决定了程序启动时去nacos读取哪个文件 ```yml spring: application: name: userserver profiles: active: dev # 环境 cloud: nacos: server-addr: localhost:8848 # Nacos地址 config: file-extension: yaml # 文件后缀名 ``` ## 配置自动更新 1. 在相关类上添加注解 @RefreshScope 2. 使用@ConfigurationProperties注解 ```java @Component @Data @ConfigurationProperties(prefix = "pattern") public class PatternProperties{ private String dateformat; } ``` ## 多环境配置共享 多种配置的优先级:
服务名-profile.yaml -> 服务名.yaml > 本地配置
当前环境配置 优先级高于 nacos中的配置 优先级高于 本地配置
## 集群搭建步骤: 1. 搭建MySQL集群并初始化数据库表 2. 下载解压nacos 3. 修改集群配置(节点信息),数据库配置 4. 分别启动多个nacos节点 5. nginx反向代理 # Feign 使用步骤 1. 引入依赖 ```xml org.springframework.cloud spring-cloud-starter-openfeign ``` 2. 在项目启动类中添加@EnableFeignClients注解 3. 编写FeignClient接口 ```java @FeignClient("userserver") public interface UserClients { @GetMapping("/user/{id}") User findById(@PathVariable("id") Long id); } ``` 4. 使用FeignClient中定义的方法代替RestTemplate ```java public Order queryOrderById(Long orderId){ Order order = orderMapper.findById(orderId); // 用feign远程调用 User user = userClients.findById(order.getUserId()); order.setUser(user); return order; } ``` ## Feign的自定义配置 ![](image/img_4.png) ### 配置Feign日志有两种方式 方式一:配置文件方式
1. 全局生效 ```yaml # Feign日志配置 feign: client: config: default: loggerLevel: FULL ``` 方式二:代码方式先声明一个Bean ```java @Bean public Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } // 1. 而后如果是全局配置,则把他放到@EnableFeignClients注解中 @EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class) // 2. 如果是局部配置,则把他放到@FeignClient注解中 @FeignClient(value = "userserver", configuration = FeignClientConfiguration.class) ``` ## Feign的性能优化 Feign底层的客户端实现 * URLConnection:默认实现,不支持连接池 * Apache HttpClient:支持连接池 * OKHttp:支持连接池 因此优化Feign的性能主要包括:
1. 使用连接池代替默认的URLConnection 2. 日志级别,最好用basic或none ### Feign 添加HttpClient的支持 引入依赖 ```xml io.github.openfeign feign-httpclient ``` 配置文件 ```yaml # 开启httpClient配置 httpclient: enabled: true #支持httpClient开关 max-connections: 200 # 最大连接数 max-connections-per-route: 50 # 单个路径的最大连接数 ``` Feign的优化: * 日志级别尽量用basic * 使用HttpClient或者OKHttp代替URLConnection * * 引入feign-httpClient依赖 * * 配置文件开启httpClient功能,设置连接池参数 ## Feign的最佳实践 ![](image/img_5.png) spring官方不推荐使用 ![](image/img_6.png) ### 实现方式二--- 抽取FeignClient--->feign-api模块 实现最佳实践方式二的步骤如下:
1.首先创建一个module,命名为feign-api,然后引入feign的starter依赖
2.将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
3.在order-service中引入feign-api的依赖
4.修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包
5.重启测试
![](image/img_7.png) 推荐第二种 # 统一网关Gateway 网关功能: * 身份认证和权限校验
* 服务路由,负载均衡
* 请求限流
![](image/img_8.png) ## 搭建网关步骤 1. 创建新的module,引入SpringCloudGateway依赖和Nacos的服务发现依赖 ```xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.cloud spring-cloud-starter-gateway ``` 2. 编写路由配置及其nacos地址 ```yaml server: port: 10010 # 网关端口 spring: application: name: gateway # 服务名 cloud: nacos: server-addr: localhost:8848 # nacos地址 # gateway配置 gateway: routes: # 网关路由配置 - id: user-server # 路由id,自定义主要是唯一即可 # uri: http://127.0.0.1:8081 # 路由的目标地址 固定地址 uri: lb://userserver # 路由的目标地址 lb就是负载均衡,后面跟服务名称 predicates: # 路由断言,也就是判断请求是否符合路由规则的条件 - Path=/user/** # 这个是按照路径匹配, 只要以/user/开头就符合要求 - id: order-server uri: lb://orderserver predicates: - Path=/order/** ``` ![](image/img_9.png) ## 路由断言工厂 * After:在指定的时间后进行路由 例如 ```yaml predicates: - After=2021-01-01T11:37:34.485+08:00[Asia/Shanghai] ``` * Before:在指定的时间进行路由 例如: ```yaml predicates: - Before=2021-01-01T11:37:34.485+08:00[Asia/Shanghai] ``` * Between:在指定的两个时间之间进行路由 例如: ```yaml predicates: - Between=2021-01-01T11:37:34.485+08:00[Asia/Shanghai], 2021-01-07T11:37:34.485+08:00[Asia/Shanghai] ``` * Cookie:cookie匹配 例如: ```yaml predicates: - Cookie=username, zhangsan ``` * Header:请求头匹配 例如: ```yaml predicates: - Header=X-Request-Id, \d+ ``` * Host:请求主机地址 例如: ```yaml predicates: - Host=**.abc.org, **.xyz.org ``` * Method:请求方式 例如: ```yaml predicates: - Method=GET ``` * Path:请求路径 例如: ```yaml predicates: - Path=/foo/{segment} ``` * Query:请求参数 例如: ```yaml predicates: - Query=myParam, \d+ ``` * RemoteAddr:IP地址 例如: ```yaml predicates: - RemoteAddr=192.168.1.1/24 ``` * Weight:路由权重处理 例如: ```yaml predicates: - Weight=group1, 5 - Weight=group2, 10 ``` ## 路由过滤器 GatewayFilter ![](image/img_10.png) 给所有进入userserver的请求加一个请求头 ```yaml // 实现方法 ## 添加过滤 # filters: # - AddRequestHeader=Truth, XYZ - id: order-server uri: lb://orderserver predicates: - Path=/order/** # 全局过滤配置 default-filters: - AddRequestHeader=Truth,ABC ``` 过滤器的作用是什么?
对路由的请求或响应做加工处理,比如添加请求头配置在路由下的过滤器只对当前路由的请求生效
defaultFilters的作用是什么?
对所有路由生效的过滤器,比如添加请求头配置在defaultFilters下过滤器对所有路由的请求都生效
### 全局过滤器GlobalFilter ![](image/img_11.png) ```java @Component //@Order(-1) // 优先级 public class AuthorizeFilter implements GlobalFilter, Ordered { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 1. 获取请求参数 ServerHttpRequest request = exchange.getRequest(); MultiValueMap params = request.getQueryParams(); // 2. 获取参数中的authorization 参数 String auth = params.getFirst("authorization"); // 3. 判断参数值是否等于 admin if ("admin".equals(auth)){ // 4. 是 放行 return chain.filter(exchange); } exchange.getResponse().setRawStatusCode(401); // 5. 否拦截 return exchange.getResponse().setComplete(); } // 优先级 @Override public int getOrder() { return -1; } } ``` 全局过滤器的作用是什么?对所有路由都生效的过滤器,并且可以自定义处理逻辑
实现全局过滤器的步骤?
* 实现GlobalFilter接口 * 添加@Order注解或实现Ordered接口 * 编写处理逻辑 ### 过滤器的执行顺序 ![](image/img_12.png) ### 跨域问题处理 ```yaml spring: cloud: gateway: globalcors: add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题 corsConfigurations: '[/**]': allowedOrigins: # 允许哪些网站的跨域请求 # - "http://localhost:8080" - "*" allowedMethods: # 允许的跨域的ajax的请求方式 - "GET" - "POST" - "PUT" - "DELETE" - "OPTIONS" allowedHeaders: "*" # 允许在请求中携带的头信息 exposedHeaders: true # 是否允许请求中携带cookie maxAge: 36000 # 这次跨域检测的有效期 ```