Alibaba之Nacos

上个月最后一天的凌晨,Spring Cloud Alibaba 正式入驻了 Spring Cloud 官方孵化器,并在 maven 中央库发布了第一个版本。

目前 Spring Cloud Alibaba 还只能算是预览版吧,里边的坑肯定不少,不过我还是决定试试,看看 Alibaba 到底靠谱不靠谱。

image

Spring Cloud Alibaba

目前 Spring Cloud Alibaba 项目还处于 Spring Cloud 官方孵化器中,打开它 Github 的就能看到 “亲切” 的中文文档。

它目前只有三个组件:

  • Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

  • Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

  • AliCloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。

看官方路线图上讲后边还会增加

  • Dubbo:Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。

  • RocketMQ:Apache RocketMQ™ 基于 Java 的高性能、高吞吐量的分布式消息和流计算平台。

  • Schedulerx:阿里中间件团队开发的一款分布式任务调度产品,支持周期性的任务与固定时间点触发任务。

  • AliCloud SLS:针对日志类数据的一站式服务,在阿里巴巴集团经历大量大数据场景锤炼而成。您无需开发就能快捷完成日志数据采集、消费、投递以及查询分析等功能,提升运维、运营效率,建立 DT 时代海量日志处理能力。

从数量上来看,Alibaba 的组件数量和目前 Netflix 的相比少了一多半,但是仔细看看各组件的功能描述,也就明白了。在没真正上手之前,我个人先大胆猜测一下:

  • Nacos = Eureka/Consule + Config + Admin
  • Sentinel = Hystrix + Dashboard + Turbine
  • Dubbo = Ribbon + Feign
  • RocketMQ = RabbitMQ
  • Schedulerx = Quartz
  • AliCloud OSS、AliCloud SLS 这三个应该是独有的
    链路跟踪(Sleuth、Zipkin)不知道会不会在 Sentinel 里
    以上只是猜测,待我从坑里爬出来之后再回来更新。也欢迎大家一起交流探讨~

这里我就先试试 Nacos。

Nacos

image

这是 Nacos 的架构图,可以看到它确实是融合了服务注册发现中心、配置中心、服务管理等功能,和我之前猜想的它是 Eureka/Consule + Config + Admin 的合体差不多。

另外通过官方文档发现,Nacos 除了可以和 Spring Cloud 集成,还可以和 Spring、SpringBoot 进行集成。

不过我们只关注于 Spring Cloud,别的就略过了,直接上手吧~

工程的目录结构如下:


alibaba
├── nacos-config
│   ├── pom.xml
│   └── src
├── nacos-consumer
│   ├── pom.xml
│   └── src
├── nacos-provider
│   ├── pom.xml
│   └── src
└── pom.xml

首先引入 Spring Cloud Alibaba 的 BOM


<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.4.RELEASE</version>
    <relativePath/>
</parent>
<properties>
    <spring-cloud.version>Finchley.SR2</spring-cloud.version>
    <spring-cloud-alibaba.version>0.2.0.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba.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>
    </dependencies>
</dependencyManagement>

这里版本号有坑,文档上说和 Spring Boot 2.0.x 版本兼容,但是实测 2.0.6.RELEASE 报错


java.lang.NoClassDefFoundError: org/springframework/core/env/EnvironmentCapable

Nacos Server

在使用 Nacos 之前,需要先下载 Nacos 并启动 Nacos Server。

Nacos Server 有两种运行模式:

  • standalone
  • cluster

不论哪种方式吧,都需要先去 https://github.com/alibaba/nacos/releases 下载最新的 release 包,然后解压,以 nacos-server-0.4.0.zip 为例

unzip nacos-server-0.4.0.zip
cd nacos

standalone 模式

此模式一般用于 demo 和测试,不用改任何配置,直接敲以下命令执行

sh bin/startup.sh -m standalone

Windows 的话就是

cmd bin/startup.cmd -m standalone

然后从 http://localhost:8848/nacos/index.html 进入控制台就能看到如下界面了

image

cluster 模式

集群模式需要依赖 MySQL,然后改两个配置文件:

conf/cluster.conf
conf/application.properties

具体怎么改,在这里就先不展开了。我们先用 standalone 模式撸起来,享受 coding 的快感,然后再慢慢转到 cluster 上边。

配置管理

在 nacos/pom.xml 里添加依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
</dependencies>

启动类不用修改


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

修改 bootstrap.yml

spring:
  application:
    name: nacos
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848

注意:必须是写在 bootstrap.yml 中,配置在 application.yml 中不行,启动报错

java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.application.name' in value "${spring.application.name}"

至于 bootstrap.yml 和 application.yml 的区别,之前讲过这里就不赘述了。

