文章目录
nacos
启动服务器
- Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式):
sh startup.sh -m standalone
如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:
bash startup.sh -m standalone
- Windows
启动命令(standalone代表着单机模式运行,非集群模式):
startup.cmd -m standalone
ps:需要在bin目录下运行该命令,之后访问:http://localhost:8848/nacos,关闭时直接关闭cmd窗口就行
测试(OPEN API配置管理测试)
curl是一个命令行工具,用于http协议的测试,下载地址(windows):https://curl.haxx.se/windows/
-
发布配置
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=LaLaLa"
-
获取配置
curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
结果如下:
D:\curl\curl-7.74.0_2-win64-mingw\bin>curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test" LaLaLa
获取到了LaLaLa
编写程序获取配置
-
依赖
<dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>1.3.2</version> </dependency>
功能
-
服务发现与服务健康检查
服务发现不用说了(DNS、http访问),还提供服务的实时健康检查,防止像不健康的服务实例发送请求。
-
动态配置管理
消除了在更新配置时重新部署应用程序,这使配置的更改更加的高效、灵活
-
动态DNS服务
第一点提到的提供支持DNS的服务发现,旨在支持异构语言的服务发现,以域名的形式暴露,让三方应用方便的查阅
-
服务和元数据管理
管理数据中心的所有服务及元数据,包括服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略
针对微服务架构中的服务发现(已经用过)、配置管理(微服务架构中的配置中心)、服务治理的综合型解决方案。
ps:配置中心是对应用程序的配置进行一个统一管理,同一程序在不同的环境(开发、测试、生产)、不同集群(这个是什么,是多个注册中心的意思?比如eureka?)经常需要有不同的配置,所以需要有配置管理。
其他配置中心
市面上其他的主流的配置中心:springcloud config、Apollo、nacos和Disconf等(这个不再维护)。
对比 | springcloud config | Apollo | nacos |
---|---|---|---|
配置实时推送 | 支持(springcloud bus) | 支持(http长轮询1s内) | 支持(http长轮询1s内) |
版本管理 | 支持(git),我知道 | 支持 | 支持 |
配置回滚 | 支持(git) | 支持 | 支持 |
灰度发布 | 支持 | 支持 | 不支持 |
权限管理 | 支持(依赖git) | 支持 | 不支持 |
多集群 | 支持 | 支持 | 支持 |
多环境 | 支持 | 支持 | 支持 |
监听查询 | 支持 | 支持 | 支持 |
语言 | 只有Java | 主流语言,提供了Open API | 主流语言,提供了Open API |
配置格式校验 | 不支持 | 支持 | 支持 |
单机读(QPS) | 7(限流所致) | 9000 | 15000 |
单机写(QPS) | 5(限流所致) | 1100 | 1800 |
3节点读(QPS) | 21(限流所致) | 27000 | 45000 |
3节点写(QPS) | 5(限流所致) | 3300 | 5600 |
ps:Apollo的功能完善;nacos的性能最好,优势是整合了注册中心、配置中心,推荐nacos与Apollo
配置管理
nacos的配置管理,通过namespace、group、Data Id能够定位到一个配置文件。
配置集(Data Id)
一个配置文件就是一个配置集
配置项
存在于配置集中,以key=value的形式存在
配置分组(group)
对配置集进行分组,通过一个又意义的字符串(如buy或trade)来表示,不同的配置分组下可以有相同的配置文件,在创建配置时,若未填写配置分组的名称,默认采用DEFAULT_GROUP。
命名空间(namespace)
用于进行不同环境的配置隔离:开发环境、测试环境和生产环境。也可用于隔离不同的开发人员(用同一个nacos管理各自的配置)。不同的命名空间下,可以存在相同名称的配置分组或配置文件。
- 从一个用户的角度来看:开发、测试、生产环境
-
从多个用户(租户)的角度来看,每个用户可能有自己的namespace,每个用户的配置数据以及注册的服务数据都会归属到自己的namespace下。如超级管理员分配了三个用户:掌三、里斯、亡吾,各用户用自己的账号密码登录后,创建自己的namespace,如下
-
命名空间管理
某公司拥有开发、测试、生产三套环境,那么建立三个namespace,建立好之后,在配置管理与服务管理模块下所有页面,都会包含用于切换namespace的tab按钮,如下:
ps:public是默认的命名空间
配置文件的导出和导入(也可以克隆)
是界面操作,省略呵呵
配置文件回滚(历史版本不包含当前版本)
省略呵呵
监听
当配置信息发生变化的时候,nacos的服务端(注册中心)去通知客户端(正在运行中)
结果:
"C:\Program Files\Java\jdk1.8.0_45\bin\java.exe" "-javaagent:D:\Idea\IntelliJ IDEA
common:
config1:somethinglll
common:
config1:somethinghhh
打印出了更改后的配置
登录管理
-
修改密码
-
导入依赖
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>5.1.4.RELEASE</version> </dependency>
-
加密程序(这应该是MD5加密吧)
//该程序会在每次生成密码时会加随机盐,所以生成密码每次可能不一样 String encode = new BCryptPasswordEncoder().encode("123");
密码就是123,在数据库不是123
-
创建用户名和密码的时候,将上方的encode更新到数据库
insert into users(username,password,enabled)values('nacos2','$2a$10$nMR1p1Agm9ZzlCEh.22Sj.r5ekpnaIdbr0wxmOS3WUeVaE4vR9u2e,true'); insert into roles(username,role)values('nacos2','ROLE_ADMIN'); --管理员角色
-
-
可以将登录功能关闭
spring.security.enabled=false #这个是spring的认证 management.security=false security.basic.enabled=false nacos.security.ignore.urls=/**
替换以上内容(如果没有应该可以增加)
应用于分布式系统(important!)
单体应用的坏处:
- 复杂性逐渐变高,可维护性逐渐变差:业务模块都在一起,复杂度越来越高,修改时牵一发动全身
- 版本迭代速度逐渐变慢:修改局部,需要将整个应用编译、部署,启动时间过长
- 阻碍技术更新:若更新技术框架只能将系统全部重写,无法实现部分技术更新
- 无法按需伸缩:通过冗余部署完整应用的方式来实现水平扩展,无法针对某业务按需伸缩
区别于单体应用,一个微服务一般完成某个特定的功能,比如订单服务、用户服务等等。每一个微服务都是完整的应用,都有自己的业务逻辑和数据库,一些微服务还会发布API给其他微服务和客户端使用。
微服务的好处:
- 分而治之,易于团队的拆分和管理
- 可伸缩,能够单独对指定服务进行伸缩
- 局部容易修改,容易替换、部署,有利于持续集成和快速迭代
- 不会受限于任何技术栈
-
架构
-
发布配置
两个服务:sevice1、service2
service1
namespace: dev dataId: service1.yaml group: TEST_GROUP 格式:yaml 内容:common: name: service1_config
service2
namespace: dev dataId: service2.yaml group: TEST_GROUP 格式:yaml 内容:common: name: service2_config
-
父工程的主要依赖
<!--打包方式--> <packaging>pom</packaging> <properties> <spring-cloud.version>Edgware.SR4</spring-cloud.version> <spring-cloud-alibaba.version>1.5.0.RELEASE</spring-cloud-alibaba.version> <project.build.sourceEncoding>utf8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <lombok.version>1.16.18</lombok.version> <log4j.version>1.2.17</log4j.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--springboot的依赖 因为springcloud的版本是Edgware.SR4--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--数据源--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!--springboot启动器--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!--单元测试 日志--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> </dependencyManagement>
-
微服务service1配置
springcloud简介:
利用springboot巧妙地简化了分布式系统基础设施得到开发,如服务注册发现、配置中心、断路器等,springcloud没有重复地造轮子,将各家公司比较成熟的框架组合起来,集成最多的要数Netflix公司,最终留下了一套简单易懂、易部署和维护的分布式系统开发工具包
springcloud alibaba:
springcloud alibaba是遵循springcloud微服务套件的标准所开发的一套微服务框架的集合。所以,springcloud alibaba和springcloud Netflix是springcloud微服务标准的实现,如果用springcloud alibaba,只需要加一些注解和少量配置,就可以将springcloud应用接入springcloud alibaba这一套方案,通过阿里的中间件来搭建分布式应用系统,nacos就是阿里的中间件,因此,开发springcloud微服务应用,使用springcloud alibaba来集成nacos的配置管理功能比较好。
1)依赖
<dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
2)bootstrap.yml
因为使用了外部的配置中心,同时因为bootstrap.yml的优先级高于application.yml,所以此处使用bootstrap.yml
server: port: 56010 spring: application: name: service1 cloud: nacos: config: server-addr: 127.0.0.1:8080 #配置中心地址,也是注册中心 file-extension: yaml #dataId是配置文件的名称,是application.name+扩展名(file-extension) #如service1.yaml 准确的说应该是${prefix}-${spring.profiles.active}.${file- #extension} namespace: e12e455c-c01e-4c0e-bb8b-e30b286434f9 #dev环境的id group: TEST_GROUP #测试组
3)动态获取更新的配置
@Autowired ConfigurableApplicationContext applicationContext; applicationContext.getEnvironment().getProperty("common.name");
小结:有问题可以去翻看日志,包括因手速过快拼错单词的问题
-
对在yml中配置时的namespace、group和dataId的理解
1)namespace:在没有指定
spring. cloud.nacos. config. namespace
时,默认是public命名空间。2)group:
在没有指定
spring. cloud.nacos. config. group`时,默认是DEFAULT_GROUP组。 ps:两者指定内容时必须在bootstrap.yml/properties文件中,原因上文有提到
3)dataId:
${prefix}-${spring.profiles.active}.${file-extension}
-
prefix
默认为spring.application.name
的值,也可以通过配置项spring.cloud.nacos.config.prefix
来配置。 -
spring.profiles.active
即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当spring.profiles.active
为空时,对应的连接符-
也将不存在,dataId 的拼接格式变成${prefix}.${file-extension}
-
file-exetension
为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension
来配置。目前只支持properties
和yaml
类型。放置多个dataId(在一个微服务里增加配置文件)
spring: application: name: service1 cloud: nacos: config: server-addr: 127.0.0.1:8848 #配置中心地址,也是注册中心 #增加的dataId在DEFAULT_GROUP,不支持动态刷新 ext-config[0]: data-id: ext-config-common01.properties #增加的dataId在GLOABLE_GROUP,不支持动态刷新 ext-config[1]: data-id: ext-config-common02.properties group: GLOABLE_GROUP #增加的dataId在REFRESH_GROUP,支持动态刷新 ext-config[2]: data-id: ext-config-common03.properties group: REFRESH_GROUP refresh: true
共享dataId(在多个微服务间共享dataId,不常用,只支持DEFAULT_GROUP)
spring: application: name: service1 cloud: nacos: config: shared-dataids: ext-config-common01.properties,ext-config-common02.properties,ext-config-common03.properties refreshable-dataids: ext-config-common01.properties
shared-dataids
共享dataId,refreshable-dataids
可动态刷新的配置。多个配置文件都可用“,”隔开。
-
-
配置的优先级
三种从nacos获取配置文件的方式
1)根据
${prefix}-${spring.profiles.active}.${file-extension}
自动生成dataId2)
ext-config[n]
增加多个dataId,此处的优先级是n值越大,优先级越高(应该是覆盖导致的)3)
shared-dataids
配置共享dataId(不推荐)当上方三种方式一起使用的时候,优先级:1)> 2)> 3)
-
关闭配置
设置
spring. cloud.nacos. config.enabled = false
来关闭配置
推荐的实践
namespace:代表环境,如:开发环境、测试环境和生产环境。
group:代表某项目,如xx电商项目。
Data Id:每个项目下往往有若干个工程,每个配置集(Data Id)是一个工程的主配置文件。
nacos集群部署
-
集群(3个及以上nacos节点才能构成集群)
1)复制原来的nacos文件夹即可
2)设置集群配置文件
在nacos的conf目录下,有
cluster.conf.example
,将其命名为cluster.conf
,并且在文件里设置好ip:port。# ip:port 127.0.0.1:8848 127.0.0.1:8849 127.0.0.1:8850
ps:这是单机的演示,同时需要更改nacos的conf目录下application.properties中的端口,防止端口冲突。
如果服务器有多个ip也要指定具体的ip地址,如:
nacos.inetutils.ip-address=127.0.0.1
(绑定nacos的ip地址,在nacos的application.properties配置中有这个参数,因为我的电脑或者是服务器ip地址可能是多个) 像这样:
server.port=8850 nacos.inetutils.ip-address=127.0.0.1
3)在生产环境是这样的:
生产环境的数据库至少主备模式,能够使nacos拥有多个数据源,如下:
### Count of DB: db.num=2 ### Connect URL of DB: 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.url.1=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user=root db.password=root
nacos配置管理小结
nacos配置管理主要是应用于微服务架构中配置中心的构建(应该是springcloud config的一种替代)
服务注册与发现
对比
功能 | nacos | eureka | consul | zookeeper |
---|---|---|---|---|
一致性协议 | 支持AP、CP | AP | CP | CP |
健康检查 | tcp/http/mysql/client beat | client beat | tcp/http/grpc/cmd | keep alive |
负载均衡 | 权重/metadata/selector | ribbon | fabio | - |
雪崩保护 | 有 | 有 | 无 | 无 |
自动注销实例 | 支持 | 支持 | 不支持 | 支持 |
访问协议 | http/dns | http | http/dns | tcp |
监听支持 | 支持 | 支持 | 支持 | 支持 |
多数据中心 | 支持 | 支持 | 支持 | 不支持 |
跨注册中心同步 | 支持 | 不支持 | 支持 | 不支持 |
nacos以后将会支持springcloud+kubernetes(这是啥,百度百科:简称K8s,是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了应用部署,规划,更新,维护的一种机制)的组合
架构
不罗嗦了呵呵
回顾springcloud的服务发现
springcloud是使用feign+ribbon技术来实现服务间远程调用及负载均衡的,如图:
-
负载均衡就是将用户请求通过策略,分摊到多个服务实例上执行,是处理高并发、缓解网络压力和进行服务端扩容的重要手段,分为服务端负载均衡和客户端负载均衡
- 服务端负载均衡
在负载均衡中维护一个服务清单,按照配置好的负载均衡算法(可以是默认的)选取一个去处理客户端的请求,这是服务端的负载均衡。以前老听到的nginx就是一个负载均衡的代理。
- 客户端负载均衡
ribbon属于客户端负载均衡,在ribbon客户端有一个服务注册表,在发送请求前通过负载均衡算法选择一个服务,然后进行访问,这是客户端负载均衡。
ribbon的核心是IRule,它是负载均衡策略接口,有如下实现(了解):
实现类 描述 RoundRobinRule(默认) 轮询,按顺序获取服务地址 RandomRule 随机,随机获取服务地址 AvailabilityFilteringRule 先过滤因为多次访问故障而处于断路器跳闸状态的服务和并发的连接数量超过阈值的服务,然后对剩余的服务按照轮询的策略进行访问 WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快,权重越大,被选中的几率越高;杠启动时,如果统计的信息不足,则使用RoundRobinRule(默认),等统计信息足够时,会切换到WeightedResponseTimeRule RetryRule 先按照RoundRobinRule(默认)获取服务,如果获取失败,则在指定时间内会进行重试,获取可用服务 BestAvailableRule 先过滤因为多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务 ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器(服务器?就这里不明白,应该是服务的意思) springboot修改默认的负载均衡策略(配置文件)
xxx-service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
ps:
xxx-service
是调用服务的名称,后面是固定的 -
远程调用。回顾之前写springcloud程序的时候使用的是RestTemplate去远程调用服务的,现在feign将其进一步简化。feign,它是声明式、模板化的http客户端,将http报文封装成了java接口,可快捷使用http协议。
1)依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
ps:feign默认集成了ribbon,可以直接使用。
2)声明feign客户端
@FeignClient(value = "provider1")//服务提供方的名字 public interface Provider1Agent{//生成动态代理对象 @GetMapping(value = "/service") public String service(); }
3)业务调用
@Autowired private Provider1Agent provider1Agent; ......
4)在启动类(springcloud)中添加
@EnableFeignClients
,表明此项目开启feign客户端@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class xxxx{ main函数 }
服务提供与消费实例
-
provider1
-
依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
application.yml
server: port: 56010 spring: application: name: provider1 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 logging: level: root: info org.springframework: info
-
注解
@EnableDiscoveryClient @EnableFeignClients @SpringBootApplication
ps:期间有一个小问题,
LoggerFactory.getLogger
这个静态方法idea不提示,在yml配置文件里面也没有提示,应该是idea的一个bug
-
-
consumer
-
依赖和上面一致,application如下:
server: port: 56020 spring: application: name: consumer cloud: nacos: discovery: server-addr: 127.0.0.1:8848
-
Client接口
@FeignClient("provider1") public interface Client { @GetMapping("/service") public String service(); }
-
controller如下:
@RestController public class ConsumerController { @Autowired Client client; @GetMapping("/service") public String service(){ //调用provider1里面的controller String result = client.service(); return "consumer调用:"+result; } }
-
启动类与提供者一致
-
-
多个提供者负载均衡
- 端口
server: port: ${port:56010} #动态端口,启动是没有传入下方的参数就默认56010
VM options:-Dport=56011
重这样就给provider1创建了两个服务(实例),相当于有provider2,因为启动了两次provider1
-
服务注册的模型
-
服务
提供的功能
-
服务名
通过该标识可以唯一确定其指代的服务
-
实例(ip+port)
可访问的进程,启动一个服务,就产生了一个服务实例
-
元信息
nacos数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、自定义标签,从作用范围来看分为服务级别的元信息、集群的元信息和实例的元信息。
ps:元信息能够让nacos更具备扩展性,用户可自定义数据英语描述实例、服务、集群等
-
集群
服务实例的集合,服务实例组成一个默认集群,集群可以被进一步按需求划分,划分的单位可以是虚拟集群,相同集群下的实例才能相互感知。
应用通过namespace、service、cluster(集群)的配置,描述了该服务向哪个环境(如开发环境)的哪个集群注册实例。
集群作为实例的隔离,相同集群的实例才能相互感知。namespace、cluster-name若不填写都将采取默认值,namespace默认public,cluster-name默认为DEFAULT集群,如下用provider1开启两个端口的实例集群
将consumer注册到dev里面
server: port: 56020 spring: application: name: consumer cloud: nacos: discovery: server-addr: 127.0.0.1:8848 namespace: e12e455c-c01e-4c0e-bb8b-e30b286434f9 #dev cluster-name: DEFAULT #默认集群,可不写
服务管理
-
权重
代表了被选中的几率越高
-
元数据
用户自定义信息,key-value的结果
-
下线(与权重为零一样的)
如其名,略
springcloud、springcloud alibaba与dubbo
之前总结过springcloud与dubbo的区别,简言之,springcloud的功能比dubbo完善,使用dubbo同时想有springcloud的生态,但是二者整合起来的使用方案还是不完善,springcloudalibaba解决了这个问题。
ps:feign是基于http restful的调用,在高并发下的性能不够理想,想将rpc方案切换为dubbo(在微服务的设计中,一个服务A如果访问另一个Module下的服务B,可以采用HTTP REST传输数据,并在两个服务之间进行序列化和反序列化操作,服务B把执行结果返回过来。由于HTTP在应用层中完成,整个通信的代价较高,远程过程,即rpc,调用中如果直接基于TCP进行远程调用,数据传输在传输层TCP层完成,更适合对效率要求比较高的场景,RPC主要依赖于客户端和服务端之间建立Socket链接进行,底层实现比REST更复杂。)
架构(推荐的生产环境):
dubbo底层采用socket(tcp或udp)进行通信,所以相比http可以提升效率
zuul(springcloud的网关)
Zuul是一个微服务网关,首先是一个微服务。也是会在注册中心中进行服务的注册和发现。也是一个网关,请求应该通过Zuul来进行路由。
zuul网关其底层使用ribbon来实现请求的路由,并内置Hystrix,可选择性提供网关fallback逻辑。使用zuul的时候,并不推荐使用Feign作为application client端的开发实现。毕竟Feign技术是对ribbon的再封装,使用Feign本身会提高通讯消耗,降低通讯效率,只在服务相互调用的时候使用Feign来简化代码开发就够了。而且商业开发中,使用Ribbon+RestTemplate来开发的比例更高。
工程结构
-
springcloud_nacos 原来的父工程
- nacos-micro-service 整体父工程
- gateway API网关,端口:56010
- application1 应用1,端口:56020 对外暴露http接口
- service-1 服务1父工程 对外暴露dubbo接口
- service-1-api 服务1API
- service-1-server 服务1实现,端口56030
- service-2 服务2父工程 对外暴露dubbo接口
- service-2-api 服务2API
- service-2-server 服务2实现,端口56040
- nacos-micro-service 整体父工程
构建过程
-
整体父工程依赖
<parent> <artifactId>springcloud_nacos</artifactId> <groupId>com.yyh</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>nacos-micro-service</artifactId> <packaging>pom</packaging>
-
application1
依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
配置文件
server: port: 56020 #http的端口 context-path: /application1 spring: application: name: application1 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 namespace: e12e455c-c01e-4c0e-bb8b-e30b286434f9 #dev cluster-name: DEFAULT config: server-addr: 127.0.0.1:8848 file-extension: yaml namespace: e12e455c-c01e-4c0e-bb8b-e30b286434f9 #dev group: NACOS_MICROSERVICE_GROUP #xx业务组
业务代码:
@RestController public class Application1Controller { @GetMapping public String service(){ return "test"; } }
-
service-1
-
service-1-api
接口:
public interface ConsumerService { public String service(); }
-
service-1-server
依赖
<dependency> <groupId>com.yyh</groupId> <artifactId>service-1-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dubbo</artifactId> <version>2.1.1.RELEASE</version> </dependency>
途中遇到个问题,dubbo的依赖最少2.0.0,idea无法自动识别添加依赖,需要自己去添加版本
接着出现另一个问题:
java.lang.NoSuchMethodError: org.springframework.boot.SpringApplication.getWebApplicationType()Lorg/springframework/boot/WebApplicationType;
dubbo2.7及以上在apache,以下在alibaba,因为我时springboot1.5x,我只能用2.7以下,so,我好像明白了,那么相应的 starter也只能是alibaba的starter。
参考文章:springboot与dubbo版本匹配问题
把下方
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dubbo</artifactId> <version>2.0.1.RELEASE</version> </dependency>
换成
<dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.5</version> </dependency> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.1.2.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo-registry-nacos</artifactId> <version>2.6.7</version> </dependency>
终于ok了,555555555555,但是还是不够兼容,服务名无法更改(显示的是ConsumerServiceImpl的路径)
再换
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-registry-nacos</artifactId> <version>2.7.1</version> </dependency>
然后。。。
java.lang.NoClassDefFoundError: com/alibaba/nacos/client/naming/utils/StringUtils
最后索性将爷爷的依赖拿到父级去,提高springcloud alibaba(1.5->2.1.0)、springcloud(Edgware.SR4->Greenwich.RELEASE)和springboot(1.5.3->2.1.3)的版本,问题大致上解决,虽然算不上好方法,但是问题大致解决
<properties> <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version> <spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version> <project.build.sourceEncoding>utf8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <junit.version>4.12</junit.version> <lombok.version>1.16.18</lombok.version> <log4j.version>1.2.17</log4j.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--springboot的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--数据源--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!--springboot启动器--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!--单元测试 日志--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> </dependencyManagement>
此方法有个问题,注册了三个端口一样的实例,原因未知:
-
-
增加application1的依赖并且注入service
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> </dependency> <dependency> <groupId>com.yyh</groupId> <artifactId>service-1-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
@RestController public class Application1Controller { //注入service(dubbo协议) @Reference ConsumerService consumerService; @GetMapping public String service(){ String service = consumerService.service(); return "test:"+service; } }
此处的@Reference得是dubbo的,@Reference会生成代理对象,然后进行远程调用
-
service-2与service-1类似,省略呵呵
-
service-1调用service-2
service-1-server添加依赖
<dependency> <groupId>com.yyh</groupId> <artifactId>service-2-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
在实现类这调用service-2
@Service//必须是dubbo的service 标记此类为dubbo接口 public class ConsumerServiceImpl implements ConsumerService{ //注入servive-2 @Reference//dubbo的 ProviderService providerService; @Override public String service() { //service1调用service2 String service = providerService.service(); return "Consumer(service1)调用:"+service; } }
至此,现在是application1->service-1(consumer)->service-2(provider)
-
网关
网关为服务的统一入口,,它会对请求进行过滤、校验(校验请求的合法性不合法将被拦截,解决访问)、路由等处理,因此提高了微服务的安全性。
zuul是springcloud的网关,它实现了请求路由、负载均衡、校验、过滤等功能。
在实际项目中zuul与nginx配合使用,nginx的作用是反向代理、负载均衡,zuul的作用是保障微服务的安全访问,拦截微服务请求、校验合法性和负载均衡,看图:
1)在gateway中添加依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2)在nacos界面新建gateway.yaml配置文件(配置路由),内容如下:
zuul: routes: application1: stripPrefix: false path: /application1/**
path的意思是以application1开头的都转发到application1上面
3)在启动类上面添加
@EnableZuulProxy
注解,欧了