From d8ed71c4e7139d12d7161d87e40510de1f7cc7ae Mon Sep 17 00:00:00 2001 From: tim-qtp <2469100031@qq.com> Date: Wed, 1 Jan 2025 04:01:13 +0800 Subject: [PATCH] =?UTF-8?q?add:=20Eureka=20Ribbon=20Feign=20Nacos=E6=96=87?= =?UTF-8?q?=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/framework/springcloud/Feign.md | 479 +++++++++ .../Microservices with Eureka Ribbon.md | 458 +-------- src/life/README.md | 37 + src/microservices/nacos/Cluster.md | 413 ++++++++ .../nacos/Configuration Center.md | 966 ++++++++++++++++++ .../nacos/Registration Center.md | 386 +++++++ src/microservices/nacos/Strated.md | 164 +++ .../Maintenance of flash sale products.md | 168 +-- 9 files changed, 2470 insertions(+), 603 deletions(-) create mode 100644 src/framework/springcloud/Feign.md create mode 100644 src/microservices/nacos/Cluster.md create mode 100644 src/microservices/nacos/Configuration Center.md create mode 100644 src/microservices/nacos/Registration Center.md create mode 100644 src/microservices/nacos/Strated.md diff --git a/README.md b/README.md index 5f3873f..f7c558b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

『Qtp-稳重不爱吃肉』

