SpringCloud
2021-03-20 00:00:00

微服务相关概念

  1. 微服务 是分布式架构最佳的实践方案,将单体应用拆分成若干个服务,基于服务进行开发和部署。

  2. SpringCloud 是微服务框架,集成了微服务的各种功能组件,比如Eureka、Nacos、Fegin、Dubbo等等,同时SpringCloud还是基于SpringBoot的,实现了这些组件的自动装配,可以开箱即用。

    • Dubbo是一款RPC框架,它的核心在于服务的远程调用,是不提供注册中心、配置中心、网关等组件的。

微服务开发规范:

  • 服务的单一职责
  • 每个服务有独立的数据库,从物理上隔离
  • 服务对外暴露接口,供其他服务调用

架构的演变

单体架构:以项目为单元进行开发部署,优点:架构简单,部署方便。缺点代码耦合性高、依赖关系复杂、项目太大编译时间过长。

分布式架构:以模块为单元进行开发部署,一个业务就是一个模块/服务。优点;耦合性降低,缺点:架构相对复杂,服务的治理问题

我感觉这种模块更好一点吧,如果让网关直接路由到底层服务,那客户端岂不是要调用很多个接口来实现聚合?

是的,网关直接路由到底层服务的实现方式通常被称为”普通网关模式”,它通常需要客户端调用多个API端点来收集所需的数据,这可能会导致较大的网络延迟和性能瓶颈,并对前端应用程序的开发和维护造成一定的负担。相比之下,使用BFF模式将前端应用程序和后端微服务之间引入了一个专用的中间层,可以减轻客户端的工作负担,并简化了前端应用程序的开发和维护。

在你的具体实现中,将不同的功能模块(例如用户、商家和管理)分别作为不同的BFF层,非常符合BFF模式的一般实现方式。这种实现方式可以为前端应用程序提供精细化的功能模块,同时避免了前端应用程序直接依赖后端微服务的设计缺陷。

需要注意的是,这种设计模式并不是适用于所有业务场景。在一些需要处理大量重复逻辑的简单系统中,使用BFF模式可能会增加不必要的复杂度。但是,在一些需要在前端应用程序和后端微服务之间建立复杂的数据交互和数据协同关系的较大规模系统中,BFF模式可能会是一种更好的设计模式选择。

Gateway网关的作用并不只是简单地路由请求到后端服务,它还可以提供负载均衡、安全认证、限流控制、请求转换等功能。此外,使用Gateway网关还可以将所有的API流量集中到一个入口,方便进行监控和管理。

因此,即使使用了BFF模式,Gateway网关仍然是一个有用的组件,可以提供一些额外的功能和保证API的稳定性。此外,Gateway网关可以将微服务和BFF层之间进行解耦,使得后端服务可以更加灵活地进行管理和部署。

当然,在具体的实现中,还需要根据具体的业务需求和技术架构来选择是否使用Gateway网关。如果整个系统较为简单或者实现时需要节省成本,也可以考虑直接让前端应用程序调用BFF层。

Nacos

为什么需要注册中心?

如果没有服务注册中心,那么服务调用时服务地址就要硬编码,一是地址不好维护,二是集群无法扩展,以及无法感知健康状态等等。而注册中心相当于一个中间件,维护了服务的地址和健康状态,服务调用都先经过服务注册中心。

Nacos是Alibaba开源的服务管理和配置管理平台,提供服务的注册发现和服务的动态配置。相当于Eureka + consul + bus。

官方文档下载地址

配置文件

conf/application.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//控制台URI路径
server.servlet.contextPath=/nacos
//端口号
server.port=8848

//数据库持久化,nacos有内嵌的数据库,但一般都会配置外部的数据库
//如果配置后启动日志报错`No Database set`,检查数据库的配置是否有误
#*************** Config Module Related Configurations ***************#
### If use MySQL as datas ource:
# spring.datasource.platform=mysql

### Count of DB:
# db.num=1

### Connect URL of DB:
# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
# db.user.0=数据库用户名
# db.password.0=数据库密码

如果要配置外部的数据库,首先要创建一个数据库,以及创建naocs相关的表,导入conf/nacos-mysql.sql即可

Nacos权限验证

Nacos权限漏洞问题 在 < 2.0的版本中

通过GET http://localhost:2478/nacos/v1/auth/users/?pageNo=1&pageSize=9 可以访问用户列表

通过POST http://127.0.0.1:2478/nacos/v1/auth/users?username=test1&password=test 可以添加用户

https://nacos.io/zh-cn/blog/announcement-token-secret-key.html

