1. 程式人生 > >線上SpringCloud閘道器呼叫微服務跨機房了,咋整?

線上SpringCloud閘道器呼叫微服務跨機房了,咋整?

1、前言

公司內考慮到伺服器資源成本的問題,目前業務上還在進行服務的容器化改造和遷移,計劃將容器化後的服務,以及一些中介軟體(MQ、DB、ES、Redis等)儘量都遷移到其他機房。

那你們為什麼不用阿里雲啊,騰訊雲啊,還用自己的機房?

的確是這樣,公司內部目前還是有專門的運維團隊。也是因為歷史原因,當時業務發展比較迅猛,考慮到資料的安全性也是自建機房的。對於中小型公司這樣做,顯然成本太高了,所以一般都用阿里雲。對於中大型企業或者對資料安全性要求高的公司,自建機房維護的也不再少數。

對於中介軟體來說,比如 Redis 快取,有的業務也是因為歷史原因,當時上線後都是單獨申請,並部署的一套叢集,但是量並不是很大,所以類似這種情況的,可以考慮跟其他專案使用的叢集合併為一個,這樣就可能節省了一部分伺服器資源。

現在大多數企業都已經微服務化,容器化了。

所以,將非容器化的業務要求都遷移到容器中,這裡的容器基本都是指 Kubernetes 平臺了,通過容器釋出排程服務,對於運維來說,維護變得更加便捷,高效。

對於研發來說,業務需要部署服務,不再需要重新提 JIRA 工單,走一系列稽核流程,最後給到你的可能還是一臺虛擬機器,依賴的軟體單獨安裝部署。用了容器,只要在 集裝箱 中提前安裝好所需軟體環境,按照發布規範打好映象,釋出服務的過程一路就是 點點點...

2、線上業務場景介紹

繼續來說今天的主題。

有一個專案是 SpringCloud 架構的,其中使用到了 閘道器 Zuul,並且也使用了到了 Eureka

作為註冊中心。

因為該專案提前已經遷移到北京機房節點部署的容器環境,我們最終目標是遷移到其他機房(如:天津機房)。

北京有兩個機房:A機房、B機房,因為都在北京,所以兩個機房之間的 網路延時 是可以接受的。

微服務也同樣在這兩個機房之間都有部署。

此時,如果只是將微服務部署到 天津機房,會變成如下圖所示的關係:

問題很明顯,就是閘道器服務只有北京的,而微服務新增了天津機房的,此時會導致 跨機房呼叫,即北京閘道器呼叫到了天津微服務。

儘管北京到天津 ping 的網路延時僅有 3 毫秒 之差,但是服務與服務之間的呼叫,可就不止這 3 毫秒了。

其中包括伺服器與伺服器之間 TCP連線的建立、資料傳輸的網路開銷,如果資料包過大,跨機房訪問耗時就會很明顯了。

所以呢,儘量避免跨機房訪問,當然要將閘道器也要遷移到天津機房。

但是,大家看 粉紅色粗體 的線條,仍然存在跨機房呼叫,天津閘道器呼叫到北京微服務。

對於線上併發訪問量稍微大點,或者有些介面響應體大的,又或者網路抖動等場景下,可能就會導致介面響應時間變長了。

如何解決呢?

因大部分業務都部署到天津,可以將天津機房的服務權重調高

SLB配置 (類Nginx):

upstream {
    server 北京機房閘道器IP  20;
    server 天津機房閘道器IP  80;
}

閘道器與微服務之間,都是通過 Eureka 註冊中心媒介來溝通,即 註冊服務 拉取服務

僅僅在閘道器層配置好權重還不夠,此時還會存在天津閘道器路由到北京微服務上。

Eureka 內部是基於 Ribbon 實現負載均衡的,自行實現按權重的負載均衡策略,Eureka做一點改造,介面上支援權重的修改。

下圖截圖了部分示例:

IP後面的就是權重值,可以在介面上輸入權重值進行調整。

