您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關怎么解析Nacos配置中心,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
上回我們說到Nacos的注冊中心,我們講了注冊中心的一致性協議,訂閱和注冊的原理,有興趣的可以看一下上一篇文章:你應該了解的Nacos注冊中心。在Nacos中還有一個功能特別重要那就是配置中心,在這里先不具體介紹配置中心是什么,先來憶苦思甜一波。
在我們最開始做一些簡單的學習項目的時候,我們會遇到一些需要配置的東西,比如數據庫連接池大小,用戶的黑名單等等,我們都把這些東西寫死在代碼里面,比如if(userId == 123){do something}
,這種代碼在項目里隨處可見。后來參加工作了,發現這種寫法并沒有將配置很好的統一管理起來,配置地方隨處可見,并且無法根據代碼環境去進行調整,比如線上和線下都只能使用同一個配置,雖然可以通過if,else的方式,但是這個非常麻煩,所以在工作就開始使用xml,yaml等方式在文件里面進行配置,在不同的運行環境讀取不同的配置。這種方式基本滿足了大部分的需求,但是后面遇到了一個需要動態去修改這些配置的情況,如果通過文件的方式我們就只能修改文件然后重新上線服務,這樣是非常麻煩的,所以就誕生了配置中心。
我們在這里可以想想,如果你要實現配置中心,應該具備哪些功能呢?我這里列舉一些:
可以動態的修改配置。
配置中心掛了也不影響配置的使用。
配置是可以多個服務共享的。
支持權限管理,只有授予權限的人才能查看和修改配置
配置可以回滾,當我們遇到配置出現問題的時候可以像回滾服務一樣回滾配置。
灰度發布,可以讓某幾臺機器先使用這個配置如果沒有問題,在進行全量。
配置中心自身的QPS能保證足夠,如果是一個公司的基礎服務的話是需要保證這個的
其實在開源的項目中有挺多配置中心的開源的比如spring cloud config
, Apollo
等等,其中Apollo是攜程開源的配置中心,在業界也是非常出名,我們這邊文章主要還是介紹Nacos的配置中心,當然有興趣的同學可以下來自行查看其他注冊中心相關介紹。
同樣的我們首先也先介紹一下和注冊中心相關的一些基本名詞概念:
命名空間(namespace):和注冊中心一樣,命名空間屬于Nacos頂層的結構,用于進行租戶級別的隔離,我們最常用的就是不同環境比如測試環境,線上環境進行隔離。
配置管理:系統配置的編輯、存儲、分發、變更管理、歷史版本管理、變更審計等所有與配置相關的活動。
配置項:一個具體的可配置的參數與其值域,通常以 param-key=param-value 的形式存在。例如我們常配置系統的日志輸出級別(logLevel=INFO|WARN|ERROR) 就是一個配置項。
配置集: 一組相關或者不相關的配置項的集合稱為配置集。在系統中,一個配置文件通常就是一個配置集,包含了系統各個方面的配置。例如,一個配置集可能包含了數據源、線程池、日志級別等配置項。
配置集 ID : Nacos 中的某個配置集的 ID。配置集 ID 是組織劃分配置的維度之一。
配置分組:Nacos 中的一組配置集,是組織配置的維度之一。
配置快照:Nacos 的客戶端 SDK 會在本地生成配置的快照。當客戶端無法連接到 Nacos Server 時,可以使用配置快照顯示系統的整體容災能力。配置快照類似于 Git 中的本地 commit,也類似于緩存,會在適當的時機更新,但是并沒有緩存過期(expiration)的概念。
配置中心的架構圖如下:
用戶可以在后臺界面進行添加或者修改配置,也可以通過client-api進行修改配置
所有修改的數據通過raft首先在Leader修改生效,然后同步至其他副本。
如果用戶想訂閱該配置通過long polling的方式進行訂閱。
配置中心最為關鍵的就是如何去做好存儲,一般我們存儲就兩種方式, 要么全內存存儲,能保證性能非常高,但是維護不同機器內存一致性復雜度比較高,還有一種就是使用數據庫,內存里面不維護任何狀態,每一臺機器都可以進行寫入操作,這個復雜度比較低,不需要考慮一致性的問題,但是由于所有的讀寫都會走數據庫所以性能就不能保證。在Nacos中對這兩種存儲方式做了一些改進,實現了既保證了性能又保證了復雜度一致性。
在Nacos1.3之后提供了mysql 和 raft + derby兩種存儲方式,接下來介紹一一介紹一下這兩種存儲方式。
nacos最開始提供的就是mysql的方式,所有機器都可以進行讀寫,沒有主備之分,如下圖所示:
如果只是使用mysql,有同學會提出問題,只使用mysql如何才能保證數據庫性能不會成為瓶頸呢?最簡單的方法就是使用高配置的Mysql,用錢給我干上去,很明顯這個不是很靠譜,只適用于土豪玩家。那么怎么去做這種優化呢?一般做業務的同學通常會在Mysql前面放一層緩存層,比如redis,memcached等等。
在Nacos中同樣的也使用了緩存這個概念幫助我們緩解數據庫壓力。但是和普通的緩存稍微有點不同:
在ConfigService中有一個HashMap緩存了所有Config的元數據(MD5,類型這些數據)
但是對于具體存儲的值我們不會直接放在內存,而是存儲到了本地磁盤,這么做的好處是因為我們的config所配置的值我們不能保證他的大小,如果每個config的值都很大,那么我們的內存必然會不足,這個時候Nacos和Apollo 兩個開源中間件給出兩種解法:
Apollo的做法是使用一個guavaCache,使用淘汰策略將不經常使用的進行淘汰。
Nacos的做法是全量緩存元數據,具體的值存儲到磁盤空間,采用分離存儲的方式,nacos采用這種方法,如果只是訪問元數據那么全量內存即可,不會像Apollo一樣可能會遇到淘汰的原因,訪問數據庫。
Nacos使用的是全量緩存元數據到內存,具體的值存儲到磁盤空間,但是會存在一個問題,那就是當一臺機器的數據發生變更,其他機器的內存怎么變更呢?這就需要我們的全量異步通知,在每一次修改數據的時候都會發送一個ConfigDataChage事件,然后本機接受并進行處理,然后發送這個變更消息到其他的所有機器上。
其他機器收到這個變更通知之后,會進行一次dump操作:
會先查詢元數據中的MD5,MD5其實也是根據我們配置中的值算出來的,所以能進行快速判斷這一次時候發生了值的變更,如果發生變更,我們就將這個值存儲到磁盤上。
如果我們這個機器是新啟動的,這個時候其實就不會存在任何緩存以及dump文件,那么DumpService會遍歷數據庫的所有數據,全量的都緩存到機器上,以便我們使用。
Nacos在1.3.0之后提供了一個新的存儲模式,那就是使用raft協議保證數據一致性,使用apache derby進行內嵌的數據存儲。提供這種方式的目的是減少用戶維護mysql數據庫集群的成本,并且簡化了集群部署的成本,部署Nacos的時候直接打包Nacos鏡像就好,不需要再單獨部署一套數據庫。
在Nacos中使用的是sofa-jraft,這個是螞蟻開源的一個java版本高性能的raft實現,不熟悉raft的同學可以閱讀以下raft的論文,了解過raft的同學應該都知道raft非常強化Leader的概念:
系統中必須存在且同一時刻只能有一個 leader,只有 leader 可以接受 clients 發過來的請求
Leader 負責主動與所有 followers 通信,負責將’提案’發送給所有 followers,同時收集多數派的 followers 應答
Leader 還需向所有 followers 主動發送心跳維持領導地位
我們發現所有的事情都和leader相關,那么我們的性能必定被限制在leader上面,所以在Nacos中選擇了對raft本身有大量優化的sofa-jraft,在sofa-jraft中做了如下的優化:
批量化:批量化操作是很多系統的一個優化策略,在jraft中同樣的也采用了批量化操作,通過disruptor 的 MPSC 模型批量消費,實現了下面的一些批量操作,提升了很多的性能:
批量提交 task
批量網絡發送
本地 IO batch 寫入
批量應用到狀態機
pipeline復制: pipeline是一種管道技術,幫助我們不再和以前請求-響應模型一樣,他可以持續往管道中放入請求,過程中而不需要等待請求的回復,在最后再一并讀取結果即可。在jraft中開啟pipeline性能會提升30%。
并行化:leader持久化log和發送Log到follower是并行的,發送到不同的follower也是并行的。
線性讀:在raft協議中,讀請求會按照 Log 處理,通過 Log 復制和狀態機執行來得到讀結果,然后再把結果返回給 Client。這種辦法的缺點是需要 Log 存儲、復制,這樣會帶來刷盤開銷、存儲開銷、網絡開銷,因此在讀操作很多的場景下對性能影響很大。在Sofajrat中進行了ReadIndex,Lease Read優化,讓所有的讀都可以在本地執行,這個對性能的提升特別大。
Apache Derby也是一個Java編寫的輕量級數據庫,Nacos通過這樣的設計其實是構建了一個輕量級的分布式數據庫,在每一臺的機器上都會有一個保存數據的數據庫,然后通過raft協議保證所有機器數據的一致性。
內嵌數據庫的方式并不比Mysql的方式更好,在性能上Mysql那種方式因為存了很多緩存,并且content也保存到磁盤上,讀取的時候基本不會走庫,所以Mysql的方式其實更好,但是內嵌數據庫的方式在運維部署的方式上是非常占優的。這里如何取舍需要用戶自己進行一個選擇
我們在上一節說到Nacos注冊中心中的訂閱是通過udp廣播+定時輪訓來獲取到,而在配置中心中采用的是長輪訓的方式進行訂閱變更,為什么這兩個實現訂閱會采用不同的方式來實現呢?我們注冊中心中所保存的數據都是小數據比如節點的Ip,端口等信息,但是我們在配置中心中你不能控制配置的大小,比如一個服務訂閱了100個配置,每個配置的數據大小是1M,如果按照定時輪訓的做法每次會拉100M的數據,顯然是不靠譜的,所以這里采用了長輪訓的方式,具體長輪訓的方式如下:
Step1: 客戶端定時發出長輪訓的請求,超時時間默認為30s。發出的請求是自己所有訂閱配置內容的MD5,這里我們不會把整個內容當成請求發出,不然又會出現上面所說的每次都會發出很多的數據。
Step2: 服務端收到這個請求后利用Servlet3.0的特性,開啟了異步AsyncContext。
Step3: 服務端存儲這個AsyncContext,等待配置的變更,數據的變更會通過DataChangeEvent事件中進行觸發,然后判斷之前請求中的md5和新更新的md5是否一樣,如果一致將變更信息寫入到AsyncContext的response中。
Ste4: 如果超時還沒有到,那么代表本次沒有配置進行更新,又會回到Step1。
通過這樣的方式,我們每次請求量都會很少,只有在數據真正更新的時候才會將真正的數據返回給我們。
我們可能有這樣的一個需求,我們需要驗證某個配置是否對業務上有影響,通常的配置中心都是直接修改,所有機器全量都會被更新,如果這個配置出現問題,那么就會全量的出現故障。在Nacos中提供了一個灰度的功能,我們可以將某個配置只給某一些機器使用,這樣就可以完成一些小流量驗證。
在Nacos中灰度發布也叫做beta發布,如下圖所示:
在nacos中的具體實現的是用一個單獨的表去保存beta相關的信息:
用beta_ips字段保存了我們需要灰度的機器,在客戶端訂閱進行長輪訓的時候,也會過濾是否是灰度的機器,如果是才會進行更新,下面是LongPollingService的代碼:
在Nacos中也提供了歷史版本,類似git的commit一樣,只要你有commitid你就能回滾到對應的版本,在Nacos用了一個history_config表來進行保存,我們可以通過這個表獲取我們某個配置的所有歷史,以此來進行回滾。
在Nacos中還有很多其他的功能,比如權限管理等等,在這里我就不一一介紹了。在Nacos的配置中心中設計得最為巧妙的也就是存儲和訂閱了,存儲Nacos提供了兩種模式,一個是Mysql+緩存+本次磁盤的方式,還有一種是通過raft+derby的方式,都有自己的優劣點。訂閱的話Nacos采用的和注冊中心完全不一樣的方式,通過長輪訓很好的解決了更新的實時通知,并且不需要大量請求資源。如果大家對Nacos感興趣,建議還是可以閱讀下Nacos的代碼。
上述就是小編為大家分享的怎么解析Nacos配置中心了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。