Spring Cloud Alibaba系列之-Nacos服务注册和配置中心(三)

一、实现目标

项目[ac-mall-cloud]各module注册到Nacos服务,并通过Nacos服务名访问接口

Nacos官网文档
Nacos官方GitHub地址
Nacos官方下载地址

二、Nacos(Naming Configuration Service)简介

2.1 是什么

1、一个更易于构建云远程应用的动态服务发现,配置管理和服务管理平台
2、Nacos就是:注册中心 + 配置中心的组合,等价于Nacos = Eureka + Config + Bus

2.2 能干嘛

1、替代Eureka做服务注册中心
2、替代Config做服务配置中心

2.3 注册中心比较
注册中心比较
Nacos和CAP
Nacos与其他注册中心特性对比
2.3.1 CAP 原则
  • C:一致性(Consistency)
  • A:可用性(Availability)
  • P:分区容错性(Partition tolerance)

P(分区容错):一般是针对多节点部署的系统,分区指网络分区(由于网络原因节点之间无法通信同步数据),容错指系统节点出现分区了对外依然要能提供服务,不能说分区了导致整个系统不能提供服务了。

在满足P的前提下,Client发一条数据给节点1,因为分区产生这条数据暂时无法同步给节点2。如果要保证整个分布式系统的数据一致性(C),肯定要牺牲掉可用性(A),也就是整个分布式系统对外暂时不可用,不然Client对节点1和节点2的这条数据查询的结果就不一致了。同样的道理,如果要保证A那肯定要牺牲掉C了,因为数据还没在节点间同步,Client查询节点1和节点2的这条数据结果肯定不一样。

2.3.2 BASE原则
  • BA:基本可用(Basically Available)
  • S:软状态(Soft State)
  • E:最终一致性(Eventual Consistency)

CAP原则是三选二,BASE原则是CAP的折中,C、A、P三个都要,但不用100%的保证每一个原则,分布式系统肯定优先保证P,多数时候是在C和A之间做权衡选择

2.3.3 各注册中心满足的CAP原则
  • mysql单机(CA)
  • eureka集群(AP)
  • zookeeper集群(CP)
  • nacos集群(AP或CP),临时节点走AP,持久化节点走CP
  • redis集群(AP)
2.3.4 脑裂问题

脑裂:集群(Master-Slave的情况)的脑裂通常是发生在节点之间通信不可达(分区)的情况下,集群会分裂成不同的小集群,小集群各自选出自己的master节点,导致原有的集群出现多个master节点的情况。

2.4 Nacos基础概念
2.4.1 Nacos服务发现和服务健康监测

Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。

Nacos 提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。

2.4.2 命名空间

用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

三、Nacos安装

可参考Nacos 快速开始Nacos Spring Cloud 快速开始

3.1 windows环境安装
3.1.1 正常操作

1、本地Java8+Maven环境已经OK

2、先从官网下载Nacos Nacos官方下载地址

下载地址

3、解压安装包


解压安装包

4、启动Nacos(错误示范)


startup.cmd

在Nacos的低版本中,可以直接点击运行bin目录下的startup.cmd来启动Nacos,但在高版本中,则会启动失败,原因是高版本默认采用了集群模式,用到了数据库,而我们没有配置数据库,因此启动失败。


启动失败

5、启动方式一
打开cmd命令窗口,在启动命令中指定单机模式运行

cd D:\install\nacos-server-2.0.0\nacos\bin
startup.cmd -m standalone
cmd命令窗口

运行成功后访问http://localhost:8848/nacos
默认账号nacos nacos

Nacos控制台界面

6、启动方式二
用编辑器打开startup.cmd文件,找到set MODE="cluster",修改成set MODE="standalone",将默认的集群模式改成单机模式。此时再双击startup.cmd就可以启动Nacos了

startup.cmd启动成功
3.1.2 问题处理
3.1.2.1 问题一
问题描述