我們可以將北京微服務權重調低,天津微服務權重調高。

相當於閘道器以及微服務兩側都是通過基於 權重 的負載均衡演算法來儘量減少跨機房呼叫的,但是無法避免跨機房呼叫。

使用 Eureka 的分割槽改進

上面描述的方案對於 20% 的流量仍然存在跨機房訪問,我們能不能做到先訪問同一機房的服務,如果同一機房的服務都不可用了,再訪問其他機房的呢?

答案是 可以的

我們可以藉助於 Eureka 註冊中心裡提供了 regionzone 的概念來實現。

regionzone 兩個概念均來自亞馬遜的 AWS:

region:簡單理解為地理上的分割槽,比如亞洲地區,或者華北地區等等,沒有具體大小的限制。根據專案情況,自行合理劃分 region。

zone:簡單理解為 region 內的具體機房,比如說 zone 劃分為北京、天津,且北京有兩個機房,就可以在 region 內劃分為三個zone,北京劃分為zone1、zone2,天津為zone3。

結合上面的示例,假設僅設定一個 region 為京津地區。

然後我們給這個區域下的閘道器服務、微服務打上 zone 機房標籤,在系統運維上將機房也稱作 IDC 資料中心。

閘道器服務打上zone標籤:

微服務打上zone標籤:

這個功能都是在 Eureka註冊中心 上實現的,在給服務配置 zone 前,呼叫路徑如下所示:

給服務配置 zone 之後,框架內部的路由機制的實現下,呼叫路徑如下所示:

當前使用的 Eureka 是部署在北京,如果想讓服務在註冊續約拉取 動作時也能實現 就近機房訪問,部署架構就變成如下這個樣子:

北京區域不同機房假設認為網路延時小,所以北京兩個機房可以使用同一個 Eureka 叢集;天津可以單獨再部署一套 Eureka 叢集,這樣就可以實現優先路由到同機房訪問。

服務註冊的關鍵配置

基本原理就是這樣,貼上一段 Eureka 使用 regionzone 的配置供大家參考:

spring:
  application:
    name: mananger
 
server:
  port: ${EUREKA_SERVER_PORT:8011}
 
eureka:
  instance: 
    # 全網服務例項唯一標識
    instance-id: ${EUREKA_SERVER_IP:127.0.0.1}:${server.port}
    # 服務例項的meta資料鍵值對集合,可由註冊中心進行服務例項間傳遞
    metadata-map:
      # [HA-P配置]-當前服務例項的zone
      zone: ${EUREKA_SERVER_ZONE:tz-1}
      profiles: ${spring.profiles.active}
    # 開啟ip,預設為false=》hostname
    prefer-ip-address: true
    ip-address: ${EUREKA_SERVER_IP:127.0.0.1}
    # [HA-P配置]-當前服務例項的region
client:
    region: ${EUREKA_SERVER_REGION:cn-bj}
    # [HA-P配置]-開啟當前服務例項優先發現同zone的註冊中心,預設為true
    prefer-same-zone-eureka: true
    # [服務註冊]-允許當前服務例項註冊,預設為true
    register-with-eureka: true
    # [服務續約]-允許當前服務例項獲取註冊資訊,預設為true
    fetch-registry: true
    # [HA-P配置]-可用region下zone集合
        availability-zones:
      cn-bj: ${eureka.instance.metadata-map.zone},zone-bj,zone-tj
   service-url:  
      # [HA-P配置]-各zone下注冊中心地址列表
       zone-bj: http://BJIP1:8011/eureka,http://BJIP2:8012/eureka
       zone-tj: http://TJIP1:8013/eureka,http://TJIP2:8014/eureka

prefer-same-zone-eureka :

預設就為true,首先會通過 region 找到 availability-zones 內的第一個 zone,然後通過這個 zone 找到 service-url 對應該機房的註冊中心地址列表,並向該列表內的 第一個URL 地址發起註冊和心跳,不會再向其它的URL地址發起操作。只有當第一個URL地址註冊失敗的情況下,才會依次向其它的URL發起操作,重試一定次數仍然失敗,會間隔一段心跳時間繼續重試。

