注册中心

注册中心在微服务项目中扮演着非常重要的角色,是微服务架构中的纽带,类似于”通讯录“,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就到这里找到服务的地址,进行调用。

在分布式系统中,我们面临着以下几个问题

如何管理庞大的网状服务结构?
服务宕机后,如何及时下线?
流量高峰时,服务如何有效的水平扩展?

springboot nacos用户名和密码加密_SpringCloud


除了基本的服务注册与发现机制,从开发和运维角度,至少还要考虑如下五个方面:

  • 测活:服务注册之后,如何对服务进行测活以保证服务的可用性?
  • 负载均衡:当存在多个服务提供者时,如何均衡各个提供者的负载?
  • 集成:在服务提供端或者调用端,如何集成注册中心?
  • 运行时依赖:引入注册中心之后,对应用的运行时环境有何影响?
  • 可用性:如何保证注册中心本身的可用性,特别是消除单点故障?

Nacos快速上手

Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。中文文档非常齐全,文档地址戳

springboot nacos用户名和密码加密_spring_02


springboot nacos用户名和密码加密_AlibabaCloud_03

下载与启动

  • 源码下载
$ git clone https://github.com/alibaba/nacos.git
$ cd nacos/
$ mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  
$ ls -al distribution/target/

// change the $version to your actual path
$ cd distribution/target/nacos-server-$version/nacos/bin
  • 安装包下载
    可以从 最新稳定版本 下载 nacos-server-$version.zip 包。
    Windows 下载解压后(.zip),直接点击 bin/startup.cmd 就可以了。

    如果不小心报了如下错:
java.io.IOException: java.lang.IllegalArgumentException: db.num is null
org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup
work.boot.web.server.WebServerException: Unable to start embedded Tomcat

那说明你的Nacos默认是集群模式,需要改为单机模式

  • 找到startup.cmd文件,并编辑
  • 把集群模式改为单机模式
set MODE="cluster"
改为:
set MODE="standalone"
  • Linux/Unix/Mac
$ unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
$ cd nacos/bin

启动命令(standalone代表着单机模式运行,非集群模式):

$ sh startup.sh -m standalone

如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:

$ bash startup.sh -m standalone

springboot nacos用户名和密码加密_Nacos_04

  • 打开控制台:
    Nacos提供了一个可视化的操作平台,安装好之后,在浏览器中输入http://localhost:8848就可以访问了,默认的用户名和密码都是nacos(我使用的是1.3.0版本)

构建服务

它和Eureka不一样,并不需要创建新的web项目,而是和ZookeeperConsul一样,只需要下载安装启动后,将我们的微服务注册进去就可以了。 创建两个微服务,一个客户端(调用者)和一个服务端(提供者)

这里我先创建一个名为it235-nacos-parent的聚合模块父项目,后续所有模块均在该父项目中完成

springboot nacos用户名和密码加密_AlibabaCloud_05


springboot nacos用户名和密码加密_注册中心_06


springboot nacos用户名和密码加密_Nacos_07

调用端(消费者)
  • 创建项目
  • 引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
	<!--继成springboot-->    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.it235.nacos</groupId>
    <artifactId>order-service-consumer</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>order-service-consumer</name>
    <description>订单服务作为消费者</description>

    <!--声明相关依赖版本-->
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <!--作为web容器启动-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--加入阿里服务发现依赖 重要-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

    <!--alibaba cloud 相关依赖管理-->
    <dependencyManagement>
        <dependencies>
            <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>
        </dependencies>
    </dependencyManagement>

    <!--springboot 打包构建插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
  • 添加Nacos配置
  • 修改application.properties文件为bootstrap.yml(Nacos首先加载该命名文件)
  • bootstrap.yml中加入如下配置
server:
  port: 6010
spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        #必须配置ip地址
        server-addr: localhost:8848
        # 将自己的服务注册到注册中心
        register-enabled: true
        #namespace: all-register-service-namespace
	```
  • Application启动类加入服务发现注解@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient //重点
public class OrderServiceConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceConsumerApplication.class, args);
    }
}

springboot nacos用户名和密码加密_注册中心_08


springboot nacos用户名和密码加密_spring_09

  • 启动服务,查看Nacos控制台的服务列表
提供端(生产者)
  • 创建项目
    依葫芦画瓢创建course-service-provider项目,并配置,此处忽略
  • 引入依赖
    order-service-consumer的依赖保持一致
  • 添加Nacos配置
server:
  port: 6020
spring:
  application:
    name: course-service
  cloud:
    nacos:
      discovery:
        #必须配置ip地址
        server-addr: localhost:8848
        # 将自己的服务注册到注册中心
        register-enabled: true
        #namespace: all-register-service-namespace
  • 课程服务主Application启动类添加服务发现注解
@SpringBootApplication
@EnableDiscoveryClient  //重要
public class CourseServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(CourseServiceProviderApplication.class, args);
    }
}
启动服务

springboot nacos用户名和密码加密_SpringCloud_10


springboot nacos用户名和密码加密_Nacos_11

添加服务调用代码

为最简单演示,这里我直接使用restTemplate对象来进行远程服务调用

  1. 给course-service模块添加controller控制器,用来提供给远程服务调用
@RestController
@RequestMapping("course")
public class CourseController {

    @GetMapping("list")
    public String get(){
        return "已经访问到课程服务";
    }
}

springboot nacos用户名和密码加密_Nacos_12

  1. order-service模块添加controller控制器,用来调用course-service的服务
  • order-service服务主Application中注入restTemplate对象
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceConsumerApplication {

    // 新增restTemplate对象注入方法,注意,此处LoadBalanced注解一定要加上,否则无法远程调用
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    // 新增 end
    
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceConsumerApplication.class, args);
    }
}
		```
  • 添加OrderController,并使用restTemplate对象调用远程的课程服务方法
@RestController
@RequestMapping("order")
public class OrderController {
    
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("get")
    public String get(){
        //通过服务名的方式调用远程服务(非ip端口)
        String result = restTemplate.getForObject(
            "http://course-service/course/list", String.class);
        return result;
    }
}

springboot nacos用户名和密码加密_spring_13

  • 启动服务,并查看Nacos注册情况
  1. 浏览器访问URL,进行测试http://localhost:6010/order/get 如果能正常返回course-service提供的值,则表示Demo运行成功
  2. 错误解析
    如出现nested exception is java.net.UnknownHostException: course-service错误,请在order-service项目的主Application中加上@LoadBalanced注解
    课件代码详见:https://gitee.com/appdoc/it235.git,tag名:1.0.0

MySQL支持

在前面的学习中,我们对于Nacos服务端自身并没有做过什么特殊的配置,一切均以默认的单机模式运行,完成了上述所有功能的学习。但是,Nacos的单机运行模式仅适用于学习与测试环境,对于有高可用要求的生产环境显然是不合适的。

在搭建Nacos集群之前,我们需要先修改Nacos的数据持久化配置为MySQL存储。默认情况下,Nacos使用嵌入式数据库实现数据的存储。所以,如果启动多个默认配置下的Nacos节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只要支持MySQL的存储。

在0.7版本之前,在单机模式时nacos使用嵌入式数据库实现数据的存储,不方便观察数据存储的基本情况。0.7版本增加了支持mysql数据源能力,Nacos 1.2.0版本后自动支持MySQL8.0+,具体的操作步骤:

  • 安装数据库,版本要求:5.6.5+
  • 初始化mysql数据库
  • 修改conf/application.properties文件,增加支持mysql数据源配置(目前只支持mysql),添加mysql数据源的url、用户名和密码。
# 此项一定要启用,默认是注释掉的
spring.datasource.platform=mysql

# 注意MySQL8.0以上版本指定url时一定要带入serverTimezone参数
db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos_config?serverTimezone=Asia/Shanghai&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=123456

# 可选启用配置
nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false
  • 这个的application.properties指nacos的解压目录nacos/conf目录下的文件
  • 这里的db具体配置根据自身情况而变

再以单机模式启动nacosnacos所有写嵌入式数据库的数据都写到了mysql,访问UI查看是否部署成功,并进行数据库验证。

  1. 添加一行配置
    Nacos主界面->配置管理->右边+号新建
  2. 保存发布
  3. 数据库查看

启动异常分析
若同学出现如下错误,请检查MySQL相关配置

  • db.url未指定serverTimezone
org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
...
Caused by: com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value '?й???????' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
  • Nacos早期版本不兼容MySQL8.0数据库
    Nacos 1.2.0之前的版本使用的mysql-connector-java-version.jar为5.x,如果要使Nacos 1.2.0支持MySQL8.0+数据库,需要替换该驱动包。
  • 找到Nacos的target目录下的nacos-server.jar
  • 使用压缩工具打开,进入BOOT-INF\lib 目录下,将mysql-connector-java-5.x.jar版本的删除,替换为8.x的jar
  • 替换后结果如下