添加一个 Endpoint 便于观察

@RestController
@RequestMapping("/config")
@RefreshScope
public class ConfigController {

    @Value("${useLocalCache:false}")
    private boolean useLocalCache;

    @RequestMapping("/get")
    public boolean get() {
        return useLocalCache;
    }

}

注意一定要加@RefreshScope注解

小心!此处有坑!

这时候先别急着启动 NacosConfigApplication 的,需要需要通过调用 Nacos Open API 往 Nacos Server 里发布一个配置。dataId 为 nacos.properties,内容为useLocalCache=true

curl -X "POST" "http://127.0.0.1:8848/nacos/v1/cs/configs" \
     -H 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' \
     --data-urlencode "dataId=nacos.properties" \
     --data-urlencode "group=DEFAULT_GROUP" \
     --data-urlencode "content=useLocalCache=true
     

dataId 的完整格式如下:

{prefix}-{spring.profile.active}.${file-extension}

  • prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。
  • spring.profile.active 即为当前环境对应的 profile,详情可以参考 Spring >Boot 文档。 注意:当 spring.profile.active 为空时,对应的连接符 - >也将不存在,dataId 的拼接格式变成 {prefix}.{file-extension}
  • file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。

然后启动 NacosConfigApplication,从启动日志里能看到

Located property source: CompositePropertySource {name='NACOS', propertySources=[NacosPropertySource {name='nacos.properties'}]}

如果 propertySources 里边是空的,那抱歉,你掉到坑里边了。 如果你能看到之前发布的 dataId,那恭喜,请求 http://localhost:8080/config/get 就可以看到返回内容 true 了。

再次调用 Nacos Open API 修改内容为useLocalCache=false

再次访问 http://localhost:8080/config/get ,此时返回内容为false,说明程序中的useLocalCache值已经被动态更新了。

当然,以上手动调用 Nacos Open API 的方式也可以通过 Nacos Console 的可视化界面来操作

image

另外我们可以查询配置的历史记录并能快速回滚

image

还能查询到某个配置当前的被监听状态(这里的分页有些 bug)

image

数据源

经过了上边的一些简单操作,我们已经可以正常使用 Nacos 配置中心了。
但是不知道你有没有想过:配置数据是存在哪里呢?

我们没有对 Nacos Server 做任何配置,那么数据只有两个位置可以存储:

  • 内存
  • 本地数据库

如果我们现在重启刚刚在运行的 Nacos Server,会发现刚才加的 nacos.properties 配置还在,说明不是内存存储的。

这时候我们打开NACOS_PATH/data,会发现里边有个derby-data目录,Derby 是 Java 编写的数据库,属于 Apache 的一个开源项目。我们的配置数据现在就存储在这个库中。

Derby 我并不是很熟悉,那能不能将数据源改为我们熟悉的 MySQL 呢?当然可以了。

注意:不支持 MySQL 8.0 版本

这里我以本地运行的 MySQL 为例:

创建一个名为nacos_config的 database

将NACOS_PATH/conf/nacos-mysql.sql中的表结构导入刚才创建的库中,这几张表的用途就自己研究吧

修改NACOS_PATH/conf/application.properties,加入 MySQL 配置


db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=root

创建cluster.conf,填入要运行 Nacos Server 机器的 ip


192.168.100.155
192.168.100.156

我就是运行个 demo,没有多余机器来组建集群怎么办呢?

其实不用虚拟机,直接只填一个本地地址也是可以的(仅限于配置管理,服务发现不行)。

这里有两个坑:

Nacos Server 的数据源是用 Derby 还是 MySQL 完全是由其运行模式决定的:

  • standalone 的话仅会使用 Derby,即使在 application.properties 里边配置 MySQL 也照样无视;
  • cluster 模式会自动使用 MySQL,这时候如果没有 MySQL 的配置,是会报错的。
    官方提供的 cluster.conf 示例如下

#it is ip
#example
10.10.109.214
11.16.128.34
11.16.128.36

从习惯来看,这个#号后边的应该就是注释的,但是抱歉哦,必须删掉,否则下面的异常就扑面而来

Caused by: java.lang.NumberFormatException: For input string: "it is ip:0"
  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
  at java.lang.Long.parseLong(Long.java:589)
  at java.lang.Long.parseLong(Long.java:631)
  at com.alibaba.nacos.naming.core.DistroMapper.onServerStatusUpdate(DistroMapper.java:125)
  at com.alibaba.nacos.naming.core.DistroMapper.init(DistroMapper.java:100)
  at com.alibaba.nacos.naming.core.DistroMapper.<clinit>(DistroMapper.java:65)
  ... 79 common frames omitted

以上配置结束后,运行 Nacos Server 就能看到效果了。