eureka.instance.metadata-map.zone:

服務提供者和消費者都要配置該引數,表示自己屬於哪一個機房的。閘道器服務也屬於消費者,從註冊中心拉取到登錄檔之後會根據這個引數中指定的 zone 進行過濾,過濾後向同 zone 內的服務會有多個例項 ,通過 Ribbon 來實現負載均衡呼叫。如果同一 zone 內的所有服務都不可用時,會其他 zone 的服務發起呼叫。

另外注意一點 availability-zones 下 region 的配置是 ${eureka.instance.metadata-map.zone},... 這樣配置的好處是,你只要指定好了 eureka.instance.metadata-map.zone,優先會將這個引數放到可用分割槽下作為第一個 zone 來訪問。

Zuul 閘道器路由分割槽原始碼分析

閘道器使用的 zuul,其內部也是通過 ribboneureka 的結合來實現服務之間的呼叫,因為閘道器實際也是個服務消費者,同樣會註冊到 eureka 上,被閘道器拉取過來的登錄檔裡的服務,作為服務提供者,同樣會註冊到eureka上。

通過一張圖把控整個請求的大致脈絡:

上述圖示中部分核心原始碼如下所示:

PollServerListUpdater#start(final UpdateAction action) 啟動後會每隔30秒(預設)去Eureka註冊中心拉取一次登錄檔資訊,更新本地快取的資料結構。

呼叫到了DyamicServerListLoadBalancer匿名實現類中。

通過DyamicServerListLoadBalancer類呼叫了 updateListOfServer() 方法更新服務列表,serverListImpl的實現是DiscoveryEnabledNIWSServerList類

在DiscoveryEnabledNIWSServerList類內部會呼叫 obtainServersViaDiscovery() 方法,其內部通過 EurekaClient 來實現從 Eureka 註冊中心拉取服務列表。

過濾器內部獲取同一機房(zone)的服務列表,先後會呼叫 ZonePreferenceServerListFilterZoneAffinityServerListFilter 兩個過濾器實現 zone 的過濾。

最開始獲取的Servers一共是有4條記錄,根據除錯的程式碼看,我們是為了獲取 zone 為2的服務,所以得到的結果是一條,即 zone = "2",說明找到了同 zone 服務。

請求介面後會呼叫到 LoadBalancerContext#getServerFromLoadBalancer(...),內部會呼叫到ILoadBalancer 具體實現的 chooseServer() 方法,最終會獲取到 zone="2" 裡的一個Server。

那麼這裡是如何選擇的Server呢?

本地除錯時,只配置了已給可用的zone,所以這裡條件滿足會直接呼叫 super.chooseServer(key) 父類的方法:

BaseLoadBalancer#chooseServer(...) 父類的選擇Server的方法,其內部通過 IRule#choose(key) 會呼叫到具體的負載均衡器的實現:

上述截圖中,能看到 MetadataWeightedRule ,這個類是我們自行基於權重負載均衡實現。

該實現類是繼承了 ZoneAviodanceRule ,目的就是利用了 zone 的概念,所重寫的 choose(Object key) 方法,呼叫了 this.getPredicate().getEligibleServers(...) 會走同樣的過濾規則獲取到同一機房(zone)下的所有服務列表,然後在基於每個服務配置的權重篩選一個Server。

獲取到 Server 後,拼接介面的URI請求地址 http://IP:PORT/api/.../xxx.json ,通過底層的 OkHttp 實現完成 Http 介面的呼叫過程。

好了,到此基本就分析完了,從閘道器請求,通過 ribbon 元件從 eureka 註冊中心拉取服務列表,如何基於 zone 分割槽來實現多資料中心的訪問。

對於 服務註冊,要保證服務能註冊到同一個 zone 內的註冊中心,如果跨 zone 註冊,會導致網路延時較大,出現拉取登錄檔,心跳超時等問題。