双击startup.cmd启动文件,cmd命令窗口不出现(或闪一下),无法定位启动失败原因。

解决方案

改用cmd命令启动,cmd命令窗口会显示启动失败原因

cd /d D:\service\nacos-server-2.0.0\nacos\bin

startup.cmd -m standalone
启动失败截图

原因是没有配置JAVA_HOME环境变量,配置Java环境变量后,关闭cmd命令窗口再重新启动,或直接双击startup.cmd启动。

Nacos启动
3.2 Linux(ubuntu) 环境安装

1、将Nacos安装包文件上传到远程服务器

scp -r D:/install/nacos-server-2.0.0 root@[47.105.146.74](mailto:root@47.105.146.74):/data/nacos-server-2.0.0

2、登录远程服务器,启动Nacos

ssh root@47.105.146.74
输入密码

cd /data/nacos-server-2.0.0/nacos/bin

ubuntu 启动命令

bash startup.sh -m standalone

linux 启动命令

sh startup.sh -m standalone
启动

可以通过命令查看启动日志

tail -f /data/nacos-server-2.0.0/nacos/logs/start.out -n 1000
启动日志

4、Nacos控制台效果


Nacos控制台效果

四、项目[ac-mall-cloud]接入Nacos

4.1 父级工程配置

在父级工程 [ac-mall-cloud] pom.xml中引入Nacos依赖

 <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>${alibaba.cloud.version}</version>
 </dependency>

父级工程 [ac-mall-cloud] pom.xml全配置如下

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ac-mall-cloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>user-service</module>
        <module>product-service</module>
        <module>order-service</module>
    </modules>

    <packaging>pom</packaging>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
        <mysql.version>8.0.17</mysql.version>
        <mybatis.plus.version>3.2.0</mybatis.plus.version>
        <druid.version>1.1.10</druid.version>
        <boot.version>2.2.4.RELEASE</boot.version>
        <alibaba.cloud.version>2.1.0.RELEASE</alibaba.cloud.version>
        <lombok.version>1.18.10</lombok.version>
    </properties>

    <!-- 管理子类所有的jar包的版本,这样的目的是方便去统一升级和维护 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <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>${alibaba.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>

            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis.plus.version}</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.version}</version>
            </dependency>

            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <scope>provided</scope>
            </dependency>

        </dependencies>

    </dependencyManagement>

    <!-- 所有的子工程都会自动加入下面的依赖  -->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <!-- SpringBoot 工程编译打包的插件,放在父pom中就直接给所有子工程继承 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
4.2 module [user-service] 配置

1、在module [user-service]pom.xml中引入Nacos依赖

 <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 </dependency>

module [user-service]pom.xml全配置如下

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ac-mall-cloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.ac</groupId>
    <artifactId>user-service</artifactId>

    <dependencies>
        <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>

</project>

2、在module [user-service]application.yml配置文件中配置Nacos注册中心信息

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 47.105.146.74:8848

module [user-service]application.yml全配置如下

server:
  port: 8010

spring:
  application:
    name: user-service

  cloud:
    nacos:
      discovery:
        server-addr: 47.105.146.74:8848

3、补充说明
从Spring Cloud Edgware开始,@EnableDiscoveryClient可省略。只需加上相关依赖,并进行相应配置,即可将微服务注册到服务发现组件上。因此本项目中不需要在UserApplication启动类上加@EnableDiscoveryClient注解

4.3 module [order-service] 配置

module [order-service] 配置与[user-service]一样,此处省略

4.4 Naocs控制台

配置完成后,登录Naocs控制台,效果如下


Naocs控制台效果
4.4 改造module[user-service]和modul[order-service]RestTemplate的通信

将RestTemplate由IP访问,改成用服务名访问

@Service
public class OrderServiceImpl implements IOrderService {

    @Autowired
    OrderDao orderDao;

    @Autowired
    RestTemplate restTemplate;