解决办法:

  1. 修改配置文件

    1
    2
    3
    4
    5
    6
    nacos.core.auth.enabled=true #设置为true

    # 下面这三个不要使用默认值,也有漏洞,随机就好
    nacos.core.auth.server.identity.key=serverIdentity #随机字符串
    nacos.core.auth.server.identity.value=security #随机字符串
    nacos.core.auth.plugin.nacos.token.secret.key=SecretKey01234567890123456789012345678901234567890123456789012345678 #自定义密钥时,推荐将配置项设置为Base64编码的字符串,且原始密钥长度不得低于32字符
  2. 开启权限认证后项目中要设置username和password

    1
    2
    3
    4
    5
    6
    7
    8
    spring:
    application:
    name: user-service #这个name是服务的名称,也叫做serviceId,一定要配置
    cloud:
    nacos:
    discovery:
    username: nacos
    password: nacos

在 >2.0 的版本中,默认是不需要授权的,必须要将nacos.core.auth.enabled设置为true,而且不要使用官方的默认值!!

单机启动

1
2
3
4
5
6
7
cd nacos/bin
#单机启动
sh startup.sh -m standalone
#集群启动
sh startip.sh
#停止
sh shutdown.sh

启动成功,访问Web控制台: http://localhost:8848/nacos,默认用户名密码: nacos/nacos

集群启动

集群的作用就是防止单节点挂掉无法提供服务,配置很简单:

  1. 首先使用集群就必须配置数据库持久化

  2. 准备多台服务器,在每个服务器的nacos的conf目录下配置cluster.conf

    1
    2
    3
    4
    //每个服务器的ip以及nacos端口
    192.168.1.109:8848
    192.168.1.119:8858
    192.168.1.129:8868

    当然也可以在一台服务器下启动多个nacos,根据端口做集群配置

  3. 启动nacos命令:sh startup.sh,注意没有 -m standalone

命名空间

nacos的命名空间的作用是项目隔离,一个nacos服务可以配置多个项目,一个项目即对应一个命名空间。(当然也可以每个项目都配置一个nacos,视情况而定)。

使用:在控制台创建命名空间后会给一个命名空间id,在项目中配置namespace属性即可

服务注册

  1. 引入依赖

    父工程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <!-- alibaba下依赖的版本号管理,放在dependencyManagement子工程才会继承 -->
    <dependencyManagement>
    <dependencies>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.9.RELEASE</version>
    <type>pom</type> <!-- 注意这里的type是pom,它不是jar包 -->
    <scope>import</scope>
    </dependency>
    </dependencies>
    </dependencyManagement>

    子工程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!-- spring cloud alibaba nacos discovery 依赖 -->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <!-- 引入 Web 功能 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  2. 启动类配置注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //开启服务发现,这个注解只代表其他的服务可以调用它。不加该注解也会成功注册的
    @EnableDiscoveryClient
    @SpringBootApplication
    public class NacosClientApplication {

    public static void main(String[] args) {
    SpringApplication.run(NacosClientApplication.class, args);
    }

    }
  3. 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    server:
    port: 8000

    # 以下是nacos的配置
    spring:
    application:
    name: ecommerce-nacos-client #这个name是服务的名称,也叫做serviceId,一定要配置
    cloud:
    nacos:
    discovery:
    enabled: true # 使用nacos
    server-addr: 127.0.0.1:8848 #nacos地址
    # server-addr: 127.0.0.1:8848,127.0.0.1:8858,127.0.0.1:8868 # 集群地址配置
    namespace: e2302326-7a3d-40e9-bc8c-2de52f4073a6 # 命名空间
  4. 测试一下

    可以先去控制台服务列表看一下是否注册成功,然后用代码写个接口来获取一下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Slf4j
    @Service
    public class NacosClientService {

    //这是SpringCloud提供的接口
    @Autowired
    private DiscoveryClient discoveryClient;

    //传入上面定义的spring.application.name
    public List<ServiceInstance> getInstances(String serviceId) {
    log.info("获取服务实例,serviceId: [{}]", serviceId);
    List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
    return instances;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @RestController
    public class NacosClientController {

    @Autowired
    private NacosClientService nacosClientService;

    /**
    * 获取服务实例
    * @param serviceId 服务名称 spring.application.name
    * @return
    */
    @GetMapping("service-instance")
    public List<ServiceInstance> getServiceInstances(String serviceId) {
    return nacosClientService.getInstances(serviceId);
    }

    }

版本问题

com.alibaba.nacos.api.exception.NacosException: Request nacos server failed:

2.x的服务端可以兼容1.x的客户端,但是1.x的服务端不能兼容2.x的客户端。

解决办法:

  1. 修改服务端版本

  2. 修改客户端版本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
    <exclusion>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
com.alibaba.nacos nacos-client 1.4.1 Dubbo
1
2
3
4
5
6
7
8
9
10

## 服务配置

# Gateway

# Dubbo


|