除了 MySQL 的数据表发生了变化,我们会发现NACOS_PATH/data下的目录结构也发生了变化,多了config-data/DEFAULT_GROUP/nacos_config这么一个文件,里边的内容就是我们的配置

useLocalCache=true

这是容错呢?还是缓存呢?只有等看过源码才知道了。

服务发现

服务注册中心和服务发现的服务端都是由 Nacos Server 来提供的,我们只需要提供 Service 向其注册就好了。

首先我们先将 Nacos Server 由伪分布式改为 standalone 模式,原因后边再说吧。

这里模拟提供两个 service:provider 和 consumer

alibaba
├── nacos-provider
│   ├── pom.xml
│   └── src
└── nacos-consumer
│   ├── pom.xml
│   └── src
└── pom.xml

首先在 provider 和 consumer 的 pom 添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

在两者的 bootstrap.yml 中添加配置

provider


spring:
  application:
    name: nacos-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
server:
  port: 18080
consumer

spring:
  application:
    name: nacos-consumer
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
server:
  port: 18081
  

使用 Spring Cloud 的原生注解 @EnableDiscoveryClient 开启服务发现


@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosProviderApplication.class, args);
    }
}

提供 Endpoint 以供访问


@RestController
@RequestMapping("/echo")
public class EchoController {

    @RequestMapping(value = "/{string}", method = RequestMethod.GET)
    public String echo(@PathVariable String string) {
        return "Hello Nacos Discovery " + string;
    }

}

Consumer

在 NacosConsumerApplication 中集成 RestTemplate 和 Ribbon

@LoadBalanced
@Bean
public RestTemplate restTemplate() {
  return new RestTemplate();
}

提供 Controller

@RestController
@RequestMapping("/echo")
public class TestController {

    private final RestTemplate restTemplate;

    @Autowired
    public TestController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @RequestMapping(value = "/{str}", method = RequestMethod.GET)
    public String echo(@PathVariable String str) {
        return restTemplate.getForObject("http://nacos-provider/echo/" + str, String.class);
    }

}

分别启动 NacosProviderApplication 和 NacosConsumerApplication ,调用 http://localhost:18080/echo/windmthttp://localhost:18081/echo/windmt ,返回内容均为 Hello Nacos Discovery windmt,说明服务发现成功了。

这时候查看 Nacos Console 也能看到已注册的服务列表及其详情

image
image

现在来讲一下为什么前边要将 Nacos Server 由伪分布式再改为 standalone 模式。

单个节点的 Nacos Server 伪分布式在配置管理运行的好好的,但是到了服务发现,它就失效了。

通过 log 可以发现一些端倪,单节点的在选主的时候,无法正确选出 leader


==> logs/naming-raft.log <==
2018-11-13 16:38:56,424 INFO leader timeout, start voting,leader: null, term: 1

从而导致 Client 无法正常注册


java.lang.IllegalStateException: failed to req API:/nacos/v1/ns/instance after all servers([127.0.0.1:8848]) tried
    at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:339) ~[nacos-client-0.3.0.jar:na]
    at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:272) ~[nacos-client-0.3.0.jar:na]
    at com.alibaba.nacos.client.naming.net.NamingProxy.registerService(NamingProxy.java:171) ~[nacos-client-0.3.0.jar:na]
    at com.alibaba.nacos.client.naming.NacosNamingService.registerInstance(NacosNamingService.java:161) ~[nacos-client-0.3.0.jar:na]
    ... ...
    

小结

当今年年初 Dubbo 进入 Apache 孵化器的时候,就有预感阿里要与 Spring Cloud 结缘。只是没想到这么快。

如今 Spring Cloud Alibaba 已经进入了 Spring Cloud 官方孵化器,相信等不了多久也就能正式发布了。虽然大家在生产环境必然还不会这么快速地接入,但是总归是多了一种选择。

而 Nacos 作为微服务核心的服务注册与发现中心,让大家在 Eureka 和 Consule 之外有了新的选择,开箱即用,上手简洁,暂时也没发现有太大的坑。但将配置中心融合也融合进来是好是坏,这个我先按下不表。

总而言之,Spring Cloud Alibaba 的入驻对于 Spring Cloud 生态总归是好的~

本文示例代码:https://github.com/zhaoyibo/spring-cloud-study/tree/master/alibaba

参考

https://github.com/spring-cloud-incubator/spring-cloud-alibaba

https://github.com/alibaba/Nacos

https://nacos.io/en-us/docs/quick-start-spring-cloud.html

原文链接:https://windmt.com/2018/11/09/intro-to-spring-cloud-alibaba-nacos/

关注我:

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

推荐阅读更多精彩内容