瘋狂創客圈 經典圖書 : 《Netty Zookeeper Redis 高併發實戰》 面試必備 + 面試必備 + 面試必備 【博客園總入口 】html
瘋狂創客圈 經典圖書 : 《SpringCloud、Nginx高併發核心編程》 大廠必備 + 大廠必備 + 大廠必備 【博客園總入口 】java
入大廠+漲工資必備: 高併發【 億級流量IM實戰】 實戰系列 【 SpringCloud Nginx秒殺】 實戰系列 【博客園總入口 】mysql
推薦閱讀 |
---|
nacos 實戰(史上最全) |
sentinel (史上最全+入門教程) |
springcloud + webflux 高併發實戰 |
Webflux(史上最全) |
SpringCloud gateway (史上最全) |
和 1000+ Java 高併發 發燒友、 一塊兒 交流 、學習、入大廠、作架構,GO |
問題,既然有了Eureka ,爲啥還要用Nacos?
而 Nacos 做爲微服務核心的服務註冊與發現中心,讓你們在 Eureka 和 Consule 以外有了新的選擇,開箱即用,上手簡潔,暫時也沒發現有太大的坑。git
1 eureka 2.0閉源碼了。web
2 從官網來看nacos 的註冊的實例數是大於eureka的,面試
3 由於nacos使用的raft協議,nacos集羣的一致性要遠大於eureka集羣.redis
分佈式一致性協議 Raft,自 2013 年論文發表,以後就受到了技術領域的熱捧,與其餘的分佈式一致性算法比,Raft 相對比較簡單而且易於實現,這也是 Raft 能異軍突起的主要因素。算法
Raft 的數據一致性策略
Raft 協議強依賴 Leader 節點來確保集羣數據一致性。即 client 發送過來的數據均先到達 Leader 節點,Leader 接收到數據後,先將數據標記爲 uncommitted 狀態,隨後 Leader 開始向全部 Follower 複製數據並等待響應,在得到集羣中大於 N/2 個 Follower 的已成功接收數據完畢的響應後,Leader 將數據的狀態標記爲 committed,隨後向 client 發送數據已接收確認,在向 client 發送出已數據接收後,再向全部 Follower 節點發送通知代表該數據狀態爲committed。spring
springcloud config大部分場景結合git 使用, 動態變動還須要依賴Spring Cloud Bus 消息總線來經過全部的客戶端變化.sql
springcloud config不提供可視化界面
nacos config使用長鏈接更新配置, 一旦配置有變更後,通知Provider的過程很是的迅速, 從速度上秒殺springcloud原來的config幾條街,
目前 Spring Cloud Alibaba 主要有三個組件:
Nacos:一個更易於構建雲原生應用的動態服務發現、配置管理和服務管理平臺。
Sentinel:把流量做爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。
AliCloud OSS: 阿里雲對象存儲服務(Object Storage Service,簡稱
OSS),是阿里雲提供的海量、安全、低成本、高可靠的雲存儲服務。您能夠在任何應用、任什麼時候間、任何地點存儲和訪問任意類型的數據。
仔細看看各組件的功能描述,Spring Cloud Alibaba 套件和Spring Cloud Netflix套件大體的對應關係:
這是 Nacos 的架構圖,能夠看到它確實是融合了服務註冊發現中心、配置中心、服務管理等功能,相似於 Eureka/Consule + Config + Admin 的合體。
另外經過官方文檔發現,Nacos 除了能夠和 Spring Cloud 集成,還能夠和 Spring、SpringBoot 進行集成。
不過咱們只關注於 Spring Cloud,別的就略過了,直接上手實戰吧。
在使用 Nacos 以前,須要先下載 Nacos 並啓動 Nacos Server。
安裝的參考教程:
Nacos Server 有兩種運行模式:
此模式通常用於 demo 和測試,不用改任何配置,直接敲如下命令執行
sh bin/startup.sh -m standalone
Windows 的話就是
cmd bin/startup.cmd -m standalone
而後從 http://cdh1:8848/nacos/index.html 進入控制檯就能看到以下界面了
默認帳號和密碼爲:nacos nacos
測試環境,能夠先用 standalone 模式擼起來,享受 coding 的快感,可是,生產環境可使用 cluster 模式。
conf/cluster.conf conf/application.properties
大體以下:
1: cluster.conf,填入要運行 Nacos Server 機器的 ip
192.168.100.155 192.168.100.156
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
建立一個名爲nacos_config的 database,將NACOS_PATH/conf/nacos-mysql.sql中的表結構導入剛纔建立的庫中,這幾張表的用途就本身研究吧
問題來了: Nacos Server 的配置數據是存在哪裏呢?
咱們沒有對 Nacos Server 作任何配置,那麼數據只有兩個位置能夠存儲:
若是咱們如今重啓剛剛在運行的 Nacos Server,會發現剛纔加的 nacos.properties 配置還在,說明不是內存存儲的。
這時候咱們打開NACOS_PATH/data,會發現裏邊有個derby-data目錄,咱們的配置數據如今就存儲在這個庫中。
Derby 是 Java 編寫的數據庫,屬於 Apache 的一個開源項目
若是將數據源改成咱們熟悉的 MySQL 呢?固然能夠。
注意:不支持 MySQL 8.0 版本
這裏有兩個坑:
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 12345
以上配置結束後,運行 Nacos Server 就能看到效果了。
實戰的工程的目錄結構以下:
<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 來提供的,咱們只須要提供 Service 向其註冊就行了。
這裏模擬提供兩個 service:provider 和 consumer
alibaba ├── service-provider-demo │ ├── pom.xml │ └── src └── sevice-consumer-demo │ ├── pom.xml │ └── src └── pom.xml
<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>
使用 Spring Cloud 的原生註解 @EnableDiscoveryClient 開啓服務註冊與發現
package com.crazymaker.cloud.nacos.demo.starter; import com.crazymaker.springcloud.standard.context.SpringContextUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.Environment; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.List; @EnableSwagger2 @SpringBootApplication @EnableDiscoveryClient @Slf4j public class ServiceProviderApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ServiceProviderApplication.class, args); Environment env = applicationContext.getEnvironment(); String port = env.getProperty("server.port"); String path = env.getProperty("server.servlet.context-path"); System.out.println("\n--------------------------------------\n\t" + "Application is running! Access URLs:\n\t" + "Local: \t\thttp://localhost:" + port + path+ "/index.html\n\t" + "swagger-ui: \thttp://localhost:" + port + path + "/swagger-ui.html\n\t" + "----------------------------------------------------------"); } }
service-provider-demo 提供 一個很是簡單的 Rest 服務接口以供訪問
package com.crazymaker.cloud.nacos.demo.controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/echo") public class EchoController { //回顯服務 @RequestMapping(value = "/{string}", method = RequestMethod.GET) public String echo(@PathVariable String string) { return "echo: " + string; } }
spring: application: name: service-provider-demo cloud: nacos: discovery: server-addr: ${NACOS_SERVER:cdh1:8848} server: port: 18080
在 NacosConsumerApplication 中集成 RestTemplate 和 Ribbon
@LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); }
package com.crazymaker.cloud.nacos.demo.consumer.controller; import com.crazymaker.cloud.nacos.demo.consumer.client.EchoClient; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/echo") @Api(tags = "服務- 消費者") public class EchoConsumerController { //注入 @FeignClient 註解配置 所配置的 EchoClient 客戶端Feign實例 @Resource EchoClient echoClient; //回顯服務 @ApiOperation(value = "消費回顯服務接口") @RequestMapping(value = "/{string}", method = RequestMethod.GET) public String echoRemoteEcho(@PathVariable String string) { return "provider echo is:" + echoClient.echo(string); } }
spring: application: name: sevice-consumer-demo cloud: nacos: discovery: server-addr: 127.0.0.1:8848 server: port: 18081
訪問遠程的echo API:
服務提供者 service-provider-demo:
http://localhost:18080/provider/swagger-ui.html#/Echo_%E6%BC%94%E7%A4%BA
服務消費者:
[http://localhost:18081/consumer/swagger-ui.html#/服務- 消費者/echoRemoteEchoUsingGET](http://localhost:18081/consumer/swagger-ui.html#/服務- 消費者/echoRemoteEchoUsingGET)
註冊中心Nacos:
http://cdh1:8848/nacos/index.html#/serviceManagement?dataId=&group=&appName=&namespace=
這時候查看 Nacos Console 也能看到已註冊的服務列表及其詳情
Java項目通常都會有多個Profile配置,用於區分開發環境,測試環境,準生產環境,生成環境等,每一個環境對應一個properties文件(或是yml/yaml文件),而後經過設置 spring.profiles.active 的值來決定使用哪一個配置文件。
例子:
spring: application: name: sharding-jdbc-provider jpa: hibernate: ddl-auto: none dialect: org.hibernate.dialect.MySQL5InnoDBDialect show-sql: true profiles: active: sharding-db-table # 分庫分表配置文件 #active: atomiclong-id # 自定義主鍵的配置文件 #active: replica-query # 讀寫分離配置文件
Nacos Config的做用就把這些文件的內容都移到一個統一的配置中心,即方便維護又支持實時修改後動態刷新應用。
當使用Nacos Config後,Profile的配置就存儲到Data ID下,即一個Profile對應一個Data ID
Data ID的拼接格式:${prefix} - ${spring.profiles.active} . ${file-extension}
prefix 默認爲 spring.application.name 的值,也能夠經過配置項 spring.cloud.nacos.config.prefix 來配置
spring.profiles.active 取 spring.profiles.active 的值,即爲當前環境對應的 profile
file-extension 爲配置內容的數據格式,能夠經過配置項 spring.cloud.nacos.config.file-extension 來配置
Group 默認爲 DEFAULT_GROUP,能夠經過 spring.cloud.nacos.config.group 來配置,當配置項太多或者有重名時,能夠經過分組來方便管理
最後就和原來使用springcloud同樣經過@RefreshScope 和@Value註解便可
這回首先要在nacos中配置相關的配置,打開Nacos配置界面,依次建立2個Data ID
內容以下圖:
內容以下圖:
問題2:微服務Provider實例上,如何使用Nacos Config Client組件的有哪些步驟?
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>${nacos.version}</version> </dependency>
package com.crazymaker.cloud.nacos.demo.consumer.starter; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.Environment; import springfox.documentation.swagger2.annotations.EnableSwagger2; @EnableSwagger2 @EnableDiscoveryClient @Slf4j @SpringBootApplication( scanBasePackages = { "com.crazymaker.cloud.nacos.demo", "com.crazymaker.springcloud.standard" }, exclude = {SecurityAutoConfiguration.class, //排除db的自動配置 DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class, //排除redis的自動配置 RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class}) //啓動Feign @EnableFeignClients(basePackages = {"com.crazymaker.cloud.nacos.demo.consumer.client"}) public class ConfigDomeProviderApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = null; try { applicationContext = SpringApplication.run(ConfigDomeProviderApplication.class, args); System.out.println("Server startup done."); } catch (Exception e) { log.error("服務啓動報錯", e); return; } Environment env = applicationContext.getEnvironment(); String port = env.getProperty("server.port"); String path = env.getProperty("server.servlet.context-path"); System.out.println("\n----------------------------------------------------------\n\t" + "Application is running! Access URLs:\n\t" + "Local: \t\thttp://localhost:" + port + path + "/index.html\n\t" + "swagger-ui: \thttp://localhost:" + port + path + "/swagger-ui.html\n\t" + "----------------------------------------------------------"); } }
package com.crazymaker.cloud.nacos.demo.config.controller; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/config") @Api(tags = "Nacos 配置中心演示") public class ConfigGetController { @Value("${foo.bar:empty}") private String bar; @Value("${spring.datasource.username:empty}") private String dbusername; //獲取配置的內容 @ApiOperation(value = "獲取配置的內容") @RequestMapping(value = "/bar", method = RequestMethod.GET) public String getBar() { return "bar is :"+bar; } //獲取配置的內容 @ApiOperation(value = "獲取配置的db username") @RequestMapping(value = "/dbusername", method = RequestMethod.GET) public String getDbusername() { return "db username is :"+bar; } }
而後是在配置文件(bootstrap.yml)中加入如下的內容:
spring: application: name: nacos-config-demo-provider profiles: active: dev cloud: nacos: discovery: server-addr: ${NACOS_SERVER:cdh1:8848} config: server-addr: ${NACOS_SERVER:cdh1:8848} prefix: nacos-config-demo group: DEFAULT_GROUP file-extension: yaml server: port: 18083 servlet: context-path: /config
啓動程序,經過swagger ui訪問:
執行結果以下:
config.prefix 來對應主配置文件
使用spring.cloud.nacos.config.ext-config 選項來對應更多的文件
eg:
spring: application: name: nacos-config-demo-provider profiles: active: dev cloud: nacos: discovery: server-addr: ${NACOS_SERVER:cdh1:8848} config: server-addr: ${NACOS_SERVER:cdh1:8848} prefix: nacos-config-demo group: DEFAULT_GROUP file-extension: yaml ext-config: - data-id: crazymaker-db-dev.yml group: DEFAULT_GROUP refresh: true - data-id: crazymaker-redis-dev.yml group: DEFAULT_GROUP refresh: true - data-id: crazymaker-common-dev.yml group: DEFAULT_GROUP refresh: true - data-id: some.properties group: DEFAULT_GROUP refresh: true
啓動程序,發現能夠獲取到其餘data-id的配置 ,你們能夠自行配置。
在實際的應用中,存在着如下幾種環境隔離的要求:
一、開發環境、測試環境、準生產環境和生產環境須要隔離
二、不一樣項目須要隔離
三、同一項目,不一樣的模塊須要隔離
能夠經過三種方式來進行配置隔離:Nacos的服務器、namespace命名空間、group分組,在bootstrap.yml文件中能夠經過配置Nacos的server-addr、namespace和group來區分不一樣的配置信息。