3.Spring Cloud 之服務治理 - 搭建高可用的Eureka服務注冊中心

概述

著名的CAP理論指出相速,一個分布式系統(tǒng)不可能同時滿足C(一致性)料按、A(可用性)和P(分區(qū)容錯性)。由于分區(qū)容錯性在是分布式系統(tǒng)中必須要保證的,因此我們只能在A和C之間進行權衡秽澳。

Eureka Server提供服務注冊服務,各個節(jié)點啟動后戏羽,會在Eureka Server中進行注冊担神,這樣Eureka Server中的服務注冊表中將會存儲所有可用服務節(jié)點的信息,服務節(jié)點的信息可以在界面中直觀的看到始花。

Eureka看明白了這一點妄讯,因此在設計時就優(yōu)先保證可用性孩锡。在此Zookeeper保證的是CP, 而Eureka則是AP。Eureka各個節(jié)點都是平等的亥贸,幾個節(jié)點掛掉不會影響正常節(jié)點的工作躬窜,剩余的節(jié)點依然可以提供注冊和查詢服務。

在應用啟動后炕置,將會向Eureka Server發(fā)送心跳,默認周期為30秒荣挨,如果Eureka Server在多個心跳周期內(nèi)沒有接收到某個節(jié)點的心跳,Eureka Server將會從服務注冊表中把這個服務節(jié)點移除(默認90秒)朴摊。
  其次默垄,Eureka Client對已經(jīng)獲取到的注冊信息也做了30s緩存。即服務通過eureka客戶端第一次查詢到可用服務地址后會將結果緩存甚纲,下次再調用時就不會真正向Eureka發(fā)起HTTP請求了口锭。
  再次, 負載均衡組件Ribbon也有30s緩存介杆。**Ribbon會從上面提到的Eureka Client獲取服務列表鹃操,然后將結果緩存30s
  最后春哨,如果你并不是在Spring Cloud環(huán)境下使用這些組件(Eureka, Ribbon)组民,你的服務啟動后并不會馬上向Eureka注冊,而是需要等到第一次發(fā)送心跳請求時才會注冊悲靴。心跳請求的發(fā)送間隔也是30s臭胜。(Spring Cloud對此做了修改,服務啟動后會馬上注冊)
  Eureka Server之間通過復制的方式完成數(shù)據(jù)的同步癞尚,Eureka還提供了客戶端緩存機制耸三,即使所有的Eureka Server都掛掉,客戶端依然可以利用緩存中的信息消費其他服務的API浇揩。
  以上這幾個30秒正是官方wiki上寫服務注冊最長需要2分鐘的原因仪壮。Eureka通過心跳檢查、客戶端緩存等機制胳徽,確保了系統(tǒng)的高可用性积锅、靈活性和可伸縮性。
  而Eureka的客戶端在向某個Eureka注冊或時如果發(fā)現(xiàn)連接失敗养盗,則會自動切換至其它節(jié)點缚陷,只要有一臺Eureka還在,就能保證注冊服務可用(保證可用性)往核,只不過查到的信息可能不是最新的(不保證強一致性)箫爷。
除此之外,Eureka還有一種自我保護機制,如果在15分鐘內(nèi)超過85%的節(jié)點都沒有正常的心跳虎锚,那么Eureka就認為客戶端與注冊中心出現(xiàn)了網(wǎng)絡故障硫痰,此時會出現(xiàn)以下幾種情況:

  1. Eureka不再從注冊列表中移除因為長時間沒收到心跳而應該過期的服務
  2. Eureka仍然能夠接受新服務的注冊和查詢請求,但是不會被同步到其它節(jié)點上(即保證當前節(jié)點依然可用)
  3. 當網(wǎng)絡穩(wěn)定時窜护,當前實例新的注冊信息會被同步到其它節(jié)點中

因此效斑, Eureka可以很好的應對因網(wǎng)絡故障導致部分節(jié)點失去聯(lián)系的情況,而不會像Zookeeper那樣使整個注冊服務癱瘓柱徙。

創(chuàng)建服務

創(chuàng)建一個Eureka服務中心十分簡單,只需要引入相關依賴,添加注解,稍作配置即可鳍悠。
1.引入依賴

compile "org.springframework.cloud:spring-cloud-starter-eureka-server:${cloud_eureka}"

2.添加注解

@EnableEurekaServer

3.稍作配置