-:rocket: 无限进步,影视飓风的座右铭! +:rocket: 无限进步,影视飓风的座右铭!
:rocket: 做技术的应该多写点技术文章,输出的同时倒逼输入! :fire: :fire: :fire: 推荐 | 在线阅读: diff --git a/src/framework/springcloud/Feign.md b/src/framework/springcloud/Feign.md new file mode 100644 index 0000000..51fbd75 --- /dev/null +++ b/src/framework/springcloud/Feign.md @@ -0,0 +1,479 @@ +--- +order: 2 +author: +title: "Feign" +category: + - SpringCloud + - Feign + + +--- + +# Feign远程调用 + + +Feign是一个声明式的Web服务客户端,它简化了使用基于HTTP的远程服务的开发。 + +Feign是在`RestTemplate`和`Ribbon`的基础上进一步封装,使用`RestTemplate`实现`Http`调用,使用`Ribbon`实现负载均衡。 + +以前利用`RestTemplate`发起远程调用的代码是这样的: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/9ca03769551f7970a73c4517d7074952.png) + +存在下面的问题: + +- 代码可读性差,编程体验不统一 + +- 参数复杂URL难以维护 + + + +Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign + +其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/0489c90e8c01db06c3e8e25c2cf26812.png) + + + +## 2.1.Feign替代RestTemplate + +Fegin的使用步骤如下: + +### 1)引入依赖 + +我们在order-service服务的pom文件中引入feign的依赖: + +```xml + + org.springframework.cloud + spring-cloud-starter-openfeign + +``` + + + +### 2)添加注解 + +在order-service的启动类添加注解开启Feign的功能: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/307c15d119cf2e8d4439add429c523d1.png) + + + +### 3)编写Feign的客户端 + +在order-service中新建一个接口,内容如下: + +```java +package cn.itcast.order.client; + +import cn.itcast.order.pojo.User; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +@FeignClient("userservice") +public interface UserClient { + @GetMapping("/user/{id}") + User findById(@PathVariable("id") Long id); +} +``` + + + +这个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如: + +- 服务名称:userservice +- 请求方式:GET +- 请求路径:/user/{id} +- 请求参数:Long id +- 返回值类型:User + +这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。 + + + + + +### 4)测试 + +修改order-service中的OrderService类中的queryOrderById方法,使用Feign客户端代替RestTemplate: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/00b3a6299b17e245b871a74014e119b7.png) + +是不是看起来优雅多了。 + + + +### 5)总结 + +使用Feign的步骤: + +① 引入依赖 + +② 添加@EnableFeignClients注解 + +③ 编写FeignClient接口 + +④ 使用FeignClient中定义的方法代替RestTemplate + + + +Feign不仅实现了远程调用,而且还是实现了负载均衡,查看依赖树: + +发现Feign集成了Ribbon + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/6c025066755ee2d737bf4964649ddcab.png) + + + +## 2.2.自定义配置 + +Feign可以支持很多的自定义配置,如下表所示: + +| 类型 | 作用 | 说明 | +| ---------------------- | ---------------- | ------------------------------------------------------ | +| **feign.Logger.Level** | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL | +| feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 | +| feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 | +| feign.Contract | 支持的注解格式 | 默认是SpringMVC的注解 | +| feign.Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 | + +一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可。 + + + +下面以日志为例来演示如何自定义配置。 + +### 2.2.1.配置文件方式 + +基于配置文件修改feign的日志级别可以针对单个服务: + +```yaml +feign: + client: + config: + userservice: # 针对某个微服务的配置 + loggerLevel: FULL # 日志级别 +``` + +也可以针对所有服务: + +```yaml +feign: + client: + config: + default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置 + loggerLevel: FULL # 日志级别 +``` + + + +而日志的级别分为四种: + +- NONE:不记录任何日志信息,这是默认值。 +- BASIC:仅记录请求的方法(GET),URL(http://userservice/user/1), 请求协议(HTTP /1.1),以及响应状态码(200)和执行时间(4ms) +- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息 +- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。 + + + +### 2.2.2.Java代码方式 + +也可以基于Java代码来修改日志级别,先声明一个类,然后声明一个Logger.Level的对象: + +```java +public class DefaultFeignConfiguration { + @Bean + public Logger.Level feignLogLevel(){ + return Logger.Level.BASIC; // 日志级别为BASIC + } +} +``` + + + +如果要**全局生效**,将其放到启动类的@EnableFeignClients这个注解中: + +```java +@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class) +``` + + + +如果是**局部生效**,则把它放到对应的@FeignClient这个注解中: + +```java +@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class) +``` + + + + + + + +## 2.3.Feign使用优化 + +> Feign是声明式客户端,它只是把我们的==请求(声明)==变成HTTP请求,最终发http请求时,还是会用到别的一些组件 + +Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括: + +- URLConnection:默认实现,==不支持连接池== + +- Apache HttpClient :支持连接池 + +- OKHttp:支持连接池 + + + +因此提高Feign的性能主要手段就是使用**连接池**代替默认的URLConnection。 + + + +这里我们用Apache的HttpClient来演示。 + +1)引入依赖 + +在order-service的pom文件中引入Apache的HttpClient依赖: + +> 这个依赖已经被spring管理起来了,所以我们不需要管版本,只需要引就可以了 + +```xml + + + io.github.openfeign + feign-httpclient + +``` + + + +2)配置连接池 + +在order-service的application.yml中添加配置: + +```yaml +feign: + client: + config: + default: # default全局的配置 + loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息 + httpclient: + enabled: true # 开启feign对HttpClient的支持 + max-connections: 200 # 最大的连接数 + max-connections-per-route: 50 # 每个路径的最大连接数 +``` + + + +接下来,在FeignClientFactoryBean中的loadBalance方法中打断点: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/abb4e264235626581d4acd6ad80e2246.png) + +Debug方式启动order-service服务,可以看到这里的client,底层就是Apache HttpClient: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/f2912662f4a0ec6592e3ed4684ed7590.png) + + + + + + + +总结,Feign的优化: + +1.日志级别尽量用basic + +2.使用HttpClient或OKHttp代替URLConnection + +① 引入feign-httpClient依赖 + +② 配置文件开启httpClient功能,设置连接池参数 + + + +## 2.4.最佳实践 + +所谓最佳实践,就是使用过程中总结的经验,最好的一种使用方式。 + +仔细观察可以发现,Feign的客户端与服务提供者的controller代码非常相似: + +feign客户端: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/868de537e2ea78ec9253c13d9ea6de98.png) + +UserController: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/2c856eda05dabb96737f3ccb1ff4b4cc.png) + + + +有没有一种办法简化这种重复的代码编写呢? + +==上面这个接口最终的目的是什么:== + +==是让消费者基于声明的信息,去发送一次HTTP的请求,最终这个请求到哪里啊?== + +==是不是一定会到达,这个`userservice`服务对应的一个实例,最后到达`userservice`的`UsreController`。== + + + +### 2.4.1.继承方式 + +一样的代码可以通过继承来共享(**契约编程**): + +1)定义一个API接口,利用定义方法,并基于SpringMVC注解做声明。 + +2)Feign客户端和Controller都集成该接口 + + + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/678b00f03852a3f4bc6988db97c3f7bc.png) + + + +优点: + +- 简单 +- 实现了代码共享 + +缺点: + +- 服务提供方、服务消费方紧耦合 + +- 参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表、注解 + + + + + +### 2.4.2.抽取方式 + +将Feign的Client抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用。 + +例如,将UserClient、User、Feign的默认配置都抽取到一个feign-api包中,所有微服务引用该依赖包,即可直接使用。 + +> UserController对外暴露了查询用户的接口,这两个微服务都想要去查询用户,以前是你写你的Client,我写我的Client; +> +> 但是将来我的微服务越来越多,十几个都来调UserService,那这个client是不是等于写了十多遍了; +> +> 重复开发 + + + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/a0097cfc1bdf63ca19f39b45d22b39f6.png) + +> Feign调用的过程中,是不是会创建实体类,那我也帮你们定义好,省的你俩都得写实体类; +> +> 是不是以后还要写配置啊,你们也不用配了,我帮你们做一个默认配置; +> +> 这里接口肯定也不只一个,全都给你定义进来; +> +> 以后怎么用呢?引依赖,导jar包; + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/d3bb46f8036d46c75b624e947da02335.png) + + + + + +### 2.4.3.实现基于抽取的最佳实践 + +#### 1)抽取 + +首先创建一个module,命名为feign-api: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/23f76cb08518bd37325c4f14205021f2.png) + +项目结构: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/597ffbe46c831157b7f619d53144d7d8.png) + +在feign-api中然后引入feign的starter依赖 + +```xml + + org.springframework.cloud + spring-cloud-starter-openfeign + +``` + + + +然后,order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/6477e2dfa1f553ca89185076a75c7f38.png) + + + +#### 2)在order-service中使用feign-api + +首先,删除order-service中的UserClient、User、DefaultFeignConfiguration等类或接口。 + + + +在order-service的pom文件中中引入feign-api的依赖: + +```xml + + cn.itcast.demo + feign-api + 1.0 + +``` + + + +修改order-service中的所有与上述三个组件有关的导包部分,改成导入feign-api中的包 + + + +#### 3)重启测试 + +重启后,发现服务报错了: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/b3b8266f3ea03a95891ba095c4e4bb57.png) + +这是因为UserClient现在在cn.itcast.feign.clients包下,、 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/1429b38a0ced32853e95205ecfe15253.png) + +没有报错只是因为确实有这个类,但是没有被注册进spring容器; + +``` +为什么? +OrderApplication启动类扫描的是自己所在的包,也就是package cn.itcast.order; +``` + + + +#### 4)解决扫描包问题 + +方式一: + +指定Feign应该扫描的包: + +```java +@EnableFeignClients(basePackages = "cn.itcast.feign.clients") +``` + + + +方式二: + +指定需要加载的Client接口(**各种各样的**): + +```java +@EnableFeignClients(clients = {UserClient.class}) +``` + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/a7e707f5cc22e8a1ae02e742ace28f3d.png) + +成功! + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/d33e47e1a0e2bcd36771ebe0e22cdfaa.png) + + + diff --git a/src/framework/springcloud/Microservices with Eureka Ribbon.md b/src/framework/springcloud/Microservices with Eureka Ribbon.md index 7845fb5..cb8d03d 100644 --- a/src/framework/springcloud/Microservices with Eureka Ribbon.md +++ b/src/framework/springcloud/Microservices with Eureka Ribbon.md @@ -1,7 +1,7 @@ --- order: 1 author: -title: "【微服务+Eureka+Ribbon】" +title: "微服务+Eureka+Ribbon" category: - SpringCloud - 微服务 @@ -449,7 +449,7 @@ eureka: 上一节中,我们添加了@LoadBalanced注解,即可实现负载均衡功能,这是什么原理呢? -### 4.1.负载均衡原理: +### 1.负载均衡原理: SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载均衡功能的。 @@ -459,7 +459,7 @@ SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载 -### 4.2.源码跟踪: +### 2.源码跟踪: 为什么我们只输入了service名称就可以访问了呢?之前还要获取ip和端口。 @@ -547,11 +547,11 @@ SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTemplate发出 - IRule利用内置负载均衡规则,从列表中选择一个,例如localhost:8081 - RibbonLoadBalancerClient修改请求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1,发起真实请求 -### 4.3.负载均衡策略 +### 3.负载均衡策略 -#### 4.3.1.负载均衡策略 +#### 3.1.负载均衡策略 负载均衡的规则都定义在IRule接口中,而IRule有很多不同的实现类: @@ -577,7 +577,7 @@ SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTemplate发出 ![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/337a05a7d5ba0e8821075143bc3a26a9.png) -#### 4.3.2.自定义负载均衡策略 +#### 3.2.自定义负载均衡策略 通过定义IRule实现可以修改负载均衡规则,有两种方式: @@ -608,7 +608,7 @@ userservice: # 给某个微服务配置负载均衡规则,这里是userservice ![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/36bb98c1f4eafe937eac0ddb2afe607d.png) -### 4.4.饥饿加载: +### 4.饥饿加载: Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。 @@ -635,7 +635,7 @@ ribbon: -### 4.5.饥饿加载: +### 5.总结 1、Ribbon负载均衡规则 @@ -651,445 +651,3 @@ ribbon: - 开启饥饿加载 - 指定饥饿加载的微服务名称 - - - -## 五、Nacos注册中心 - -国内公司一般都推崇阿里巴巴的技术,比如注册中心,SpringCloudAlibaba也推出了一个名为Nacos的注册中心。 - -### 5.1.认识和安装Nacos - -[Nacos](https://nacos.io/)是阿里巴巴的产品,现在是[SpringCloud](https://spring.io/projects/spring-cloud)中的一个组件。相比[Eureka](https://github.com/Netflix/eureka)功能更加丰富,在国内受欢迎程度较高。 - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/8627877a03c1d35d0132e99d09cdc6fe.png) - -安装方式可以参考课前资料《Nacos安装指南.md》 - -启动: - -```bash -startup.cmd -m standalone -``` - -### 5.2.服务注册到nacos - -Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说,并没有太大区别。 - -主要差异在于: - -- 依赖不同 -- 服务地址不同 - -![image-20241231121817181](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/image-20241231121817181.png) - -##### 1)引入依赖 - -在cloud-demo父工程的pom文件中的``中引入SpringCloudAlibaba的依赖: - -```xml - - com.alibaba.cloud - spring-cloud-alibaba-dependencies - 2.2.6.RELEASE - pom - import - -``` - -然后在user-service和order-service中的pom文件中引入nacos-discovery依赖: - -```xml - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - -``` - - - -> **注意**:不要忘了注释掉eureka的依赖。 - - - -##### 2)配置nacos地址 - -在user-service和order-service的application.yml中添加nacos地址: - -```yaml -spring: - cloud: - nacos: - server-addr: localhost:8848 -``` - - - -> **注意**:不要忘了注释掉eureka的地址 - - - -##### 3)重启 - -重启微服务后,登录nacos管理页面,可以看到微服务信息: - - - -### 5.3.服务分级存储模型 - -一个**服务**可以有多个**实例**,例如我们的user-service,可以有: - -- 127.0.0.1:8081 -- 127.0.0.1:8082 -- 127.0.0.1:8083 - -假如这些实例分布于全国各地的不同机房,例如: - -- 127.0.0.1:8081,在上海机房 -- 127.0.0.1:8082,在上海机房 -- 127.0.0.1:8083,在杭州机房 - -Nacos就将同一机房内的实例 划分为一个**集群**。 - -也就是说,user-service是服务,一个服务可以包含多个集群,如杭州、上海,每个集群下可以有多个实例,形成分级模型,如图: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/f6564401044a0f1674031d2d5b9d4406.png) - - - -微服务互相访问时,应该尽可能访问同集群实例,因为本地访问速度更快。当本集群内不可用时,才访问其它集群。例如: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/1c37ab0d9c7b3ce310064efc3ba214f3.png) - -杭州机房内的order-service应该优先访问同机房的user-service。 - - - - - -#### 5.3.1.给user-service配置集群 - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/1b020ab8fda94a4337c568a9309755d5.png) - -默认集群名为DEFAULT - -修改user-service的application.yml文件,添加集群配置: - -```yaml -spring: - cloud: - nacos: - server-addr: localhost:8848 - discovery: - cluster-name: HZ # 集群名称 -``` - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/1e6c32c3ec15291ba183997ff3446677.png) - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/3335d59e99a12c37674e3a7631f89c2e.png) - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/3b0aaf1bae12be169fd8c36b5f4fa939.png) - - - -#### 5.3.2.Nacos小结: - -1、Nacos服务分级存储模型 - -- 一级是服务,例如userservice -- 二级是集群,例如杭州或上海 -- 三级是实例,例如杭州机房的某台部署了userservice的服务器 - -2、如何设置实例的集群属性 - -- 修改application.yml文件,添加spring.cloud.nacos.discovery.cluster-name属性即可 - - - -#### 5.3.3.同集群优先的负载均衡 - -orderservice和userservice的8081和8082都在一个集群中了,我们希望的是orderservice,那此时呢我们希望的是other service发起远程调用时,优先选择8081和8082 - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/bc2d8995777666c8df94ccd7ceb610a0.png) - -默认的`ZoneAvoidanceRule`并不能实现根据同集群优先来实现负载均衡。 - -因此Nacos中提供了一个`NacosRule`的实现,可以优先从同集群中挑选实例。 - -***1)给order-service配置集群信息*** - -修改order-service的application.yml文件,添加集群配置: - -```sh -spring: - cloud: - nacos: - server-addr: localhost:8848 - discovery: - cluster-name: HZ # 集群名称 -``` - - - -***2)修改负载均衡规则*** - -修改order-service的application.yml文件,修改负载均衡规则: - -```yaml -userservice: - ribbon: - NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则 ,NacosRule---优先选择本地集群 -``` - -#### 5.3.4.如果配置了优先访问本地集群,那本地的多个集群都崩了会发生什么? - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/e626c7d4350f4ee02ab4a1b624ed59fd.png) - -只留一个试试。 - -```java -一次跨集群访问发生了,谁呢? userservice -想访问的是杭州,但实际是上海 -A cross-cluster call occurs,name = userservice, clusterName = HZ, instance = [Instance{instanceId='192.168.43.172#8083#SH#DEFAULT_GROUP@@userservice', ip='192.168.43.172', port=8083, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='SH', serviceName='DEFAULT_GROUP@@userservice', metadata={preserved.register.source=SPRING_CLOUD}}] - -``` - -运维人员看见警告就会处理。 - -#### 5.3.5.总结 - -NacosRule负载均衡策略 - -- 优先选择同集群服务实例列表 -- 本地集群找不到提供者,才去其它集群寻找,并且会报警告 -- 确定了可用实例列表后,再采用随机负载均衡挑选实例 - -### 5.4.权重配置 - -实际部署中会出现这样的场景: - -- 服务器设备性能有差异,部分实例所在机器性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求。 - -但默认情况下NacosRule是同集群内随机挑选,不会考虑机器的性能问题。 - - - -因此,Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高。 - - - -在nacos控制台,找到user-service的实例列表,点击编辑,即可修改权重: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/4192d335f35eff4c6d4cf09be162eb5b.png) - -在弹出的编辑窗口,修改权重: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/b211a65fc38d0425e6ab69792f771c99.png) - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/df3df2f5a92e80ad89d1ae060c15a04c.png) - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/8e5807c9f7b537bd94df1af95e43ff17.png) - -> **注意**:如果权重修改为0,则该实例永远不会被访问 - -如果一个服务想要做一个版本的升级,怎么办? 重启!王者荣耀不停服更新---部分分批更新(设权重) - -**总结:** - -> 实例的权重控制 -> -> - Nacos控制台可以设置实例的权重值,0~1之间 -> - 同集群内的多个实例,权重越高被访问的频率越高 -> - 权重设置为0则完全不会被访问 - -### 5.5.环境隔离 - -Nacos提供了namespace来实现环境隔离功能。 - -- nacos中可以有多个namespace -- namespace下可以有group、service等 -- 不同namespace之间相互隔离,例如不同namespace的服务互相不可见 - -开发/测试/生产 三种环境需要隔离 服务和配置的 - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/459a09af4f9ddbb94be4ac51b6f8afcb.png) - - - -#### 5.5.1.创建namespace - -默认情况下,所有service、data、group都在同一个namespace,名为public: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/c7ade712e06eb0395ce562c70ea8a757.png) - - - -我们可以点击页面新增按钮,添加一个namespace: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/e193a37f988088684e36bc15548a6de4.png) - - - -然后,填写表单: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/3a9563601ac8cbc3c1e4ad8cff2ce9c2.png) - -就能在页面看到一个新的namespace: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/5f6ab6500651acf4c67b1a6347b0b7be.png) - - - -#### 5.5.2.给微服务配置namespace - -给微服务配置namespace只能通过修改配置来实现。 - -例如,修改order-service的application.yml文件: - -```yaml -spring: - cloud: - nacos: - server-addr: localhost:8848 - discovery: - cluster-name: HZ - namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID -``` - - - -重启order-service后,访问控制台,可以看到下面的结果: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/684be5121966110be67f2accb3defc1e.png) - - - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/484caab3fa8b96f6673848b407a88c1a.png) - -此时访问order-service,因为namespace不同,会导致找不到userservice,控制台会报错: - -是两个世界的人了! - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/ba9db871150ba398c31c3b6d97989455.png) - -> Nacos环境隔离 -> -> - 每个namespace都有唯一id -> - 服务设置namespace时要写id而不是名称 -> - 不同namespace下的服务互相不可见 - -#### 5.6.Nacos与Eureka的区别 - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/b5d44ae7be32f5dbe38d610c79225db1.png) - -到目前为止,Nacos和Eurela没什么区别, - - - -Nacos的服务实例分为两种l类型: - -- 临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型。 - - 不写,ephemeral: false,停掉,就会等待一会儿后,nacos监测台就会爆红 - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/cb62baf822e56533b3e6d2975702a481.png) - -- 非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。 - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/6b5e436a224ca33cee40593f252b87a5.png) - -配置一个服务实例为永久实例: - -```yaml -spring: - cloud: - nacos: - discovery: - ephemeral: false # 设置为非临时实例 -``` - - - - - -Nacos和Eureka整体结构类似,服务注册、服务拉取、心跳等待,但是也存在一些差异: - -![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/cebec10ce329a95801de61f390cb98b8.png) - - - -- **Nacos与eureka的共同点** - - - 都支持服务注册和服务拉取 - - 都支持服务提供者心跳方式做健康检测 - -- **Nacos与Eureka的区别** - - - Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式 - - 临时实例心跳不正常会被剔除,非临时实例则不会被剔除(**只是把你标记为不健康**) - - Nacos支持服务列表变更的消息推送模式,服务列表更新更及时 - - Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式 - - - - **总结一下**,nacos与eureka的几点区别: - - 1、功能作用不同,nacos是一个服务注册与服务发现,而且还是一个配置中心,euraka仅仅只是一个注册中心; - - 2、心跳机制不同,nacos可以是主动询问微服务,也可以是微服务主动询问nacos,非临时实例与临时实例 - - 消费者默认每隔30秒会向注册中心拉取信息,但是服务30内挂了怎么办?这时注册中心已经监听到了不健康的服务,那消费者直接去消费就会出问题。 所以Eureka服务列表更新的频率也就比较差。 - - 有回应有主动 比渣男好多了!哈哈哈哈哈!!! - - **记忆:临时是Nacos的舔狗,Nacos是非临时的舔狗。** - -> **为什么nacos临时实例采用心跳模式,非临时实例采用主动检测模式,为什么要区别对待?** -> -> Nacos采用心跳模式来监测临时实例的健康状况,而采用主动检测模式来监测非临时实例的健康状况,原因如下: -> -> 1. 对于临时实例,由于这些实例通常是一些短暂存在于服务列表中的实例,它们的声明周期较短,因此采用心跳模式更加适合。心跳模式是通过服务提供者定期发送心跳信息告诉注册中心自己还存活着,如果一段时间内没有收到心跳信息,则认为该实例已经下线,将其从服务列表中移除。这种方式可以及时发现实例的下线,避免了误判,并且减少了对网络带宽和系统资源的占用。 - - - - - -Nacos和Eureka整体结构类似,服务注册、服务拉取、心跳等待,但是也存在一些差异: - -[外链图片转存中...(img-ilk7BFmk-1686851870407)] - - - -- **Nacos与eureka的共同点** - - - 都支持服务注册和服务拉取 - - 都支持服务提供者心跳方式做健康检测 - -- **Nacos与Eureka的区别** - - - Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式 - - 临时实例心跳不正常会被剔除,非临时实例则不会被剔除(**只是把你标记为不健康**) - - Nacos支持服务列表变更的消息推送模式,服务列表更新更及时 - - Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式 - - - - **总结一下**,nacos与eureka的几点区别: - - 1、功能作用不同,nacos是一个服务注册与服务发现,而且还是一个配置中心,euraka仅仅只是一个注册中心; - - 2、心跳机制不同,nacos可以是主动询问微服务,也可以是微服务主动询问nacos,非临时实例与临时实例 - - 消费者默认每隔30秒会向注册中心拉取信息,但是服务30内挂了怎么办?这时注册中心已经监听到了不健康的服务,那消费者直接去消费就会出问题。 所以Eureka服务列表更新的频率也就比较差。 - - 有回应有主动 比渣男好多了!哈哈哈哈哈!!! - - **记忆:临时是Nacos的舔狗,Nacos是非临时的舔狗。** - -> **为什么nacos临时实例采用心跳模式,非临时实例采用主动检测模式,为什么要区别对待?** -> -> Nacos采用心跳模式来监测临时实例的健康状况,而采用主动检测模式来监测非临时实例的健康状况,原因如下: -> -> 1. 对于临时实例,由于这些实例通常是一些短暂存在于服务列表中的实例,它们的声明周期较短,因此采用心跳模式更加适合。心跳模式是通过服务提供者定期发送心跳信息告诉注册中心自己还存活着,如果一段时间内没有收到心跳信息,则认为该实例已经下线,将其从服务列表中移除。这种方式可以及时发现实例的下线,避免了误判,并且减少了对网络带宽和系统资源的占用。 -> -> 2. 对于非临时实例,这些实例通常存在比较长的生命周期,而采用心跳模式无法保证及时发现实例的下线,因此采用主动检测模式更加适合。主动检测模式是注册中心通过发送HTTP请求或者TCP请求等方式来主动探测服务提供者的状态,以此来保证服务的可用性。这种方式可以更加精确地判断实例的状态,但是也会带来一些额外的负担,因为需要耗费更多的资源和网络带宽。 \ No newline at end of file diff --git a/src/life/README.md b/src/life/README.md index 9f3930a..0d61eb8 100644 --- a/src/life/README.md +++ b/src/life/README.md @@ -6,3 +6,40 @@ title: Qtp生活 生活像一把无情刻刀,改变了我们... +写一个linux内核 + +主从模式的高可用数据库 + +> color=NavajoWhite +> color=Feldspar +> color=SandyBrown +> color=LightSalmon +> color=Salmon +> color=LightCoral +> +> color=Pink +> color=PaleVioletRed +> color=HotPink +> +> color=silver +> color=LightSlateGray +> color=SlateGray +> color=grey +> color=RosyBrown +> color=maroon +> +> color=DarkSeaGreen +> color=LightSeaGreen +> color=SeaGreen +> +> color=PowderBlue +> color=LightSteelBlue +> color=CadetBlue +> color=navy +> +> color=Thistle +> color=Plum +> color=MediumPurple +> color=Purple + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/191049a044630e3010aba4dda68ea90a.png) \ No newline at end of file diff --git a/src/microservices/nacos/Cluster.md b/src/microservices/nacos/Cluster.md new file mode 100644 index 0000000..0ae374d --- /dev/null +++ b/src/microservices/nacos/Cluster.md @@ -0,0 +1,413 @@ +--- +order: 4 +author: +title: "搭建集群" +category: + - Nacos + - 集群 + +--- + +## 搭建Nacos集群 + +Nacos生产环境下一定要部署为集群状态 + +### 1.集群结构图 + +官方给出的Nacos集群图: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/bacf4ed6f01d2acc95ffe94e11aec509.png) + +其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。 + +我们计划的集群结构: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/e85b99a4a1ed07778d1ff17e2fbe2ebc.png) + + + +三个nacos节点的地址: + +| 节点 | ip | port | +| ------ | ------------- | ---- | +| nacos1 | 192.168.150.1 | 8845 | +| nacos2 | 192.168.150.1 | 8846 | +| nacos3 | 192.168.150.1 | 8847 | + + + +### 2.搭建集群的基本步骤: + +- 搭建数据库,初始化数据库表结构 +- 下载nacos安装包 +- 配置nacos +- 启动nacos集群 +- nginx反向代理 + + + +### 3.初始化数据库 + +Nacos默认数据存储在内嵌数据库Derby中,不属于生产可用的数据库。 + +官方推荐的最佳实践是使用带有主从的高可用数据库集群 + +这里我们以单点的数据库为例来讲解。 + +首先新建一个数据库,命名为nacos,而后导入下面的SQL: + +```sql +CREATE TABLE `config_info` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `data_id` varchar(255) NOT NULL COMMENT 'data_id', + `group_id` varchar(255) DEFAULT NULL, + `content` longtext NOT NULL COMMENT 'content', + `md5` varchar(32) DEFAULT NULL COMMENT 'md5', + `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + `src_user` text COMMENT 'source user', + `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', + `app_name` varchar(128) DEFAULT NULL, + `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', + `c_desc` varchar(256) DEFAULT NULL, + `c_use` varchar(64) DEFAULT NULL, + `effect` varchar(64) DEFAULT NULL, + `type` varchar(64) DEFAULT NULL, + `c_schema` text, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info'; + +/******************************************/ +/* 数据库全名 = nacos_config */ +/* 表名称 = config_info_aggr */ +/******************************************/ +CREATE TABLE `config_info_aggr` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `data_id` varchar(255) NOT NULL COMMENT 'data_id', + `group_id` varchar(255) NOT NULL COMMENT 'group_id', + `datum_id` varchar(255) NOT NULL COMMENT 'datum_id', + `content` longtext NOT NULL COMMENT '内容', + `gmt_modified` datetime NOT NULL COMMENT '修改时间', + `app_name` varchar(128) DEFAULT NULL, + `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段'; + + +/******************************************/ +/* 数据库全名 = nacos_config */ +/* 表名称 = config_info_beta */ +/******************************************/ +CREATE TABLE `config_info_beta` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `data_id` varchar(255) NOT NULL COMMENT 'data_id', + `group_id` varchar(128) NOT NULL COMMENT 'group_id', + `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', + `content` longtext NOT NULL COMMENT 'content', + `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps', + `md5` varchar(32) DEFAULT NULL COMMENT 'md5', + `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + `src_user` text COMMENT 'source user', + `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', + `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta'; + +/******************************************/ +/* 数据库全名 = nacos_config */ +/* 表名称 = config_info_tag */ +/******************************************/ +CREATE TABLE `config_info_tag` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `data_id` varchar(255) NOT NULL COMMENT 'data_id', + `group_id` varchar(128) NOT NULL COMMENT 'group_id', + `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id', + `tag_id` varchar(128) NOT NULL COMMENT 'tag_id', + `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', + `content` longtext NOT NULL COMMENT 'content', + `md5` varchar(32) DEFAULT NULL COMMENT 'md5', + `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + `src_user` text COMMENT 'source user', + `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag'; + +/******************************************/ +/* 数据库全名 = nacos_config */ +/* 表名称 = config_tags_relation */ +/******************************************/ +CREATE TABLE `config_tags_relation` ( + `id` bigint(20) NOT NULL COMMENT 'id', + `tag_name` varchar(128) NOT NULL COMMENT 'tag_name', + `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type', + `data_id` varchar(255) NOT NULL COMMENT 'data_id', + `group_id` varchar(128) NOT NULL COMMENT 'group_id', + `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id', + `nid` bigint(20) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`nid`), + UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`), + KEY `idx_tenant_id` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation'; + +/******************************************/ +/* 数据库全名 = nacos_config */ +/* 表名称 = group_capacity */ +/******************************************/ +CREATE TABLE `group_capacity` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群', + `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值', + `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量', + `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值', + `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值', + `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值', + `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量', + `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_group_id` (`group_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表'; + +/******************************************/ +/* 数据库全名 = nacos_config */ +/* 表名称 = his_config_info */ +/******************************************/ +CREATE TABLE `his_config_info` ( + `id` bigint(64) unsigned NOT NULL, + `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `data_id` varchar(255) NOT NULL, + `group_id` varchar(128) NOT NULL, + `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name', + `content` longtext NOT NULL, + `md5` varchar(32) DEFAULT NULL, + `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `src_user` text, + `src_ip` varchar(50) DEFAULT NULL, + `op_type` char(10) DEFAULT NULL, + `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段', + PRIMARY KEY (`nid`), + KEY `idx_gmt_create` (`gmt_create`), + KEY `idx_gmt_modified` (`gmt_modified`), + KEY `idx_did` (`data_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造'; + + +/******************************************/ +/* 数据库全名 = nacos_config */ +/* 表名称 = tenant_capacity */ +/******************************************/ +CREATE TABLE `tenant_capacity` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID', + `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值', + `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量', + `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值', + `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数', + `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值', + `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量', + `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_tenant_id` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表'; + + +CREATE TABLE `tenant_info` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `kp` varchar(128) NOT NULL COMMENT 'kp', + `tenant_id` varchar(128) default '' COMMENT 'tenant_id', + `tenant_name` varchar(128) default '' COMMENT 'tenant_name', + `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc', + `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source', + `gmt_create` bigint(20) NOT NULL COMMENT '创建时间', + `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`), + KEY `idx_tenant_id` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info'; + +CREATE TABLE `users` ( + `username` varchar(50) NOT NULL PRIMARY KEY, + `password` varchar(500) NOT NULL, + `enabled` boolean NOT NULL +); + +CREATE TABLE `roles` ( + `username` varchar(50) NOT NULL, + `role` varchar(50) NOT NULL, + UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE +); + +CREATE TABLE `permissions` ( + `role` varchar(50) NOT NULL, + `resource` varchar(255) NOT NULL, + `action` varchar(8) NOT NULL, + UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE +); + +INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE); + +INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN'); +``` + + + +### 4.下载nacos + +nacos在GitHub上有下载地址:https://github.com/alibaba/nacos/tags,可以选择任意版本下载。 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/d613d050239fdb51cf0e7f4b9d9200f8.png) + + + +### 5.配置Nacos + +将这个包解压到任意非中文目录下,如图: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/998ed192e5f7998760da6f15938d5d51.png) + +目录说明: + +- bin:启动脚本 +- conf:配置文件 + + + +进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/183d3c435e577dedddb018f36e1caafa.png) + +然后添加内容: + +``` +127.0.0.1:8845 +127.0.0.1.8846 +127.0.0.1.8847 +``` + + + +然后修改application.properties文件,添加数据库配置 + +```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=root +db.password.0=123 +``` + + + +### 6.启动 + +将nacos文件夹复制三份,分别命名为:nacos1、nacos2、nacos3 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/59c70aec72444cb3990775ed909be96d.png) + +然后分别修改三个文件夹中的application.properties, + +nacos1: + +```properties +server.port=8845 +``` + +nacos2: + +```properties +server.port=8846 +``` + +nacos3: + +```properties +server.port=8847 +``` + + + +然后分别启动三个nacos节点: + +``` +startup.cmd +``` + + + +### 7.nginx反向代理: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/4c383cf4be623db030d39b47e4251849.png) + +解压到任意非中文目录下: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/3694899c3441e776f67de2d51941c585.png) + +修改conf/nginx.conf文件,配置如下: + +```nginx +upstream nacos-cluster { + server 127.0.0.1:8845; + server 127.0.0.1:8846; + server 127.0.0.1:8847; +} + +server { + listen 80; + server_name localhost; + + location /nacos { + proxy_pass http://nacos-cluster; + } +} +``` + + + +而后在浏览器访问:http://localhost/nacos即可。 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/069d412a04e88064edc58592b7581430.png) + +java代码怎么写呢,肯定写==nginx的80==啊! + +代码中application.yml文件配置如下: + +```yaml +spring: + cloud: + nacos: + server-addr: localhost:80 # Nacos地址 +``` + +假如我现在加入了一个配置文件 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/image-20241231173824342.png) + +现在打开数据库 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/image-20241231173858882.png) + +会发现存进来了 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/image-20241231173938641.png) + + + +小结: + +集群搭建步骤: + +- 搭建MySQL集群并初始化数据库表 +- 下载解压nacos +- 修改集群配置(节点信息)、数据库配置 +- 分别启动多个nacos节点 +- nginx反向代理 \ No newline at end of file diff --git a/src/microservices/nacos/Configuration Center.md b/src/microservices/nacos/Configuration Center.md new file mode 100644 index 0000000..681ef11 --- /dev/null +++ b/src/microservices/nacos/Configuration Center.md @@ -0,0 +1,966 @@ +--- +order: 3 +author: +title: "配置中心" +category: + - Nacos + - 配置中心 + - 负载均衡 + + +--- + +## 1.Nacos配置管理 + +Nacos除了可以做注册中心,同样可以做配置管理来使用。 + + + +### 1.1.统一配置管理 + +当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错,==你还得重启==。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/d4dce5e853575598871cda222c9c62d1.png) + + + +Nacos一方面可以将配置集中管理,另一方可以在配置变更时,及时通知微服务,实现==配置的热更新==。 + + + +#### 1.1.1.在nacos中添加配置文件 + +如何在nacos中管理配置呢? + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/9031c07d87c9dc8b06d6d345ed1322f6.png) + +然后在弹出的表单中,填写配置信息: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/9d4734f3215e5521bab58f4a6de2e6dc.png) + + + +> 注意:项目的核心配置,**需要热更新的配置**才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。 + +比如一些==开关逻辑==放在这比较好,true就处理,false就不处理。 + + + +#### 1.1.2.从微服务拉取配置 + +**无法注入的在UserController上添加@RefreshScope就可以了** + +微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。 + +但如果尚未读取application.yml,又如何得知nacos地址呢? + +因此spring引入了一种新的配置文件:bootstrap.yaml文件,会在application.yml之前被读取,流程如下: + + + +1)引入nacos-config依赖 + +首先,在user-service服务中,引入nacos-config的客户端依赖: + +```xml + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + +``` + +2)添加bootstrap.yaml + +然后,在user-service中添加一个bootstrap.yaml文件,内容如下: + +```yaml +spring: + application: + name: userservice # 服务名称 + profiles: + active: dev #开发环境,这里是dev + cloud: + nacos: + server-addr: localhost:8848 # Nacos地址 + config: + file-extension: yaml # 文件后缀名 +``` + +这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据 + +`${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}`作为文件id,来读取配置。 + +本例中,就是去读取`userservice-dev.yaml`: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/6d4c3cfb995f7f57ccc84baca7336971.png) + + + +3)读取nacos配置 + +在user-service中的UserController中添加业务逻辑,读取pattern.dateformat配置: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/27c7455fce8f983563efcab933e41d6e.png) + + + +完整代码: + +```java +package cn.itcast.user.web; + +import cn.itcast.user.pojo.User; +import cn.itcast.user.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Slf4j +@RestController +@RequestMapping("/user") +public class UserController { + + @Autowired + private UserService userService; + + @Value("${pattern.dateformat}") + private String dateformat; + + @GetMapping("now") + public String now(){ + return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat)); + } + // ...略 +} +``` + + + +在页面访问,可以看到效果: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/928b94d3b66b79a96bd10943a6d6a606.png) + + + +### 1.2.配置热更新 + +我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是**配置热更新**。 + +```yaml +pattern: + dateformat: yyyy年-MM月-dd日 HH:mm:ss +``` + +我们没有重启微服务,但发生了自动更新。 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/6c6278fe0f14d1f030bc4f92562d5d4b.png) + +要实现配置热更新,可以使用两种方式: + +#### 1.2.1.方式一 + +在@Value注入的变量所在类上添加注解@RefreshScope: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/1f53b425a3ab3b25063af7860ae1f032.png) + + + +#### 1.2.2.方式二(在属性注入时,推荐configurationpropertis,维护起来也方便) + +使用@ConfigurationProperties注解代替@Value注解。 + +在user-service服务中,添加一个类,读取patterrn.dateformat属性: + +```java +package cn.itcast.user.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@Data +@ConfigurationProperties(prefix = "pattern") +public class PatternProperties { + private String dateformat; +} +``` + + + +在UserController中使用这个类代替@Value: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/e76d0659cbec36e317866b3533253f33.png) + + + +完整代码: + +```java +package cn.itcast.user.web; + +import cn.itcast.user.config.PatternProperties; +import cn.itcast.user.pojo.User; +import cn.itcast.user.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Slf4j +@RestController +@RequestMapping("/user") +public class UserController { + + @Autowired + private UserService userService; + + @Autowired + private PatternProperties patternProperties; + + @GetMapping("now") + public String now(){ + return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat())); + } + + // 略 +} +``` + + + + + +### 1.3.配置共享 + +其实微服务启动时,会去nacos读取多个配置文件,例如: + +- `[spring.application.name]-[spring.profiles.active].yaml`,例如:userservice-dev.yaml + +- `[spring.application.name].yaml`,例如:userservice.yaml + +而`[spring.application.name].yaml`不包含环境,因此可以被多个环境共享。 + + + +下面我们通过案例来测试配置共享 + + + +#### 1)添加一个环境共享配置 + +我们在nacos中添加一个userservice.yaml文件: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/89910479e9102e7996dff95d700521ee.png) + + + +#### 2)在user-service中读取共享配置 + +在user-service服务中,修改PatternProperties类,读取新添加的属性: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/361a80b95675bc404b8c78fdb3d3cec6.png) + +在user-service服务中,修改UserController,添加一个方法: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/9c77d3bfeb08d028df352ae3d9709541.png) + + + +#### 3)运行两个UserApplication,使用不同的profile + +修改UserApplication2这个启动项,改变其profile值: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/d8f21b30e6d7d9bde9856a282d83c5be.png) + + + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/b790de898350bc66dafe1dece2f4df78.png) + + + +这样,UserApplication(8081)使用的profile是dev,UserApplication2(8082)使用的profile是test。 + +启动UserApplication和UserApplication2 + +访问http://localhost:8081/user/prop,结果: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/f319f955c9cef639ca9b1f4d71ae396c.png) + +访问http://localhost:8082/user/prop,结果: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/71edddd72b966284382c222b4865afe8.png) + +可以看出来,不管是dev,还是test环境,都读取到了envSharedValue这个属性的值。 + + + +### 4)配置共享的优先级 + +当nacos、服务本地同时出现相同属性时,优先级有高低之分: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/fefd67e1f779f6a39ecd79f0b4a96a33.png) + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/c5810abd1046aa74dca3cb20524ebe3b.png) + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/2f6d7ae8bc8950c3715f6f4717052352.png) + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/78325d48c62d653d175acedbfbeb94d1.png) + + + + + +### 2.6.优化 + + + +- 实际部署时,需要给做反向代理的nginx服务器设置一个域名,这样后续如果有服务器迁移nacos的客户端也无需更改配置. + +- Nacos的各个节点应该部署到多个不同服务器,做好容灾和隔离 + + + + + + + + + +# 3.Gateway服务网关 + +Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。 + + + +## 3.1.为什么需要网关 + +> **前言:** +> +> 当微服务内部有相互调用关系时,我们就可以利用Feign这样一个组件去做了; +> +> 当外部有请求时,直接发请求到我们的微服务就行了;??? +> +> 不是所有的都是对外公开的,一些是内部使用的; +> +> 需要对用户的身份进行验证; + +Gateway网关是我们服务的守门神,所有微服务的统一入口。 + +网关的**核心功能特性**: + +- 请求路由 +- 权限控制 +- 限流 + +> 小Tips: +> +> Feign的负载均衡是解决微服务内之间调用, +> +> 然后gateway负载均衡是解决客户端访问服务端的调用 + +架构图: + +![image-20210714210131152](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/5db4df28837f7bb3168848fe545e3141.png) + + + +**权限控制**:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。 + +**路由和负载均衡**:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。 + +**限流**:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。 + + + +在SpringCloud中网关的实现包括两种: + +- gateway +- zuul + +Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。 + + + + + +## 3.2.gateway快速入门 + +下面,我们就演示下网关的基本路由功能。基本步骤如下: + +1. 创建SpringBoot工程gateway,引入网关依赖 +2. 编写启动类 +3. 编写基础配置和路由规则 +4. 启动网关服务进行测试 + + + +### 1)创建gateway服务,引入依赖 + +创建服务: + +![image-20210714210919458](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/35dbc60a356f71c5b2a6d7a13f3b8a58.png) + +引入依赖: + +starter依赖---也就是自动装配 + +```xml + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + +``` + + + +### 2)编写启动类 + +```java +package cn.itcast.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + } +} +``` + + + +### 3)编写基础配置和路由规则 + +创建application.yml文件,内容如下: + +```yaml +server: + port: 10010 # 网关端口 +spring: + application: + name: gateway # 服务名称 + cloud: + nacos: + server-addr: localhost:8848 # nacos地址 + gateway: + routes: # 网关路由配置 + - id: user-service # 路由id,自定义,只要唯一即可 + # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址 + uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称 + predicates: # 路由断言,也就是判断请求是否符合路由规则的条件 + - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求 + - id: order-service + #uri: http://localhost:8080 + uri: lb://orderservice + predicates: + - Path=/order/** +``` + + + +我们将符合`Path` 规则的一切请求,都代理到 `uri`参数指定的地址。 + +本例中,我们将 `/user/**`开头的请求,代理到`lb://userservice`,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡。 + + + +### 4)重启测试 + +重启网关,访问http://localhost:10010/user/1时,符合`/user/**`规则,请求转发到uri:http://userservice/user/1,得到了结果: + +![image-20210714211908341](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/9a0abd0474c75825780b99a7fb3b1857.png) + + + + + +### 5)网关路由的流程图 + +整个访问的流程如下: + +![image-20210714211742956](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/e79fa391abca2a8df8ea3915ff60f7b2.png) + + + +总结: + +网关搭建步骤: + +1. 创建项目,引入nacos服务发现和gateway依赖 + +2. 配置application.yml,包括服务基本信息、nacos地址、路由 + +路由配置包括: + +1. 路由id:路由的唯一标示 + +2. 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡 + +3. 路由断言(predicates):判断路由的规则, + +4. 路由过滤器(filters):对请求或响应做处理 + + + +接下来,就重点来学习路由断言和路由过滤器的详细知识 + + + + + +## 3.3.断言工厂 + +我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件 + +例如Path=/user/**是按照路径匹配,这个规则是由处理的 + +`org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory`类来 + +```yaml + - id: user-service +# uri: http://localhost:8081 + uri: lb://userservice + predicates: + - Path=/user/** + - After=2024-01-20T17:42:47.789-07:00[America/Denver] +``` + +![image-20230610102944484](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/ed2d94d52e2fd81d748c6dab979818a5.png) + +![image-20230610103010625](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/03a64bf97086d445e2d45f14da0f6a28.png) + +像这样的断言工厂在SpringCloudGateway还有十几个: + +| **名称** | **说明** | **示例** | +| ---------- | ------------------------------ | ------------------------------------------------------------ | +| After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] | +| Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] | +| Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] | +| Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p | +| Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ | +| Host | 请求必须是访问某个host(域名) | - Host=**.somehost.org,**.anotherhost.org | +| Method | 请求方式必须是指定方式 | - Method=GET,POST | +| Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** | +| Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name | +| RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 | +| Weight | 权重处理 | | + + + +我们只需要掌握Path这种路由工程就可以了。 + + + +## 3.4.过滤器工厂 + +GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理: + +![image-20210714212312871](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/8d8e6250f1f7f7e8c7336453676d0cde.png) + + + +### 3.4.1.路由过滤器的种类 + +Spring提供了31种不同的路由过滤器工厂。例如: + +| **名称** | **说明** | +| -------------------- | ---------------------------- | +| AddRequestHeader | 给当前请求添加一个请求头 | +| RemoveRequestHeader | 移除请求中的一个请求头 | +| AddResponseHeader | 给响应结果中添加一个响应头 | +| RemoveResponseHeader | 从响应结果中移除有一个响应头 | +| RequestRateLimiter | 限制请求的流量 | + + + +### 3.4.2.请求头过滤器 + +下面我们以AddRequestHeader 为例来讲解。 + +> **需求**:给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome! + + + +只需要修改gateway服务的application.yml文件,添加路由过滤即可: + +```yaml +spring: + cloud: + gateway: + routes: + - id: user-service + uri: lb://userservice + predicates: + - Path=/user/** + filters: # 过滤器 + - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头 +``` + +当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效。 + +> 记得日志级别改为Header + +![image-20230610113754972](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/5993e94d678ebeadb8dcc07119382aaf.png) + +日志打印了出来 + +![image-20230610113814013](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/6c69427f1b5901af9a1c81790a9dcd04.png) + +### 3.4.3.默认过滤器 + +如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下: + +```yaml +spring: + cloud: + gateway: + routes: + - id: user-service + uri: lb://userservice + predicates: + - Path=/user/** + default-filters: # 默认过滤项 + - AddRequestHeader=Truth, Itcast is freaking awesome! +``` + + + +### 3.4.4.总结 + +过滤器的作用是什么? + +① 对路由的请求或响应做加工处理,比如添加请求头 + +② 配置在路由下的过滤器只对当前路由的请求生效 + +defaultFilters的作用是什么? + +① 对所有路由都生效的过滤器 + + + +## 3.5.全局过滤器 + +上一节学习的过滤器,网关提供了31种,但每一种过滤器的作用都是固定的。如果我们希望拦截请求,做自己的业务逻辑则没办法实现。 + +### 3.5.1.全局过滤器作用 + +全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。 + +定义方式是实现GlobalFilter接口。 + +```java +public interface GlobalFilter { + /** + * 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理 + * + * @param exchange 请求上下文(从请求网关开始,一直到结束为止),整个过程中都可以共享exchage对象,里面可以获取Request、Response等信息 + * @param chain 用来把请求委托给下一个过滤器 + * @return {@code Mono} 返回标示当前过滤器业务结束 + */ + Mono filter(ServerWebExchange exchange, GatewayFilterChain chain); +} +``` + + + +在filter中编写自定义逻辑,可以实现下列功能: + +- 登录状态判断 +- 权限校验 +- 请求限流等 + + + + + +### 3.5.2.自定义全局过滤器 + +需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件: + +- 参数中是否有authorization, + +- authorization参数值是否为admin + +如果同时满足则放行,否则拦截 + + + +实现: + +在gateway中定义一个过滤器: + +```java +package cn.itcast.gateway.filters; + +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +@Order(-1) +@Component +public class AuthorizeFilter implements GlobalFilter { + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + // 1.获取请求参数 + MultiValueMap params = exchange.getRequest().getQueryParams(); + // 2.获取authorization参数 + String auth = params.getFirst("authorization"); + // 3.校验 + if ("admin".equals(auth)) { + // 放行 + return chain.filter(exchange); + } + // 4.拦截 + // 4.1.禁止访问,设置状态码 + exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); + // 4.2.结束处理 + return exchange.getResponse().setComplete(); + } +} +``` + +![image-20230610134430192](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/74af4a3997c2b8333bdc3821556d6173.png) + +果然是403 + +![image-20230610134512810](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/5e1565a765997729072bc340af147095.png) + + + +小结: + +> 1、全局过滤器的作用是什么? +> +> - 对所有路由都生效的过滤器,并且可以自定义处理逻辑 +> +> 2、实现全局过滤器的步骤?实现GlobalFilter接口 +> +> - 添加@Order注解或实现Ordered接口 +> - 编写处理逻辑 + +![image-20230610134902623](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/11095d5773bbe793bdb799b680e2d205.png) + +![image-20230610135103617](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/bba03bfd3171d07c4900c16d9f3d3a51.png) + +### 3.5.3.过滤器执行顺序 + +请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter + +请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器: + +![image-20210714214228409](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/7ea49c972768cfb164e85d769c5be2d9.png) + + + +排序的规则是什么呢? + +- 每一个过滤器都必须指定一个int类型的order值,**order值越小,优先级越高,执行顺序越靠前**。 +- GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定 +- 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。 +- 当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。 + + + +详细内容,可以查看源码: + +`org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()`方法是先加载defaultFilters,然后再加载某个route的filters,然后合并。 + + + +`org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()`方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链 + +> 适配器: 将一个类的接口转换成客户希望的另外一个接口 + +![image-20230610140613127](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/149a1212fd21e3f8b13cceeb266d2e3a.png) + +也就是说,在网关中,所有的GlobalFilter都可以适配成GatewayFilter,所以都是GatewayFilter,都可以扔到GatewayFilter集合中去做排序; + +## 3.6.跨域问题 + + + +### 3.6.1.什么是跨域问题 + +跨域:域名不一致就是跨域,主要包括: + +- 域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com + +- 域名相同,端口不同:localhost:8080和localhost8081 + +跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题 + + + +解决方案:CORS,这个以前应该学习过,这里不再赘述了。不知道的小伙伴可以查看https://www.ruanyifeng.com/blog/2016/04/cors.html + + + +### 3.6.2.模拟跨域问题 + +找到课前资料的页面文件: + +![image-20210714215713563](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/0535eab21133fd3d7cb67f3d262b8748.png) + +放入tomcat或者nginx这样的web服务器中,启动并访问。 + +可以在浏览器控制台看到下面的错误: + +![image-20210714215832675](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/12d867dece3d60d7b5cd743115ba3938.png) + + + +从localhost:8090访问localhost:10010,端口不同,显然是跨域的请求。 + + + +### 3.6.3.解决跨域问题 + +在gateway服务的application.yml文件中,添加下面的配置: + +```yaml +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 # 这次跨域检测的有效期 +``` + + + + + + + + + +ring指定,默认是按照声明顺序从1递增。 + +- 当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。 + + + +详细内容,可以查看源码: + +`org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()`方法是先加载defaultFilters,然后再加载某个route的filters,然后合并。 + + + +`org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()`方法会加载全局过滤器,与前面的过滤器合并后根据order排序,组织过滤器链 + +> 适配器: 将一个类的接口转换成客户希望的另外一个接口 + +[外链图片转存中...(img-2tp5sbNg-1686874915080)] + +也就是说,在网关中,所有的GlobalFilter都可以适配成GatewayFilter,所以都是GatewayFilter,都可以扔到GatewayFilter集合中去做排序; + +## 3.6.跨域问题 + + + +### 3.6.1.什么是跨域问题 + +跨域:域名不一致就是跨域,主要包括: + +- 域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com + +- 域名相同,端口不同:localhost:8080和localhost8081 + +跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题 + + + +解决方案:CORS,这个以前应该学习过,这里不再赘述了。不知道的小伙伴可以查看https://www.ruanyifeng.com/blog/2016/04/cors.html + + + +### 3.6.2.模拟跨域问题 + +找到课前资料的页面文件: + +[外链图片转存中...(img-eEkZJFEU-1686874915080)] + +放入tomcat或者nginx这样的web服务器中,启动并访问。 + +可以在浏览器控制台看到下面的错误: + +[外链图片转存中...(img-pilFHEP4-1686874915080)] + + + +从localhost:8090访问localhost:10010,端口不同,显然是跨域的请求。 + + + +### 3.6.3.解决跨域问题 + +在gateway服务的application.yml文件中,添加下面的配置: + +```yaml +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 # 这次跨域检测的有效期 +``` + + + + + + + + + diff --git a/src/microservices/nacos/Registration Center.md b/src/microservices/nacos/Registration Center.md new file mode 100644 index 0000000..7032cf6 --- /dev/null +++ b/src/microservices/nacos/Registration Center.md @@ -0,0 +1,386 @@ +--- +order: 2 +author: +title: "注册中心" +category: + - Nacos + - 注册中心 + - 负载均衡 + +--- + +## 1.服务注册到nacos + +Nacos是SpringCloudAlibaba的组件,而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说,并没有太大区别。 + +主要差异在于: + +- 依赖不同 +- 服务地址不同 + + + +### 1.1.引入依赖 + +在cloud-demo父工程的pom文件中的``中引入SpringCloudAlibaba的依赖: + +```xml + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + 2.2.6.RELEASE + pom + import + +``` + +然后在user-service和order-service中的pom文件中引入nacos-discovery依赖: + +```xml + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + +``` + + + +> **注意**:不要忘了注释掉eureka的依赖。 + + + +### 1.2.配置nacos地址 + +在user-service和order-service的application.yml中添加nacos地址: + +```yaml +spring: + cloud: + nacos: + server-addr: localhost:8848 +``` + + + +> **注意**:不要忘了注释掉eureka的地址 + + + +### 1.3.重启 + +重启微服务后,登录nacos管理页面,可以看到微服务信息: + + + +## 2.服务分级存储模型 + +一个**服务**可以有多个**实例**,例如我们的user-service,可以有: + +- 127.0.0.1:8081 +- 127.0.0.1:8082 +- 127.0.0.1:8083 + +假如这些实例分布于全国各地的不同机房,例如: + +- 127.0.0.1:8081,在上海机房 +- 127.0.0.1:8082,在上海机房 +- 127.0.0.1:8083,在杭州机房 + +Nacos就将同一机房内的实例 划分为一个**集群**。 + +也就是说,user-service是服务,一个服务可以包含多个集群,如杭州、上海,每个集群下可以有多个实例,形成分级模型,如图: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/f6564401044a0f1674031d2d5b9d4406.png) + + + +微服务互相访问时,应该尽可能访问同集群实例,因为本地访问速度更快。当本集群内不可用时,才访问其它集群。例如: + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/1c37ab0d9c7b3ce310064efc3ba214f3.png) + +杭州机房内的order-service应该优先访问同机房的user-service。 + + + +### 2.1.给user-service配置集群 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/1b020ab8fda94a4337c568a9309755d5.png) + +默认集群名为DEFAULT + +修改user-service的application.yml文件,添加集群配置: + +```yaml +spring: + cloud: + nacos: + server-addr: localhost:8848 + discovery: + cluster-name: HZ # 集群名称 +``` + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/1e6c32c3ec15291ba183997ff3446677.png) + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/3335d59e99a12c37674e3a7631f89c2e.png) + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/3b0aaf1bae12be169fd8c36b5f4fa939.png) + + + +### 2.2.Nacos小结: + +1、Nacos服务分级存储模型 + +- 一级是服务,例如userservice +- 二级是集群,例如杭州或上海 +- 三级是实例,例如杭州机房的某台部署了userservice的服务器 + +2、如何设置实例的集群属性 + +- 修改application.yml文件,添加spring.cloud.nacos.discovery.cluster-name属性即可 + + + +## 3.同集群优先的负载均衡 + +orderservice和userservice的8081和8082都在一个集群中了,我们希望的是orderservice,那此时呢我们希望的是order service发起远程调用时,优先选择8081和8082 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/bc2d8995777666c8df94ccd7ceb610a0.png) + +==但是==默认的`ZoneAvoidanceRule`并不能实现根据同集群优先来实现负载均衡。 + +因此Nacos中提供了一个`NacosRule`的实现,可以优先从同集群中挑选实例。 + +### ***3.1.给order-service配置集群信息*** + +修改order-service的application.yml文件,添加集群配置: + +```sh +spring: + cloud: + nacos: + server-addr: localhost:8848 + discovery: + cluster-name: HZ # 集群名称 +``` + + + +### ***3.2.修改负载均衡规则*** + +修改order-service的application.yml文件,修改负载均衡规则: + +```yaml +userservice: + ribbon: + NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则 ,NacosRule---优先选择本地集群 +``` + +### 3.3.如果配置了优先访问本地集群,那本地的多个集群都崩了会发生什么? + +![image-20230607235047898](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/e626c7d4350f4ee02ab4a1b624ed59fd.png) + +只留一个试试。 + +```java +一次跨集群访问发生了,谁呢? userservice +想访问的是杭州,但实际是上海 +A cross-cluster call occurs,name = userservice, clusterName = HZ, instance = [Instance{instanceId='192.168.43.172#8083#SH#DEFAULT_GROUP@@userservice', ip='192.168.43.172', port=8083, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='SH', serviceName='DEFAULT_GROUP@@userservice', metadata={preserved.register.source=SPRING_CLOUD}}] + +``` + +运维人员看见警告就会处理。 + +### 3.4.总结 + +NacosRule负载均衡策略 + +- 优先选择同集群服务实例列表 +- 本地集群找不到提供者,才去其它集群寻找,并且会报警告 +- 确定了可用实例列表后,再采用随机负载均衡挑选实例 + +## 4.权重配置 + +实际部署中会出现这样的场景: + +- 服务器设备性能有差异,部分实例所在机器性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求。 + +但默认情况下NacosRule是同集群内随机挑选,不会考虑机器的性能问题。 + +因此,Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高。 + +在nacos控制台,找到user-service的实例列表,点击编辑,即可修改权重: + +![image-20210713235133225](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/4192d335f35eff4c6d4cf09be162eb5b.png) + +在弹出的编辑窗口,修改权重: + +![image-20210713235235219](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/b211a65fc38d0425e6ab69792f771c99.png) + +![image-20230608222430037](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/df3df2f5a92e80ad89d1ae060c15a04c.png) + +![image-20230608222647143](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/8e5807c9f7b537bd94df1af95e43ff17.png) + +> **注意**:如果权重修改为0,则该实例永远不会被访问 + +如果一个服务想要做一个版本的升级,怎么办? 重启!王者荣耀不停服更新---部分分批更新(设权重) + +#### 总结: + +> 实例的权重控制 +> +> - Nacos控制台可以设置实例的权重值,0~1之间 +> - 同集群内的多个实例,权重越高被访问的频率越高 +> - 权重设置为0则完全不会被访问 + +## 5.环境隔离 + +Nacos提供了namespace来实现环境隔离功能。 + +- nacos中可以有多个namespace +- namespace下可以有group、service等 +- 不同namespace之间相互隔离,例如不同namespace的服务互相不可见 + +开发/测试/生产 三种环境需要隔离 服务和配置的 + +![image-20210714000101516](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/459a09af4f9ddbb94be4ac51b6f8afcb.png) + + + +### 5.1.创建namespace + +默认情况下,所有service、data、group都在同一个namespace,名为public: + +![image-20210714000414781](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/c7ade712e06eb0395ce562c70ea8a757.png) + + + +我们可以点击页面新增按钮,添加一个namespace: + +![image-20210714000440143](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/e193a37f988088684e36bc15548a6de4.png) + + + +然后,填写表单: + +![image-20210714000505928](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/3a9563601ac8cbc3c1e4ad8cff2ce9c2.png) + +就能在页面看到一个新的namespace: + +![image-20210714000522913](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/5f6ab6500651acf4c67b1a6347b0b7be.png) + + + +### 5.2.给微服务配置namespace + +给微服务配置namespace只能通过修改配置来实现。 + +例如,修改order-service的application.yml文件: + +```yaml +spring: + cloud: + nacos: + server-addr: localhost:8848 + discovery: + cluster-name: HZ + namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID +``` + + + +重启order-service后,访问控制台,可以看到下面的结果: + +![image-20210714000830703](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/684be5121966110be67f2accb3defc1e.png) + + + +![image-20210714000837140](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/484caab3fa8b96f6673848b407a88c1a.png) + +此时访问order-service,因为namespace不同,会导致找不到userservice,控制台会报错: + +是两个世界的人了! + +![image-20210714000941256](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/ba9db871150ba398c31c3b6d97989455.png) + +> Nacos环境隔离 +> +> - 每个namespace都有唯一id +> - 服务设置namespace时要写id而不是名称 +> - 不同namespace下的服务互相不可见 + +## 6.Nacos与Eureka的区别 + +![image-20230609081002359](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/b5d44ae7be32f5dbe38d610c79225db1.png) + +到目前为止,Nacos和Eurela没什么区别, + + + +Nacos的服务实例分为两种l类型: + +- 临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型。 + +nacos默认情况下就是临时实例,临时实例栏是 `true` + + 不写,ephemeral: false,停掉,就会等待一会儿后,nacos监测台就会爆红 + +![image-20230609093334913](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/cb62baf822e56533b3e6d2975702a481.png) + +- 非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。 + +![image-20230609093454247](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/6b5e436a224ca33cee40593f252b87a5.png) + +配置一个服务实例为永久实例: + +```yaml +spring: + cloud: + nacos: + discovery: + ephemeral: false # 设置为非临时实例 +``` + + + + + +Nacos和Eureka整体结构类似,服务注册、服务拉取、心跳等待,但是也存在一些差异: + +![image-20210714001728017](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/cebec10ce329a95801de61f390cb98b8.png) + + + +- **Nacos与eureka的共同点** + + - 都支持服务注册和服务拉取 + - 都支持服务提供者心跳方式做健康检测 + +- **Nacos与Eureka的区别** + + - Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用==主动检测==模式 + - 临时实例心跳不正常会被剔除,非临时实例则==不会被剔除==(**==只是把你标记为不健康==**) + - Nacos支持服务列表变更的==消息推送push模式==,服务列表更新更及时 + - Nacos集群默认采用==AP==方式,当集群中存在非临时实例时,采用==CP==模式;Eureka采用AP方式 + + + + **总结一下**,nacos与eureka的几点区别: + + 1、功能作用不同,nacos是一个服务注册与服务发现,而且还是一个配置中心,euraka仅仅只是一个注册中心; + + 2、心跳机制不同,nacos可以是主动询问微服务,也可以是微服务主动询问nacos,非临时实例与临时实例 + + 消费者默认每隔30秒会向注册中心拉取信息,但是服务30内挂了怎么办?这时注册中心已经监听到了不健康的服务,那消费者直接去消费就会出问题。 所以Eureka服务列表更新的频率也就比较差。 + + 有回应有主动 比渣男好多了!哈哈哈哈哈!!! + + **记忆:临时是Nacos的舔狗,Nacos是非临时的舔狗。** + +> **为什么nacos临时实例采用心跳模式,非临时实例采用主动检测模式,为什么要区别对待?** +> +> Nacos采用心跳模式来监测临时实例的健康状况,而采用主动检测模式来监测非临时实例的健康状况,原因如下: +> +> 1. 对于临时实例,由于这些实例通常是一些==短暂存在于服务列表中的实例==,它们的声明周期较短,因此采用心跳模式更加适合。心跳模式是通过服务提供者定期发送心跳信息告诉注册中心自己还存活着,如果一段时间内没有收到心跳信息,则认为该实例已经下线,将其从服务列表中移除。这种方式可以及时发现实例的下线,避免了误判,并且减少了对网络带宽和系统资源的占用。 +> 2. 对于非临时实例,这些实例通常存在比较长的生命周期,而采用心跳模式无法保证及时发现实例的下线,因此采用主动检测模式更加适合。主动检测模式是注册中心通过发送HTTP请求或者TCP请求等方式来主动探测服务提供者的状态,以此来保证服务的可用性。这种方式可以更加精确地判断实例的状态,但是也会带来一些额外的负担,因为需要耗费更多的资源和网络带宽。 + diff --git a/src/microservices/nacos/Strated.md b/src/microservices/nacos/Strated.md new file mode 100644 index 0000000..89f288f --- /dev/null +++ b/src/microservices/nacos/Strated.md @@ -0,0 +1,164 @@ +--- +order: 1 +author: +title: "什么是Nacos" +category: + - Nacos + - 注册中心 + - 配置中心 + - 阿里巴巴 + +--- + +## Nacos注册中心 + +国内公司一般都推崇阿里巴巴的技术,比如注册中心,SpringCloudAlibaba也推出了一个名为Nacos的注册中心。 + +### 认识和安装Nacos + +[Nacos](https://nacos.io/)是阿里巴巴的产品,现在是[SpringCloud](https://spring.io/projects/spring-cloud)中的一个组件。相比[Eureka](https://github.com/Netflix/eureka)功能更加丰富,在国内受欢迎程度较高。 + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/image-20241231133649749.png) + +本机启动: + +```bash +startup.cmd -m standalone +``` + +## 什么是Nacos + +Nacos `/nɑ:kəʊs/` 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 + +Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。 + +Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以**“服务”**为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。 + +Nacos 支持几乎所有主流类型的**“服务”**的发现、配置和管理: + +- [Kubernetes Service](https://kubernetes.io/docs/concepts/services-networking/service/) +- [gRPC](https://grpc.io/docs/guides/concepts.html#service-definition) +- [Dubbo RPC Service](https://dubbo.apache.org/) +- [Spring Cloud RESTful Service](https://spring.io/projects/spring-cloud) + +### 产品功能 + +- **服务发现和服务健康监测** + + Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 [原生SDK](https://nacos.io/docs/v3.0/guide/user/sdk/)、[OpenAPI](https://nacos.io/docs/v3.0/guide/user/open-api/)、或一个[独立的Agent](https://nacos.io/docs/v3.0/guide/user/other-language/)注册 Service 后,服务消费者可以使用[DNS TODO](https://nacos.io/docs/v3.0/ecology/use-nacos-with-coredns/) 或[HTTP&API](https://nacos.io/docs/v3.0/guide/user/open-api/)查找和发现服务。 + + Nacos 提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。 + +- **动态配置服务** + + 动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。 + + 动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。 + + 配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。 + + Nacos 提供了一个简洁易用的UI ([控制台样例 Demo](http://console.nacos.io/nacos/index.html)) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。 + +- **动态 DNS 服务** + + 动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。 + + Nacos 提供了一些简单的 [DNS APIs TODO](https://nacos.io/docs/v3.0/ecology/use-nacos-with-coredns/) 帮助您管理服务的关联域名和可用的 IP列表。 + + + +- **服务及其元数据管理** + + Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。 + +### 产品优势 + +- **易于使用** + + Nacos经历几万人使用反馈优化,提供统一的服务发现和配置管理功能,通过直观的 Web 界面和简洁的 API,为开发和运维人员在云原生环境中带来了便捷的服务注册、发现和配置更新操作。 + +- **特性丰富** + + Nacos提供了包括服务发现、配置管理、动态 DNS 服务、服务元数据管理、流量管理、服务监控、服务治理等在内的一系列特性,帮助您在云原生时代,更轻松的构建、交付和管理微服务。 + +- **极致性能** + + Nacos经过阿里双十一超快伸缩场景的锤炼,提供高性能的服务注册和发现能力,以及低延迟的配置更新响应,确保在大规模分布式系统中的高效率和稳定运行。 + +- **超大容量** + + Nacos诞生自阿里的百万实例规模,造就支持海量服务和配置的管理,能够满足大型分布式系统对高并发和高可用性的需求。 + +- **稳定可用** + + Nacos 通过自研的同步协议,配合生态中应用广泛的Raft协议,确保了服务的高可用性和数据的稳定性,保证阿里双十一系统的高可用稳定运行。 + +- **开放生态** + + Nacos拥有活跃的开源社区、广泛的生态整合和持续的创新发展,不仅大量兼容了Spring Cloud、Dubbo等大受欢迎的开源框架、还提供了丰富的插件化能力,帮助用户在云原生时代,提供可定制满足自身特殊需求的独有云原生微服务系统。 + +## 设计理念 + +> 我们相信一切都是服务,每个服务节点被构想为一个星球,每个服务都是一个星系。Nacos 致力于帮助建立这些服务之间的**连接**,助力每个面向星辰的梦想能够透过云层,飞在云上,更好的链接整片星空。 + +Nacos希望帮助用户在云原生时代,在私有云、混合云或者公有云等所有云环境中,更好的构建、交付、管理自己的微服务平台,更快的复用和组合业务服务,更快的交付商业创新的价值,从而为用户赢得市场。正是基于这一愿景,Nacos的设计理念被定位为`易于使用`、`面向标准`、`高可用`和`方便扩展`。 + +![设计理念简图](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/design-philosophy.svg) + +#### 易于使用 + +易于使用是 Nacos 的一个核心理念,它通过提供用户友好的 Web 界面和简洁的 API 来简化服务的注册、发现和配置管理过程。开发者可以轻松集成 Nacos 到他们的应用中,无需投入大量时间在复杂的设置和学习上。 + +#### 面向标准 + +Nacos 采用面向标准的设计理念,遵循云原生应用开发的最佳实践和标准协议,以确保其服务发现和配置管理功能与广泛的技术栈和平台无缝对接。 + +#### 高可用 + +为了满足企业级应用对高可用的需求,Nacos 实现了集群模式,确保在节点发生故障时,服务的发现和配置管理功能不会受影响。集群模式也意味着 Nacos 可以通过增加节点来水平扩展,提升系统的整体性能和承载能力。 + +![Nacos高可用架构图](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/availability-structure.svg) + +#### 方便扩展 + +Nacos 还注重易于扩展,它采用了模块化的设计使得各个组件都可以独立地进行扩展或替换。这也为社区贡献者提供了方便,使他们能够针对特定的需求开发新的功能或者改善现有功能,进一步推动 Nacos 的生态发展。 + +![Nacos插件架构图](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/plugin-structure.svg) + +通过上述设计理念的实现,Nacos 为用户提供了一个强大而灵活的平台,以支持不断变化的业务需求,加速业务创新和数字转型,最终帮助用户在竞争激烈的市场中占据有利地位。 + +## 部署模式 + +Nacos 提供了两种两种部署运行模式:`单机模式`和`集群模式` + +![Nacos部署模式图](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/deploy-structure.svg) + +### 单机模式 + +单机模式又称`单例模式`, 拥有所有Nacos的功能及特性,具有极易部署、快速启动等优点。但无法与其他节点组成集群,无法在节点或网络故障时提供高可用能力。单机模式同样可以使用内置Derby数据库(默认)和外置数据库进行存储。 + +单机模式主要适合于工程师于本地搭建或于测试环境中搭建Nacos环境,主要用于开发调试及测试使用;也能够兼顾部分对稳定性和可用性要求不高的业务场景。 + +### 集群模式 + +集群模式通过自研一致性协议Distro以及Raft协议,将多个Nacos节点构建成了高可用的Nacos集群。数据将在集群中各个节点进行同步,保证数据的一致性。集群模式具有高可用、高扩展、高并发等优点,确保在故障发生时不影响业务的运行。集群模式**默认**采用外置数据库进行存储,但也可以通过内置数据库进行存储。 + +该模式主要适合于生产环境,也是社区最为推荐的部署模式。 + +## 生态组件 + +![Nacos生态图](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/ecology-structure.png) + +## 路线规划 + +![NacosRoadMap](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/roadmap.svg) + + + + + + + + + +> 1. diff --git a/src/projectessay/practicalProjects/flashSale/Maintenance of flash sale products.md b/src/projectessay/practicalProjects/flashSale/Maintenance of flash sale products.md index 353b91d..175a60e 100644 --- a/src/projectessay/practicalProjects/flashSale/Maintenance of flash sale products.md +++ b/src/projectessay/practicalProjects/flashSale/Maintenance of flash sale products.md @@ -6,7 +6,6 @@ category: - 秒杀系统 - 项目 - --- ## 1 秒杀设计 @@ -280,6 +279,20 @@ CREATE TABLE `tb_address` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ``` +其中最重要的就是秒杀商品表了:tb_sku + +![](https://qtp-1324720525.cos.ap-shanghai.myqcloud.com/blog/image-20241231202400064.png) + +商品状态:是看商品是否参与秒杀 + +是否锁定:会进行热点数据的实时分析,对分析出来的热点商品进行隔离操作,非热点数据-非锁定,热点数据-锁定。而且后面会进行热点和非热点的隔离下单,那么也需要`islock`去操作 + +秒杀数量:扣减,数量为0用户 + + + + + ## 2 项目介绍 ### 2.1 技术栈介绍 @@ -308,158 +321,9 @@ CREATE TABLE `tb_address` ( CentOS 7.6 -基础环境安装(Docker和JDK) - -#### 2.4.1 Docker和JDK安装 - -Docker安装 - -```bash -# 设置仓库 -yum install -y yum-utils device-mapper-persistent-data lvm2 -yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo - -#安装 -yum install -y docker-ce docker-ce-cli containerd.io - -#启动 -systemctl start docker - -#设置开机启动 -systemctl enable docker - -#安装好后,可以查看docker的版本 -docker -v - -#修改Docker配置文件,使用国内的Docker镜像: -vi /etc/docker/daemon.json - -# 添加以下内容 -{"registry-mirrors":["https://ncwlarc2.mirror.aliyuncs.com"]} - -#使之生效 -systemctl daemon-reload - -#重启 -systemctl restart docker -``` - -安装Docker Compose - -```bash -# 上传资料里的docker-compose-Linux-x86_64 - -# 移动并改名 -mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose - -# 将可执行权限应用于二进制文件: -chmod +x /usr/local/bin/docker-compose - -# 创建软链: -ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose - -# 测试是否安装成功: -docker-compose --version -``` - -JDK安装 - -```bash -# jdk镜像仓库:https://repo.huaweicloud.com/java/jdk/8u171-b11/ - -# 下载、解压jdk -wget https://repo.huaweicloud.com/java/jdk/8u171-b11/jdk-8u171-linux-x64.tar.gz -tar -zxf jdk-8u171-linux-x64.tar.gz -mv jdk1.8.0_171 /usr/local/jdk8 +安装看Docker栏安装安装文章 -# 配置环境 -vi /etc/profile - -# 添加内容: -export JAVA_HOME=/usr/local/jdk8 -export PATH=$JAVA_HOME/bin:$PATH - -# 配置生效命令 -source /etc/profile -#查看j版本命令 -java -version -``` - -unzip命令安装 - -```bash -yum install -y unzip -``` - -#### 2.4.2 创建Nacos - -```bash -# 启动容器 -docker run -id --name nacos \ ---restart=always -p 8848:8848 \ --e MODE=standalone nacos/nacos-server:1.4.1 -``` - -#### 2.4.3 创建MySQL - -后期要使用Canal,需要把MySQL的配置文件提取出来,所以要进行相关的配置文件的编写 - -```bash -#创建MySQL配置文件 -mkdir -p /mnt/mysql/conf -#创建配置文件mysql.cnf -vim /mnt/mysql/conf/mysql.cnf - -#内容如下: -[mysqld] -# 设置关闭二进制日志 -skip-log-bin -``` - -启动MySQL容器 - -```bash -# 创建MySQL网络环境,指定子网网段 -docker network create --subnet=172.36.0.0/16 seckill_network - -# 启动MySQL 指定容器IP,固定IP地址 -docker run -id --name seckill_mysql \ ---net seckill_network --ip 172.36.0.3 \ --v /mnt/mysql/data:/var/lib/mysql \ --v /mnt/mysql/conf:/etc/mysql/conf.d \ ---restart=always -p 3306:3306 \ --e MYSQL_ROOT_PASSWORD=eVcWs1dsEgiv4ijEZ1b6 mysql:8.0.18 -``` - -#### 2.4.4 创建Elasticsearch和kibana - -准备IK分词器 - -```bash -# 创建存放IK分词器的目录 -mkdir -p /mnt/elasticsearch/plugins/ik - -# 上传IK分词器 - -# 解压IK到指定路径 -tar -xf ik-7.4.0.tar -C /mnt/elasticsearch/plugins/ik -``` - -启动docker服务 - -```bash -# 创建单机版elasticsearch容器 -docker run -id --name elasticsearch \ ---net seckill_network --ip 172.36.0.13 \ --v /mnt/elasticsearch/plugins:/usr/share/elasticsearch/plugins \ ---restart=always -p 9200:9200 -p 9300:9300 \ --e "discovery.type=single-node" elasticsearch:7.4.0 - -# 创建kibana -docker run -id --name kibana --net seckill_network \ --e ELASTICSEARCH_HOSTS=http://172.36.0.13:9200 \ ---restart=always -p 5601:5601 kibana:7.4.0 -``` +最后: 连接kibana,测试中文分词