    //final static String USER_SERVICE_URL="http://127.0.0.1:8010/users/{userId}";

    final static String USER_SERVICE_URL="http://user-service/users/{userId}"; //用服务名来替换IP

    public Order makeOrder(String productId, String userId) {

        /**
         * RestTemplate是java创造出来的,在java能够访问到网络资源的包是java.net.URLConnenction/Socket
         * RestTemplate是对URLConnenction的封装
         * apache--HttpClient 也是对URLConnenction/HttpURLConnenction的封装
         * oKHttp 也封装了URLConnenction
         * netty/rpc/grpc/thirt/tomcat
         */

        // 1、根据用户ID调用用户服务接口数据,查询用户的名字
        UserDto userDto = restTemplate.getForObject(USER_SERVICE_URL,UserDto.class,userId);
        String userName=userDto.getUserName();

        // 2、生成订单
        Order order = new Order();
        order.setId(UUID.randomUUID().toString());
        order.setCreateTime(new Date());
        order.setPriceFen(1600L);
        order.setUserId(userId);
        order.setUserName(userName);
        order.setProductId(productId);
        order.setOrderNo(UUID.randomUUID().toString());

        // 3、保存数据库
        orderDao.insert(order);

        return order;
    }
}

我们在浏览器中输入访问地址http://127.0.0.1:8020/orders/1/1 发现接口访问失败,控制台打印出异常信息java.net.UnknownHostException: user-service 这是因为RestTemplate无法识别Nacos注册中心中的user-service服务名。

由于Nacos服务注册与发现功能中,默认集成了Ribbon,因此我们可以在RestTemplate添加Ribbon注解,让Ribbon来解决识别服务名的问题。

在module[order-service]的OrderApplication中加入Ribbon注解@LoadBalanced,代码如下

@SpringBootApplication
public class OrderApplication {

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

    @Bean
    @LoadBalanced // Ribbon负载均衡注解
    RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

重启module[order-service],再次访问http://127.0.0.1:8020/orders/1/1 ,发现与之前用IP方式通信的效果一样了

image.png

五、Nacos重点补充

5.1 Nacos如何支持多环境

在日常使用中常常需要不同的环境,比如日常,预发,线上环境,如果是逻辑隔离可以使用命名空间,Nacos支持命名空间来支持多环境隔离,可以在Nacos控制台创建多个命名空间。如果需要物理隔离,就要部署多套Nacos环境。

5.2 Nacos有什么依赖

在单机模式下,Nacos没有任何依赖,在集群模式下,Nacos依赖MySQL做存储。

5.3 Nacos单机部署如何使用MySQL

Nacos单机模式默认使用内嵌的数据库作为存储引擎,如果想换成自己安装的MySQL也可以进行相关的配置。

5.4 生产环境如何部署Nacos

生产环境使用Nacos为了达到高可用不能使用单机模式,需要搭建Nacos集群。

5.5 Nacos部署环境

Nacos定义为一个IDC内部应用组件,并非面向公网环境的产品,建议在内部隔离网络环境中部署,强烈不建议部署在公共网络环境。

备注:应用内部流量可以走专用端口,然后在防火墙和安全组指定这个端口只允许你的其他服务器 IP 访问,更多安全配置可参考Nacos 配置安全最佳实践

5.6 Nacos支持三种部署模式
  • 单机模式 - 用于测试和单机试用。
  • 集群模式 - 用于生产环境,确保高可用。
  • 多集群模式 - 用于多数据中心场景。

六、问题思考

Nacos服务做集群时,服务A调用服务B,服务B有B1、B2、B3 三个服务,现在B1要更新发布新代码,会有几秒的短暂不可用,如果此时服务A刚好访问的是服务B1,那么对应功能就会出现不可用的情况。其实针对这个问题可用通过Sentinel服务降级与熔断来解决。

七、附录

项目源码地址

八、参考资料

Nacos 配置安全最佳实践

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容