對於 服務呼叫,要保證優先呼叫同一個 zone 內的服務,當無法找到同 zone 或者 同 zone 內的服務不可用時,才會轉向呼叫其他 zone 裡的服務。

本文提到的只是閘道器到微服務之間的呼叫,實際專案中,微服務還會呼叫其他第三方的服務,也要同時考慮到跨機房呼叫的問題,儘量都讓各服務之間在同機房呼叫,減少網路延時,提高服務的穩定性。

歡迎關注我的公眾號,掃二維碼關注獲得更多精彩原創文章,與你一同成長~

相關推薦

線上SpringCloud呼叫服務機房

1、前言 公司內考慮到伺服器資源成本的問題,目前業務上還在進行服務的容器化改造和遷移,計劃將容器化後的服務,以及一些中介軟體(MQ、DB、ES、Redis等)儘量都遷移到其他機房。 那你們為什麼不用阿里雲啊,騰訊雲啊,還用自己的機房? 的確是這樣,公司內部目前還是有專門的運維團隊。也是因為歷史原因,當時業務

使用 API 構建服務 & 服務架構中的程序間通訊

本期內容 微服務系列文章的第一篇介紹了微服務架構模式,討論了使用微服務的優缺點,以及為什麼微服務雖然複雜度高卻是複雜應用程式的理想選擇。 在決定以一組微服務來構建自己的應用時,你需要確定應用客戶端如何與微服務互動。 在單體式程式中,通常只有一組冗餘的或者負載均衡的服

使用 API 構建服務-2

「Chris Richardson 微服務系列」使用 API 閘道器構建微服務 Posted on 2016年5月12日 編者的話|本文來自 Nginx 官方部落格,是微服務系列文章的第二篇,本文將探討:微服務架構是如何影響客戶端到服務端的通訊,並提出一種使用 API 閘道器的方法。 &nbs

服務架構中整合、許可權服務

前言:之前的文章有講過微服務的許可權系列和閘道器實現,都是孤立存在,本文將整合後端服務與閘道器、許可權系統。安全許可權部分的實現還講解了基於前置驗證的方式實現,但是由於與業務聯絡比較緊密,沒有具體的示例。業務許可權與業務聯絡非常密切,本次的整合專案將會把這部分的操作許可權校驗

獨立使用zuul分發不同服務的請求、許可權控制SpringCloud

閘道器api Gateway的重要性不言而喻,閘道器負責統一接收所有請求,然後根據不同的規則進行轉發到不同的服務。使用閘道器能夠統一的管理請求日誌、進行許可權控制、過濾等,這樣就能避免在每個單體應用中做重複的工作。這一篇主要是講zuul的獨立使用,就是隻作為一個獨立的專案進行

SpringCloud搭建

Zuul的主要功能是路由轉發和過濾器。路由功能是微服務的一部分,比如/api/info轉發到到info服務,/api/login轉發到到login服務。zuul預設和Ribbon結合實現了負載均衡的功能, 類似於nginx轉發。   pom <parent> <groupI

3--SpringCloudzuul

閘道器   通過服務閘道器統一向外系統提供REST API的過程中,除了具備服務路由、均衡負載功能之外,它還具備了許可權控制等功能。Spring Cloud Netflix中的Zuul就擔任了這樣的一個角色,為微服務架構提供了前門保護的作用,同時將許可權控制這些較重的非業務邏輯內容遷移到服務路由層面,使得服

阿里雲API呼叫示例

文件 阿里雲API閘道器文件 錯誤程式碼表 如何獲取錯誤資訊 maven <dependency> <groupId>com.aliyun.api.gateway</groupId> <artifactId&g

springcloud攔截+redis+自定義token做登入驗證操作

