實現一個註冊中心咱們要怎麼搞?搞些什麼呢?緩存
主流的 IP 獲取有這幾種方法:安全
最簡單粗暴的方式,手動配置須要註冊的IP。固然這種方式基本沒法在生產環境使用,由於微服務基本都是支持水平擴容多機部署的,在配置中寫死 IP 地址的方式沒法支持一份代碼水平擴容,會給運維帶來極大的成本。服務器
經過遍歷網卡的方式去獲取,找到第一個不爲本地環回地址的 IP 地址。絕大多數狀況下,這個方式比較好用,dubbo 等框架採用的就是這種方法。網絡
在一些網絡規劃比較好的標準化機房中,咱們還能夠經過手動指定網卡名,即 interfaceName 的方式來指定使用哪一塊網卡所對應的 IP 地址進行註冊。session
當上述三種方式都不能有效解決問題的時候,有一個方法就是直接與服務註冊中心創建 socket 鏈接,而後經過socket.getLocalAddress() 這種方式來獲取本機的 IP。負載均衡
端口的獲取,沒有標準化的方案。框架
若是是 RPC 應用,啓動的時候都有一個配置來指定服務監聽的端口, 註冊的時候直接使用配置項的端口值。運維
傳統的 WEB 容器所提供的 HTTP 的應用,一樣也存在一個配置文件來配置容器的監聽端口,註冊時候直接使用配置項的端口值。socket
特別的,在 Java 應用的 Spring Boot 框架中,能夠經過 EmbeddedServletContainerInitializedEvent. getEmbeddedServletContainer().getPort()來獲取。(Spring Boot 版本爲 1.x)。微服務
簡單地將 IP 和 port 信息註冊上去,能夠知足基本的服務調用的需求,可是在業務發展到必定程度的時候,咱們還會有這些需求:
固然上述兩種方式還不夠優雅,由於不能確保不出現 kill -9 這種粗暴的中止方式,並且應用調用服務下線接口也是嘗試去調用,對於網絡不通等異常場景並無作異常處理。所以,調用客戶端仍應該作好負載均衡與 failover 的處理。 更優雅的方式,先將即將中止的應用所對應的權重調成 0,此時上游將再也不調用此應用。這時候的中止應用的操做對服務訂閱者徹底沒有影響,固然這種場景須要訂閱者實現按權重的負載均衡和運維部署工具深度結合。
健康檢查分爲客戶端心跳和服務端主動探測兩種方式。
客戶端每隔必定時間主動發送「心跳」的方式來向服務端代表本身的服務狀態正常,心跳能夠是 TCP 的形式,也能夠是 HTTP 的形式。 也能夠經過維持客戶端和服務端的一個 socket 長鏈接本身實現一個客戶端心跳的方式。 ZooKeeper 並無主動的發送心跳,而是依賴了組件自己提供的臨時節點的特性,經過 ZooKeeper 鏈接的 session 來維持臨時節點。 可是客戶端心跳中,長鏈接的維持和客戶端的主動心跳都只是代表鏈路上的正常,不必定是服務狀態正常。 服務端主動調用服務進行健康檢查是一個較爲準確的方式,返回結果成功代表服務狀態確實正常。
因此如何取捨,仍是須要根據實際狀況來決定,根據不一樣的場景,選擇不一樣的策略。
在應用的配置文件中指定服務註冊中心的地址,相似於 zookeeper 和 eureka。 指定一個地址服務器的地址,而後經過這個地址服務器來獲取服務註冊中心的地址,地址服務器返回的結果會隨着服務註冊中心的擴縮容及時更新。
很經典的 Push 和 Pull 問題。
Push 的經典實現有兩種,基於 socket 長鏈接的 notify,典型的實現如 zookeeper;另外一種爲 HTTP 鏈接所使用 Long Polling。 可是基於 socket 長鏈接的 notify 和基於 HTTP 協議的 Long Polling 都會存在notify消息丟失的問題。
因此經過 Pull 的方式定時輪詢也必不可少,時間間隔的選擇也很關鍵,頻率越高服務註冊中心所承受的壓力也越大。須要結合服務端的性能和業務的規模進行權衡。
還有一種方式,真實的 Push,客戶端開啓一個 UDP server,服務註冊中心經過 UDP 的方式進行數據推送,固然這個也受限於網絡的連通性。
一個好的產品,用戶使用體驗和運維體驗必須是優雅的,若是查看本機發布和訂閱的服務,只能經過查看日誌,甚至是 jmap 的方式來獲取,顯然體驗很是糟糕。 服務註冊中心應該提供了豐富的接口,支持根據應用名、IP、訂閱服務名、發佈服務名,來進行多層次的組合查詢。 同時,客戶端的內存裏,一樣也應該保留服務發佈與訂閱的各類信息,並提供方式供人方便地查詢。
好比在 Java 中的 Spring Boot 的應用,能夠結合 actuator endpoint,經過 HTTP 的方式來提供本機服務查詢功能,查詢此應用發佈的服務,以及訂閱的服務及各服務的對應節點。
當服務節點數愈來愈多時,服務註冊中心的性能會成爲瓶頸,這時候就須要經過水平擴容來提高服務註冊中心集羣的性能。
對於那些採用了類 Paxos 協議的強一致性的組件,如ZooKeeper,因爲每次寫操做須要過半的節點確認。水平擴容不能提高整個集羣的寫性能,只能提高整個集羣的讀性能。 而對於採用最終一致性的組件來講,水平擴容能夠同時提高整個集羣的寫性能和讀性能。
首先,本地內存緩存,當運行時與服務註冊中心的鏈接丟失或服務註冊中心徹底宕機,仍能正常地調用服務。
而後,本地緩存文件,當應用與服務註冊中心發生網絡分區或服務註冊中心徹底宕機後,應用進行了重啓操做,內存裏沒有數據,此時應用能夠經過讀取本地緩存文件的數據來獲取到最後一次訂閱到的內容。
最後,本地容災文件夾。正常的狀況下,容災文件夾內是沒有內容的。當服務端徹底宕機且長時間不能恢復,同時服務提供者又發生了很大的變動時,能夠經過在容災文件夾內添加文件的方式來開啓本地容災。此時客戶端會忽略原有的本地緩存文件,只從本地容災文件中讀取配置。
當有新節點加入集羣時,節點啓動後能自動添加到地址服務器中,並經過地址服務器找到其餘節點,自動從其餘節點同步數據,以達到數據的最終一致性。
當某個節點宕機時,此服務註冊中心節點的信息會自動地址服務器中摘除,客戶端能及時感知到此節點已下線。
服務端的無狀態性保證了服務的容災和高可用能夠作的很薄。
鏈路安全,對於使用 HTTP 鏈接的服務註冊中心,保護鏈路安全的最好方式是使用 HTTPS。而使用 TCP 鏈接的服務註冊中心來講,因爲應用層協議通常使用的是私有協議,不必定存在現成的 TLS 支持方案。
在業務安全方面,應該在每一次的發佈、訂閱、心跳,都帶上鑑權的信息就行驗籤和鑑權,確保業務信息的安全性。