eureka:
    instance:
        #配置主機名
        hostname: eureka.alpha
        appname: reka-alpha
    client:
        #  、在默認設置下坐搔,Eureka服務注冊中心也會將自己作為客戶端來嘗試注冊它自己藏研,
        #    所以我們需要禁用它的客戶端注冊行為。
        #    因為當注冊中心將自己作為客戶端注冊的時候概行,發(fā)現(xiàn)在server上的端口被自己占據(jù)了蠢挡,然后就掛了
        register-with-eureka: false
        fetch-registry: false
        service-url:
            defaultZone: http://eureka.alpha:9871/eureka

這里訪問的是http://eureka.alpha,需要修改hosts文件將eureka.alpha指向127.0.0.1,如果不做指向,這里也可以使用localhost訪問,當然,為了后面的高可用配置建議這里做指向.

4.啟動服務,大功告成

代碼傳送門

高可用配置

主要是利用多個eureka相互注冊,下例用采用三臺服務器做集群部署,其中每臺eureka服務器向另外兩臺注冊自己的實例.
這里需要注意如下幾點

1.Eureka Server的同步遵循著一個非常簡單的原則:只要有一條邊將節(jié)點連接,就可以進行信息傳播與同步

2.如果Eureka A的peer指向了B, B的peer指向了C凳忙,那么當服務向A注冊時业踏,B中會有該服務的注冊信息,但是C中沒有涧卵。也就是說勤家,如果你希望只要向一臺Eureka注冊其它所有實例都能得到注冊信息,那么就必須把其它所有節(jié)點都配置到當前Eureka的peer屬性中柳恐。這一邏輯是在PeerAwareInstanceRegistryImpl#replicateToPeers()方法中實現(xiàn)的:

代碼傳送門

示例代碼中拆分了三個配置,可以根據(jù)這三個配置分別打成jar包運行即可,當然,這里建議配合docker-compose進行編排部署.

1.在Eureka中伐脖,一個instance通過一個eureka.instance.instanceId 來唯一標識,如果這個值沒有設置乐设,就采用eureka.instance.metadataMap.instanceId來代替讼庇。instance之間通過eureka.instance.appName 來彼此訪問,在spring cloud中默認值是spring.application.name,如果沒有設置則為UNKNOWN近尚。在實際使用中spring.application.name不可或缺,因為相同名字的應用會被Eureka合并成一個群集蠕啄。eureka.instance.instanceId也可以不設置,直接使用缺省值(client.hostname:application.name:port)
,同一個appNameInstanceId不能相同戈锻。

2.如果 eureka.client.registerWithEureka設置成true(默認值true)歼跟,應用啟動時,會利用指定的eureka.client.serviceUrl.defaultZone注冊到對應的Eureka server中格遭。之后每隔30s(通過eureka.instance.leaseRenewalIntervalInSeconds來配置)向Eureka server發(fā)送一次心跳哈街,如果Eureka server在90s(通過eureka.instance.leaseExpirationDurationInSeconds配置)內(nèi)沒有收到某個instance發(fā)來的心跳就會把這個instance從注冊中心中移走。發(fā)送心跳的操作是一個異步任務如庭,如果發(fā)送失敗叹卷,則以2的指數(shù)形式延長重試的時間,直到達到eureka.instance.leaseRenewalIntervalInSeconds * eureka.client.heartbeatExecutorExponentialBackOffBound這個上限,之后一直以這個上限值作為重試間隔坪它,直至重新連接到Eureka server骤竹,并且重新嘗試連接到Eureka server的次數(shù)是不受限制的。

3.在Eureka server中每一個instance都由一個包含大量這個instance信息的com.netflix.appinfo.InstanceInfo標識往毡,clientEureka server發(fā)送心跳和更新注冊信息是不相同的蒙揣,InstanceInfo也以固定的頻率發(fā)送到Eureka server,這些信息在Eureka client啟動后的40s(通過eureka.client.initialInstanceInfoReplicationIntervalSeconds配置)首次發(fā)送开瞭,之后每隔30s(通過eureka.client.instanceInfoReplicationIntervalSeconds配置)發(fā)送一次懒震。