網上看到的token做起來都太複雜,介紹說耗費的記憶體較大,寫的封裝方法非常多,看來看去非常不方便,自己就藉助token思想,和閘道器攔截器組合操作的登入驗證機制。 1.下面這段程式碼就是使用者請求,驗證資料庫是否有這個使用者名稱和密碼,使用者登入成功與否,成功登入就生成token儲存到re

osgi2——camel呼叫其它系統webservice

上一節介紹了怎麼用camel和cxf去起一個webservice,這節介紹怎麼用camel去呼叫其它系統的webservice。 請看blueprint.xml的配置 <?xml versio

高效能裝置及服務實踐(dpdk)--伺服器架構研究

針對海量的網路流量,轉發效能是我們最關鍵的一個方面,那構建高效能的後臺伺服器有哪些關鍵的技術和需要注意的地方,今天邀請了後臺開發同學童琳和鄭勝利來和大家一起談談。 一、引言 隨著網際網路的高速發展,內容量的提升以及對內容智慧的需求、雲產業的快速

高效能裝置及服務實踐

一、引言 隨著網際網路的高速發展,內容量的提升以及對內容智慧的需求、雲產業的快速突起,作為網際網路的計算基石伺服器的形態以及使用成為了炙手可熱的話題,全球各家大型網際網路公司都持續的在伺服器平臺上有非常大的動作,譬如facebook的OCP等,而整個伺服器的生態

CentOS系統主機名與IP地址、、DNS服務的配置

         Centos系統的主機名與Windows系統的主機名類似,在安裝完之後,沒有手動設定的話,都會配置一個預設的主機名,在Centos系統下可以採用命令“hostname”或者“uname -n”來查詢該Centos系統的主機名。同樣IP、閘道器、DNS的配置

SpringCloud 配置:spring-cloud-gateway

微服務閘道器微服務閘道器的功能:    路由轉發,接收一切外界請求,轉發到後端的微服務上去;    請求過濾,在服務閘道器中可以完成一系列的橫切功能,例如許可權校驗、限流以及監控等,這些都可以通過過濾器完成(其實路由轉發也是通過過濾器實現的)微服務閘道器種類    Zuul,

springcloud2+gateway配置中心2(包含熔斷jwt認證限流)

下面介紹1未講完的閘道器功能    1重試功能,配置如下         這裡可以不寫實現類,採用預設的方式配置,然後傳送一個http的GET請求,試著斷開服務端檢視後臺:  證明配置正確,起作用了!

springcloud2+gateway配置中心1(包含熔斷jwt認證限流)

第一次我也問我老大為啥不用zuul,官網有現成的指導,老大一句話:gateway效能比zuul優化效率提升20%,zuul版本落後(2x版本的code還是用的1x的原始碼),支援webflux,整合stream流;淚奔的我忙了半天zuul,哎,換! 1,引入maven,2.0以上版本注意

物聯網關鍵技術包括兩個方面物聯網是智慧家居發展的重要支撐

在無線感測網中,是不可或缺的核心裝置。此外還需要具備裝置管理功能,運營商通過裝置可以管理底層的各感知節點,瞭解各節點的相關資訊,並實現遠端控制。 物聯網閘道器關鍵技術包括兩個方面。 1.多標準互通接入能力:目前用於近程通訊的技術標準很多。常見的感測網技術包括ZigBe

別再讓你的服務裸奔基於 Spring Session & Spring Security 服務許可權控制

微服務架構 閘道器:路由使用者請求到指定服務,轉發前端 Cookie 中包含的 Session 資訊; 使用者服務:使用者登入認證(Authentication),使用者授權(Authority),使用者管理(Redis Session Management) 其他服務:依賴 Redis 中使用者資

服務springcloud服務、Zuul簡介和Zuul服務

使用zuul構建微服務閘道器 為什麼要使用微服務閘道器 雖然微服務架構已經初具雛形,但還有一些問題————不同的微服務 一般會有不同的網路地址,而外部客戶端(例如手機APP)可能還需 呼叫多個微服務接口才能完成一個業務需求。例如一個電影購票的 手機APP,可能會呼叫多個微服務介面,才