一、背景
先來說說大背景,現在,很明顯的一個趨勢就是:微服務。
這個趨勢的底層驅動力就來源於分布式系統的普及,而微服務的各個特性是如今大大小小的企業無法拒絕的誘惑。
然后,用上了微服務的架構風格,用Spring Cloud,或者Dubbo搭了一套腳手架,就開始干起來了。
接下來,一眾小公司畫完了大餅之后,發現自己根本吃不下。這就是典型的落后勞動力與先進生產力的尖銳矛盾。這個時候,返璞歸真的想法是不能有了,重構代價太大。
當然,哪里有問題,哪里就有商機。各大XX雲廠商經過一系列包裝之后,用“雲原生(Cloud Native)”的新概念粉墨登場。
Spring Cloud Alibaba就是其中之一。
這個概念的一個核心價值就是:平滑上雲,賦能運維。最明顯的業務表象就是,會提供一套Open API,甚至是貼心的提供一個可視化控制台,傻瓜式的那種。
二、從NACOS說起
NACOS解決兩個核心問題:動態配置管理,服務注冊發現。
兼容性方面,除了支持自家的Dubbo,還對Spring Cloud,Kubernetes,Istio有所兼容
至此,不說道說道Eureka,都有點過意不去了。
我用下來的體驗是:NACOS完全可以替代Eureka了。
江山代有才人出,這是必然的結果。
在“雲原生”的大背景之下,NACOS順利成章的推出了Console,將觸角進一步延伸至服務的精細化管理。
當然,不排除Eureka也在憋大招。
再說說動態配置的特性。
當然,NACOS略勝一籌,可替代Spring Cloud Config了。
原先在Git/SVN上托管的配置項,都可以在Console上統一管理了。
如果想先睹為快,可以接下着往下讀。如果想再多了解一些,可以直接跳過這部分,閱讀下一個小節。
可以把NACOS理解成是一個中心化的服務,這在阿里系的架構中屢見不鮮。所以,必須得先啟動這個服務。
有兩個辦法:其一是直接clone源碼,使用maven打包。第二個辦法是直接下載GitHub release出來的壓縮包。
推薦后者。
方法1:主要運行以下命令:
git clone https://github.com/alibaba/nacos.git cd nacos/ mvn -Prelease-nacos clean install -U
經過一段時間的構建過程,在./distribution/target目錄下有我們想要的壓縮包。
方法2:進入https://github.com/alibaba/nacos/releases,找到壓縮包,下載。
為了演示,我們先用單機模式啟動。
Windows環境下:
startup.cmd -m standalone
一切就緒的話,訪問http://127.0.0.1:8848/nacos/index.html,使用nacos/nacos登錄。
接下來,隨便逛逛。
三、重要的概念
為了避免在Console中迷失自我,有必要先闡述幾個重要的概念。
這張圖很重要。表述了namespace、group和service/dataId的包含關系。
NACOS給的最佳實踐表明,最外層的namespace是可以用於區分部署環境的,比如test,uat,product等。同時,也有一個商業利用價值:多租戶。以namespace為單位,給用戶開辟使用空間。
其它兩個領域模型不用多解釋了,見名知意。其目的也非常明顯,就是為了能夠邏輯上區分兩個目標對象。
默認情況下,namespace=public,group=DEFAULT_GROUP。
明白了這個數據模型后,可以稍微玩轉一下Console了,比如新建若干個namespace:
namespace順利創建成功后,會在每個一級頁面看到由namespace組成的TAB,可以任意切換namespace,對其下的數據進行操作。比如下圖的配置列表:
當然,還有眾多的領域模型,但是跟這一講的關系不大了,下一講深入源碼的時候再進行剖析。接下來會創建一個Demo工程,用於構建基於NACOS的config server和discovery server。
在進行下一章節之前,強烈建議先創建一個Spring Boot樣板工程,可以不做任何配置,不添加任何一段代碼。
當然,為了讓這一講的內容更具實戰意義,我不會照搬官網的Demo,本文所作的Demo工程也可以從GitHub上克隆得到。請提前准備好,接下來的內容只會挑重點講解,側重點不會在如何搭建工程。
四、使用NACOS的搭建工程
工程名稱為:nacos-example,在各個pom.xml文件中相關依賴管理就不再贅述了。
現在來介紹一下,這個demo工程干了一件什么事:用戶在下單的時候,需要校驗用戶的狀態,商品是否上架以及購買的數量上限。
為了體現動態配置,用戶狀態和購買的數量上限做成配置項。而這兩者的配置在不同的namespace下是有所不同的。
為了體現服務間的調用,下單入口在order模塊,經由user模塊進行校驗。
根據上述,NACOS服務啟動好了后,我們分別創建dev,product兩個namespace,在寫spring boot配置的時候,填寫的不是test,product這些namespace名稱,而是ID,此ID會在namespace成功創建后,由系統自動分配,目前的生成規則就是隨機的UUID函數。
這樣的配置規則會存在很大的爭議,本文不做討論。
user模塊需要動態配置,所以可以看作是一個config client。又因為需要接受order模塊的調用,所以也是一個service provider。
同樣的,order模塊需要動態配置,所以也是一個config client。
至此,讀者會發現一些NACOS帶來的“弊病”,最顯現的問題就是“多重角色”帶來的侵入性。因為是中心化的架構,如果沒有做到很好的解耦,出現這個問題也不足為奇了。
特別是在遠程調用的角色分配上,NACOS嚴格遵從了“生產者-消費者”模型,在實際業務場景下,難免會有服務既是生產者,又是消費者,而Eureka是沒有這種區分的。
接下來把目光轉向配置。
阿里系的開源產品大多建議是用properties文件,由於個人習慣,我使用的是yml,達到的效果是一樣的。
值得注意的是,因為需要更高優先級的加載順序,所以配置文件必須使用bootstrap.yml。
user模塊的配置文件,區分了環境,為了增加辨識度,也定義了group進行隔離。如下:
server: port: 8100 spring: application: name: user cloud: nacos: config: server-addr: 127.0.0.1:8848 file-extension: yaml namespace: 7d3e5f19-a102-471a-b6e0-67bd7d1d35f3 group: USER_GROUP discovery: server-addr: 127.0.0.1:8848 namespace: 7d3e5f19-a102-471a-b6e0-67bd7d1d35f3 --- spring: profiles: prod cloud: nacos: config: server-addr: 11.162.196.16:8848 namespace: c4c81555-91e1-4ef5-8b57-77c5407b3481 discovery: server-addr: 11.162.196.16:8848 namespace: c4c81555-91e1-4ef5-8b57-77c5407b3481 --- spring: profiles: active: dev
order模塊的配置文件類似,不再贅述。
然后對自定義配置參數進行封裝。如果只有單個參數,可以不用JavaBean的形式,但是絕大多數情況下都是多參數配置的,本文給出了JavaBean形式的封裝。
user模塊使用到的配置參數:
import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; @Getter @Setter @ConfigurationProperties(prefix = "user") public class UserConfig { /** * 用戶狀態:enable-啟用,disable-禁用 */ private String status;
}
order模塊使用到的配置參數:
import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; @Getter @Setter @ConfigurationProperties(prefix = "order") public class OrderConfig { /** * 最大購買數量 */ private int maxNum = Integer.MAX_VALUE; /** * 是否上架 */ private boolean onSale = true; }
然后就是編寫功能實現代碼,主要入口在order模塊中的OrderController:
@RefreshScope @RestController @RequestMapping public class OrderController { @Autowired private OrderConfig config; @Autowired private UserRpcService userRpcService; @PostMapping(value = "/order") public String placeOrder(@RequestParam(name = "num", defaultValue = "1") Integer num) { if (!"enable".equals(userRpcService.getUserStatus()))
return "該用戶已被禁用,暫不能下單"; if (num <= 0) return "購買數量有誤"; if (!config.isOnSale()) return "商品未上架"; if (num > config.getMaxNum()) return "購買數量超限"; return "OK"; } }
一些列的下單校驗,第一個校驗是判斷用戶狀態,使用了基於Feign的遠程調用。當然,必須在user模塊中提供對應的Controller實現:
@RefreshScope @RestController @RequestMapping(value = "/user") public class UserController { @Autowired private UserConfig config; @GetMapping(value = "/status") public String getUserStatus() { return config.getStatus(); } }
Controller中的@RefreshScope注解就是用來實現配置自動更新的。
整個工程准備就緒之后,先別急着run,還需要在Console中添加配置,用以測試動態配置是否生效。
添加配置的過程不再贅述,需要注意的是Data Id的填寫規范。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 類型。
接下來就是分別啟動order和user兩個模塊,隨便玩玩。
五、其他功能簡介
NACOS會記錄配置文件的歷史版本,保留30天,同時還貼心的提供了一鍵回滾功能,回滾操作將會觸發配置更新。
NACOS提供了配置監聽的Open-API。注冊監聽采用的是異步 Servlet 技術。注冊監聽本質就是帶着配置和配置值的 MD5 值和后台對比。如果 MD5 值不一致,就立即返回不一致的配置。如果值一致,就等待一定時間段,返回空值。
最后就是優雅上/下線功能,算是NACOS的一大亮點。在每個服務詳情里面,可以有多個實例(instance),通過Console可以控制每個實例的上/下線。如果是重新上線的話,會有一段時間的注冊過程,並不是點擊“上線”按鈕之后就能立馬訪問到該實例。
六、NACOS的進階功能
如果決定要將NACOS大規模投產,上述功能還遠遠滿足不了條件。在這一章節,將會講解若干個進階功能,為你的NACOS服務保駕護航。
1、集群模式
只啟動一個NACOS服務實例未免有些勢單力薄了,前述內容都是在單機部署的前提下,這一小節教你如何部署一個NACOS集群。
找到conf/cluster.conf文件,如果沒有,就新建。編輯里面的內容,僅需指定機器的ip和port,最好是3個或者3個以上。如果沒有這么多機器資源,可以直接在一台機器上部署,區分端口號即可。如下:
# ip:port 192.168.0.88:8848 192.168.0.88:8849 192.168.0.88:8840
請注意,在集群模式下就不能用127.0.0.1或者localhost了,當前版本對於網卡解析存在bug。
這個問題是因為Nacos獲取本機IP時,沒有獲取到正確的外部IP,需要保證InetAddress.getLocalHost().getHostAddress()或者hostname -i的結果是與cluster.conf里配置的IP是一致的。
找到conf/application.properties,如果沒有,說明有問題。編輯里面的內容,主要目的是啟用MySQL作為存儲層(目前僅支持MySQL)。在該文件末尾追加:
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=123456
然后新建一個名為nacos的數據庫,運行conf/nacos-mysql.sql腳本文件。
以上,就是運行NACOS集群模式所需的配置內容。
因為要在一台機器上模擬多個NACOS服務,可以將配置好的工程復制出兩份,然后在conf/application.properties中修改端口號即可。
然后,分別在三個命令窗口啟動NACOS:
startup -m cluster
分別使用對應的端口號訪問Console,如果能順利打開,說明部署成功了。
最后,在上述搭建的demo工程中,修改server-addr的值,把其他NACOS訪問地址也加上去:
server: port: 8200 spring: application: name: order cloud: nacos: config: server-addr: 192.168.0.88:8848,192.168.0.88:8849,192.168.0.88:8840 file-extension: yaml namespace: 7d3e5f19-a102-471a-b6e0-67bd7d1d35f3 group: ORDER_GROUP discovery: server-addr: 192.168.0.88:8848,192.168.0.88:8849,192.168.0.88:8840 namespace: 7d3e5f19-a102-471a-b6e0-67bd7d1d35f3
2、安全措施
很遺憾,NACOS的官網並沒有就安全性進行詳細的介紹。唯一看到的accessKey和secretKey兩項疑似安全的配置項,卻是為了配合阿里雲的ACM而設立的。
讓我最為關注的配置文件加密功能也暫未release出來,以下是官方原話:
Nacos計划在1.X版本提供加密的能力,目前還不支持加密,只能靠sdk做好了加密再存到nacos中。
NACOS Console的安全性同樣很糟糕,密碼無法修改,用戶不能創建,也沒有角色、權限的概念。
NACOS的服務注冊與發現基於HttpURLConnection進行遠程調用,這個地方是提供了HTTPS的啟用開關,JVM參數名是:com.alibaba.nacos.client.naming.tls.enable。
除此之外,目前只能在NACOS的外圍做一些安全措施了。
3、一些有用的配置
nacos.home,這個是NACOS服務的啟動參數,以JVM參數的形式傳入。但是很遺憾,使用這個參數並不是很方便,需要修改啟動腳本,大概是在startup.sh文件中的104行:
JAVA_OPT="${JAVA_OPT} -Dnacos.home=${BASE_DIR}"
更為徹底的方法是修改BASE_DIR的值(默認為startup.sh文件的父目錄),大概在startup.sh文件中的71行:
export BASE_DIR=`cd $(dirname $0)/..; pwd`
nacos.logging.path,日志是一個系統運行最寶貴的附加產物,有的時候為了便於管理,需要自定義日志目錄。如果需要指定,同樣需要修改startup.sh腳本。大概在104行后追加一行:
JAVA_OPT="${JAVA_OPT} -Dnacos.logging.path=指定的目錄"
當然,日志級別也能指定,分別通過com.alibaba.nacos.naming.log.level和com.alibaba.nacos.config.log.level這兩個JVM參數指定。
不過,還需要特別說明一下,並非所有日志都是有價值的,可以根據實際情況進行刪減,否則會對服務器造成不必要的負擔,相關日志配置可以在conf/nacos-logback.xml文件中修改。
4、endpoint
在上述配置文件中所涉及的serverAddr參數是窮舉了所有可用的NACOS服務,在大規模應用場景下,這種配置方式顯然是不合理的。endpoint相當於一個DNS服務,可以代理所有NACOS服務,只需要指定一個訪問域名。
這篇文章是對endpoint的一個最佳實踐,並且給出了環境隔離的有效手段。
七、總結
本文是對Spring Cloud Alibaba Nacos的功能性介紹。
如果研發能力強勁的隊伍,可以現在嘗嘗這只“螃蟹”,順帶還能貢獻不少的PR。
個人建議先觀望一段時間,大概在v1.2.0版本之后,就可以逐漸引入到公司的技術棧內了