4.如果eureka.client.fetchRegistry設置成true(默認值true),Eureka client在啟動時會從Eureka server獲取注冊信息并緩存到本地嗤详,之后只會增量獲取信息(可以把eureka.client.shouldDisableDelta設置成false來強制每次都全量獲雀鋈拧)。獲取注冊信息的操作也是一個異步任務葱色,每隔30秒執(zhí)行一次(通過eureka.client.registryFetchIntervalSeconds配置)递宅,如果操作失敗,也是以2的指數(shù)形式延長重試時間苍狰,直到達到eureka.client.registryFetchIntervalSeconds * eureka.client.cacheRefreshExecutorExponentialBackOffBound 這個上限办龄,之后一直以這個上限值作為重試間隔,直至重新獲取到注冊信息淋昭,并且重新嘗試獲取注冊信息的次數(shù)是不受限制的俐填。
這些任務都是在com.netflix.discovery.DiscoveryClient中啟動,spring cloudorg.springframework.cloud.netflix.eureka.CloudEurekaClient對這個類進行了擴展翔忽。

[常見問題]

1.自我保護模式

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

默認情況下英融,如果Eureka Server在一定時間內(nèi)沒有接收到某個微服務實例的心跳,Eureka Server將會注銷該實例(默認90秒)歇式。但是當網(wǎng)絡分區(qū)故障發(fā)生時矢赁,微服務與Eureka Server之間無法正常通信,以上行為可能變得非常危險了——因為微服務本身其實是健康的贬丛,此時本不應該注銷這個微服務撩银。

Eureka通過“自我保護模式”來解決這個問題——當Eureka Server節(jié)點在短時間內(nèi)丟失過多客戶端時(可能發(fā)生了網(wǎng)絡分區(qū)故障),那么這個節(jié)點就會進入自我保護模式豺憔。一旦進入該模式额获,Eureka Server就會保護服務注冊表中的信息,不再刪除服務注冊表中的數(shù)據(jù)(也就是不會注銷任何微服務)恭应。當網(wǎng)絡故障恢復后抄邀,該Eureka Server節(jié)點會自動退出自我保護模式。

綜上昼榛,自我保護模式是一種應對網(wǎng)絡異常的安全保護措施境肾。它的架構哲學是寧可同時保留所有微服務(健康的微服務和不健康的微服務都會保留),也不盲目注銷任何健康的微服務。使用自我保護模式奥喻,可以讓Eureka集群更加的健壯偶宫、穩(wěn)定。

在Spring Cloud中环鲤,可以使用eureka.server.enable-self-preservation = false 禁用自我保護模式纯趋。

2.unavailable-replicas
在配置文件中如果不使用域名的方式,而指定localhost或者ip(127.0.0.1/外網(wǎng)ip)冷离,服務能夠正常啟動吵冒,但分片服務總顯示在unavailable-replicas中,因此在host中指定了相應的域名做服務區(qū)分

** 參考 **

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末西剥,一起剝皮案震驚了整個濱河市痹栖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瞭空,老刑警劉巖结耀,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異匙铡,居然都是意外死亡图甜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門鳖眼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來黑毅,“玉大人,你說我怎么就攤上這事钦讳】笫荩” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵愿卒,是天一觀的道長缚去。 經(jīng)常有香客問我,道長琼开,這世上最難降的妖魔是什么囱桨? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任晦溪,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘点骑。我一直安慰自己卫枝,他們只是感情好苦锨,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布廉嚼。 她就那樣靜靜地躺著,像睡著了一般辅柴。 火紅的嫁衣襯著肌膚如雪箩溃。 梳的紋絲不亂的頭發(fā)上瞭吃,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音涣旨,去河邊找鬼歪架。 笑死,一個胖子當著我的面吹牛开泽,可吹牛的內(nèi)容都是我干的牡拇。 我是一名探鬼主播魁瞪,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼穆律,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了导俘?” 一聲冷哼從身側響起峦耘,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旅薄,沒想到半個月后辅髓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡少梁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年洛口,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凯沪。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡第焰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妨马,到底是詐尸還是另有隱情挺举,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布烘跺,位于F島的核電站湘纵,受9級特大地震影響,放射性物質發(fā)生泄漏滤淳。R本人自食惡果不足惜梧喷,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脖咐。 院中可真熱鬧伤柄,春花似錦、人聲如沸文搂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽煤蹭。三九已至笔喉,卻和暖如春取视,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背常挚。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工作谭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奄毡。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓折欠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吼过。 傳聞我的和親對象是個殘疾皇子锐秦,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容