天天看點

微服務注冊中心如何承載大型系統的千萬級通路?一、問題起源

一、問題起源

Spring Cloud微服務架構體系中,Eureka是一個至關重要的元件,它扮演着微服務注冊中心的角色,所有的服務注冊與服務發現,都是依賴Eureka的。不少初學Spring Cloud的朋友在落地公司生産環境部署時,經常會問:Eureka Server到底要部署幾台機器?我們的系統那麼多服務,到底會對Eureka Server産生多大的通路壓力?Eureka Server能不能抗住一個大型系統的通路壓力?如果你也有這些疑問,别着急!咱們這就一起去看看,Eureka作為微服務注冊中心的核心原理下面這些問題,大家先看看,有個大概印象。帶着這些問題,來看後面的内容,效果更佳!Eureka注冊中心使用什麼樣的方式來儲存各個服務注冊時發送過來的機器位址和端口号?各個服務找Eureka Server拉取系統資料庫的時候,是什麼樣的頻率?各個服務是如何拉取系統資料庫的?一個有幾百個服務,部署了上千台機器的大型分布式系統,會對Eureka Server造成多大的通路壓力?Eureka Server從技術層面是如何抗住日千萬級通路量的?先給大家說一個基本的知識點,各個服務内的Eureka Client元件,預設情況下,每隔30秒會發送一個請求到Eureka Server,來拉取最近有變化的服務資訊舉個例子:庫存服務原本部署在1台機器上,現在擴容了,部署到了3台機器,并且均注冊到了Eureka Server上。然後訂單服務的Eureka Client會每隔30秒去找Eureka Server拉取最近系統資料庫的變化,看看其他服務的位址有沒有變化。除此之外,Eureka還有一個心跳機制,各個Eureka Client每隔30秒會發送一次心跳到Eureka Server,通知人家說,哥們,我這個服務執行個體還活着!如果某個Eureka Client很長時間沒有發送心跳給Eureka Server,那麼就說明這個服務執行個體已經挂了。光看上面的文字,大家可能沒什麼印象。老規矩!咱們還是來一張圖,一起來直覺的感受一下這個過程。

微服務注冊中心如何承載大型系統的千萬級通路?一、問題起源

二、Eureka Server設計精妙的系統資料庫存儲結構

現在咱們假設手頭有一套大型的分布式系統,一共100個服務,每個服務部署在20台機器上,機器是4核8G的标準配置。也就是說,相當于你一共部署了100 * 20 = 2000個服務執行個體,有2000台機器。每台機器上的服務執行個體内部都有一個Eureka Client元件,它會每隔30秒請求一次Eureka Server,拉取變化的系統資料庫。此外,每個服務執行個體上的Eureka Client都會每隔30秒發送一次心跳請求給Eureka Server。那麼大家算算,Eureka Server作為一個微服務注冊中心,每秒鐘要被請求多少次?一天要被請求多少次?按标準的算法,每個服務執行個體每分鐘請求2次拉取系統資料庫,每分鐘請求2次發送心跳這樣一個服務執行個體每分鐘會請求4次,2000個服務執行個體每分鐘請求8000次換算到每秒,則是8000 / 60 = 133次左右,我們就大概估算為Eureka Server每秒會被請求150次那一天的話,就是8000 * 60 * 24 = 1152萬,也就是每天千萬級通路量好!經過這麼一個測算,大家是否發現這裡的奧秘了?首先,對于微服務注冊中心這種元件,在一開始設計它的拉取頻率以及心跳發送頻率時,就已經考慮到了一個大型系統的各個服務請求時的壓力,每秒會承載多大的請求量。是以各服務執行個體每隔30秒發起請求拉取變化的系統資料庫,以及每隔30秒發送心跳給Eureka Server,其實這個時間安排是有其用意的。按照我們的測算,一個上百個服務,幾千台機器的系統,按照這樣的頻率請求Eureka Server,日請求量在千萬級,每秒的通路量在150次左右。即使算上其他一些額外操作,我們姑且就算每秒鐘請求Eureka Server在200次~300次吧。是以通過設定一個适當的拉取系統資料庫以及發送心跳的頻率,可以保證大規模系統裡對Eureka Server的請求壓力不會太大。現在關鍵的問題來了,Eureka Server是如何保證輕松抗住這每秒數百次請求,每天千萬級請求的呢?要搞清楚這個,首先得清楚Eureka Server到底是用什麼來存儲系統資料庫的?三個字,看源碼!接下來咱們就一起進入Eureka源碼裡一探究竟:

微服務注冊中心如何承載大型系統的千萬級通路?一、問題起源

如上圖所示,圖中這個名字叫做registry的CocurrentHashMap,就是系統資料庫的核心結構。看完之後忍不住先贊歎一下,精妙的設計!從代碼中可以看到,Eureka Server的系統資料庫直接基于純記憶體,即在記憶體裡維護了一個資料結構。各個服務的注冊、服務下線、服務故障,全部會在記憶體裡維護和更新這個系統資料庫。各個服務每隔30秒拉取系統資料庫的時候,Eureka Server就是直接提供記憶體裡存儲的有變化的系統資料庫資料給他們就可以了。同樣,每隔30秒發起心跳時,也是在這個純記憶體的Map資料結構裡更新心跳時間。一句話概括:維護系統資料庫、拉取系統資料庫、更新心跳時間,全部發生在記憶體裡!這是Eureka Server非常核心的一個點。搞清楚了這個,咱們再來分析一下registry這個東西的資料結構,大家千萬别被它複雜的外表唬住了,沉下心來,一層層的分析!首先,這個ConcurrentHashMap的key就是服務名稱,比如“inventory-service”,就是一個服務名稱。value則代表了一個服務的多個服務執行個體。舉例:比如“inventory-service”是可以有3個服務執行個體的,每個服務執行個體部署在一台機器上。再來看看作為value的這個Map:Map<String, Lease>這個Map的key就是服務執行個體的idvalue是一個叫做Lease的類,它的泛型是一個叫做InstanceInfo的東東,你可能會問,這倆又是什麼鬼?首先說下InstanceInfo,其實啊,我們見名知義,這個InstanceInfo就代表了服務執行個體的具體資訊,比如機器的ip位址、hostname以及端口号。而這個Lease,裡面則會維護每個服務最近一次發送心跳的時間

三、Eureka Server端優秀的多級緩存機制

假設Eureka Server部署在4核8G的普通機器上,那麼基于記憶體來承載各個服務的請求,每秒鐘最多可以處理多少請求呢?根據之前的測試,單台4核8G的機器,處理純記憶體操作,哪怕加上一些網絡的開銷,每秒處理幾百請求也是輕松加愉快的。而且Eureka Server為了避免同時讀寫記憶體資料結構造成的并發沖突問題,還采用了多級緩存機制來進一步提升服務請求的響應速度。在拉取系統資料庫的時候:首先從ReadOnlyCacheMap裡查緩存的系統資料庫。若沒有,就找ReadWriteCacheMap裡緩存的系統資料庫。如果還沒有,就從記憶體中擷取實際的系統資料庫資料。在系統資料庫發生變更的時候:會在記憶體中更新變更的系統資料庫資料,同時過期掉ReadWriteCacheMap。此過程不會影響ReadOnlyCacheMap提供人家查詢系統資料庫。一段時間内(預設30秒),各服務拉取系統資料庫會直接讀ReadOnlyCacheMap30秒過後,Eureka Server的背景線程發現ReadWriteCacheMap已經清空了,也會清空ReadOnlyCacheMap中的緩存下次有服務拉取系統資料庫,又會從記憶體中擷取最新的資料了,同時填充各個緩存。多級緩存機制的優點是什麼?盡可能保證了記憶體系統資料庫資料不會出現頻繁的讀寫沖突問題。并且進一步保證對Eureka Server的大量請求,都是快速從純記憶體走,性能極高。為友善大家更好的了解,同樣來一張圖,大家跟着圖再來回顧一下這整個過程:

微服務注冊中心如何承載大型系統的千萬級通路?一、問題起源

四、總結

通過上面的分析可以看到,Eureka通過設定适當的請求頻率(拉取系統資料庫30秒間隔,發送心跳30秒間隔),可以保證一個大規模的系統每秒請求Eureka Server的次數在幾百次。同時通過純記憶體的系統資料庫,保證了所有的請求都可以在記憶體處理,確定了極高的性能另外,多級緩存機制,確定了不會針對記憶體資料結構發生頻繁的讀寫并發沖突操作,進一步提升性能。上述就是Spring Cloud架構中,Eureka作為微服務注冊中心可以承載大規模系統每天千萬級通路量的原理。

繼續閱讀