微服務 是一種架構模式,跟具體的語言實現無關,微服務架構將業務邏輯分散到了各個服務當中,服務間經過網絡層進行通訊共同協做;這樣一個應用就能夠劃分爲多個服務單獨來維護髮布。構建一個可靠微服務系統是須要具體看場景去衡量的,網絡通訊必然會帶來過多的網絡延遲,設計的時候就要儘可能減小服務與服務間的通訊,採用什麼通訊協議等。和單應用架構不一樣,微服務架構是由一系列職責單一的細粒度服務構成的分佈式網狀結構,服務之間經過輕量機制進行通訊來實現。微服務背後一個重要的理念就是持續集成、快速交付,而在服務內部使用一個統一的技術框架,顯然比把分散的技術組合到一塊兒更有效率。html
Spring Cloud 是基於 Spring Boot 提供了一套微服務解決方案,是一系列框架的有序集合,包括服務註冊與發現,配置中心,全鏈路監控,服務網關,負載均衡,熔斷器等組件等,其中主要經過整合 Netflix (Netflix 是一家成功實踐微服務架構的互聯網公司,幾年前,Netflix 就把它的幾乎整個微服務框架棧開源貢獻給了社區)的相關產品來實現這方面的功能(Spring Cloud Netflix),包括用於服務註冊和發現的 Eureka,調用斷路器 Hystrix,調用端負載均衡 Ribbon,Rest 客戶端 Feign,智能服務路由 Zuul 等(Feign 和 RxJava 並非 Netiflix 的產品,只是被整合到 Spring Cloud Netflix 中了)。java
結構圖 git
組件架構圖 github
服務設施中用到了 Spring Cloud Config、Netflix Eureka、Netflix Hystrix、Netflix Zuul、Netflix Ribbon、Netflix Feign 等組件,這也正是Spring Cloud分佈式開發中最核心的組件(轉載)。 spring
帳戶服務經過遠程客戶端(Feign)調用統計服務及通知服務,經過Ribbon實現負載均衡,並在調用過程當中增長了斷路器(Hystrix)的功能;docker
因爲服務發現後才能調用,所以帳戶服務、統計服務、通知服務經過註冊中心(Eureka)實現互相發現;api
API Gateway(Zuul)提供對外統一的服務網關,首先從註冊中心(Eureka)處獲取相應服務,再根據服務調用各個服務的真實業務邏輯;緩存
服務調用過程經過聚合器(Turbine)統一全部斷路信息;服務器
整個業務過程當中全部服務的配置文件經過Spring Cloud Config來管理,即起什麼端口、配置什麼參數等;網絡
認證機制經過Auth service實現,提供基本認證服務;
Spring Cloud Config、Eureka、Ribbon、Hystrix、Feign以及Turbine均爲標準組件,與業務之間沒有強關係,不涉及到業務代碼,僅需簡單配置便可工做。
CAP 理論
Eureka 是 Netflix 開源的一款提供服務註冊和發現組件,Spring Cloud 將它集成在本身的子項目 Spring Cloud Netflix 中。原生的 Eureka 會包含 AWS 定製功能,這也正是 Spring Cloud 中最核心的組件。另外服務註冊與發現開源組件不少,好比 Consul(CA)和 Zookeeper (CP),但這並非一個最佳選擇。
在分佈式系統領域有個著名的CAP定理:C——數據一致性,A——服務可用性,P——服務對網絡分區故障的容錯性。這三個特性在任何分佈式系統中不能同時知足,最多同時知足兩個。
Zookeeper 是著名 Hadoop 的一個子項目,不少場景下Zookeeper也做爲Service發現服務解決方案。Zookeeper 保證的是 CP,即任什麼時候刻對Zookeeper的訪問請求能獲得一致的數據結果,同時系統對網絡分割具有容錯性,可是它不能保證每次服務請求的可用性。從實際狀況來分析,在使用 Zookeeper 獲取服務列表時,若是zookeeper正在選主,或者Zookeeper集羣中半數以上機器不可用,那麼將就沒法得到數據了。因此說,Zookeeper不能保證服務可用性。
誠然,對於大多數分佈式環境,尤爲是涉及到數據存儲的場景,數據一致性應該是首先被保證的,這也是zookeeper設計成CP的緣由。可是對於服務發現場景來講,狀況就不太同樣了:針對同一個服務,即便註冊中心的不一樣節點保存的服務提供者信息不盡相同,也並不會形成災難性的後果。由於對於服務消費者來講,能消費纔是最重要的——拿到可能不正確的服務實例信息後嘗試消費一下,也好過由於沒法獲取實例信息而不去消費。因此,對於服務發現而言,可用性比數據一致性更加劇要——AP 賽過 CP。而 Spring Cloud Netflix 在設計 Eureka 時遵照的就是AP原則。轉載
配置單機版 Eureka Server
Eureka 由 Eureka Server(服務的註冊中心,負責維護註冊的服務列表) 和 Eureka Client 組成,咱們將 Eureka Client 再分爲 Service Provider(服務提供方,做爲一個Eureka Client,向Eureka Server作服務註冊、續約和下線等操做,註冊的主要數據包括服務名、機器ip、端口號、域名等) 與 Service Consumer(服務消費方,做爲一個Eureka Client,向Eureka Server獲取Service Provider 的註冊信息,並經過遠程調用與 Service Provider 進行通訊),另外 Service Provider 和 Service Consumer 不是嚴格的概念,Service Consumer 也能夠隨時向 Eureka Server 註冊,來讓本身變成一個 Service Provider,Eureka Server 也能夠自注冊,可是通常單機版的服務這樣作沒有意義。
Maven 配置
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <!--<dependency>--> <!--<groupId>org.springframework.boot</groupId>--> <!--<artifactId>spring-boot-starter-security</artifactId>--> <!--</dependency>—>
YML 配置文件
spring: application: name: microsrv-eureka-server server: port: 8000 eureka: instance: hostname: localhost #prefer-ip-address: true #ip-address: 192.168.1.1 client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
程序的入口Application類加上@EnableEurekaServer 註解
@SpringBootApplication @EnableEurekaServer public class MicrosrvEurekaServerApplication { public static void main(String[] args) { SpringApplication.run(MicrosrvEurekaServerApplication.class, args); } }
配置高可用集羣 Eureka Server
咱們能夠建立三個註冊中心節點,每一個節點進行兩兩相互註冊,達到集羣的最高可用性,任何一個節點掛掉都不會影響服務的註冊與發現。若是某臺 Eureka Server 宕機,Eureka Client 的請求會自動切換到新的 Eureka Server 節點,當宕機的服務器從新恢復後,Eureka 會再次將其歸入到服務器集羣管理之中。當節點開始接受客戶端請求時,全部的操做都會進行 replicateToPeer(節點間複製)操做,將請求複製到其餘Eureka Server當前所知的全部節點中。一個新的 Eureka Server 節點啓動後,會首先嚐試從鄰近節點獲取全部實例註冊表信息,完成初始化。Eureka Server 經過getEurekaServiceUrls()方法獲取全部的節點,而且會經過心跳續約的方式按期更新。默認配置下,若是 Eureka Server 在必定時間內沒有接收到某個服務實例的心跳,Eureka Server 將會註銷該實例(默認爲90秒,經過 eureka.instance.lease-expiration-duration-in-seconds 配置)。當 Eureka Server 節點在短期內丟失過多的心跳時(好比發生了網絡分區故障),那麼這個節點就會進入自我保護模式。
修改 host文件
vi /etc/hosts 增長以下信息
10.255.131.162 microsrv-eureka-server-peer1 10.255.131.163 microsrv-eureka-server-peer2 10.255.131.164 microsrv-eureka-server-peer3
YUM 文件配置(---分割每一個節點的內容,等同於建立了三個文件的效果)
### HOST 方式 spring: application: name: microsrv-eureka-server profiles: active: peer1 #logging: # level: # com.netflix.eureka: 'off' # com.netflix.discovery: 'off' --- spring: profiles: peer1 server: port: 8000 eureka: instance: hostname: microsrv-eureka-server-peer1 client: registerWithEureka: true fetchRegistry: true service-url: defaultZone: http://microsrv-eureka-server-peer2:${server.port}/eureka/,http://microsrv-eureka-server-peer3:${server.port}/eureka/ --- spring: profiles: peer2 server: port: 8000 eureka: instance: hostname: microsrv-eureka-server-peer2 client: registerWithEureka: true fetchRegistry: true service-url: defaultZone: http://microsrv-eureka-server-peer1:${server.port}/eureka/,http://microsrv-eureka-server-peer3:${server.port}/eureka/ --- spring: profiles: peer3 server: port: 8000 eureka: instance: hostname: microsrv-eureka-server-peer3 client: registerWithEureka: true fetchRegistry: true service-url: defaultZone: http://microsrv-eureka-server-peer1:${server.port}/eureka/,http://microsrv-eureka-server-peer2:${server.port}/eureka/
最後依次啓動服務
java -jar microsrv-eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer1 java -jar microsrv-eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer2 java -jar microsrv-eureka-server-0.0.1-SNAPSHOT.jar --spring.profiles.active=peer3
有時候咱們以爲使用 Host 的方式顯示並非太友好,也能夠修改爲 IP 的方式實現(配置 eureka.instance.prefer-ip-address=true 屬性),配置以下:
## IP 的方式 spring: application: name: microsrv-eureka-server profiles: active: peer1 #logging: # level: # com.netflix.eureka: 'off' # com.netflix.discovery: 'off' --- spring: profiles: peer1 server: port: 8000 eureka: instance: prefer-ip-address: true ip-address: 10.255.131.162 client: registerWithEureka: true fetchRegistry: true service-url: defaultZone: http://10.255.131.163:${server.port}/eureka/,http://10.255.131.164:${server.port}/eureka/ --- spring: profiles: peer2 server: port: 8000 eureka: instance: prefer-ip-address: true ip-address: 10.255.131.163 client: registerWithEureka: true fetchRegistry: true service-url: defaultZone: http://10.255.131.162:${server.port}/eureka/,http://10.255.131.164:${server.port}/eureka/ --- spring: profiles: peer3 server: port: 8000 eureka: instance: prefer-ip-address: true ip-address: 10.255.131.164 client: registerWithEureka: true fetchRegistry: true service-url: defaultZone: http://10.255.131.162:${server.port}/eureka/,http://10.255.131.163:${server.port}/eureka/
建立 Service Provider 服務提供者
Service Provider 本質是一個 Eureka Client。啓動時,會調用服務註冊方法向 Eureka Server 註冊本身的信息。Eureka Server 會維護一個已註冊服務的列表。
建立 Service Consumer 消費者
Service Consumer 本質也是一個 Eureka Client(它也會向 Eureka Server 註冊,只是這個註冊信息可有可無)。它啓動後,會從 Eureka Server 上獲取全部實例的註冊信息,包括IP地址、端口等,並緩存到本地。這些信息默認每30秒更新一次。前文提到過,若是與 Eureka Server 通訊中斷,Service Consumer 仍然能夠經過本地緩存與 Service Provider 通訊。
Liunx 服務器運行報 java.net.UnknownHostException:Name or service not known
2018-06-28 17:27:06.970 INFO 1292 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using XML decoding codec XStreamXml 2018-06-28 17:27:07.027 WARN 1292 --- [ main] c.n.e.transport.JerseyReplicationClient : Cannot find localhost ip java.net.UnknownHostException: iZuf6i3b97wsrn5x2oic17Z: iZuf6i3b97wsrn5x2oic17Z: Name or service not known at java.net.InetAddress.getLocalHost(InetAddress.java:1505) ~[na:1.8.0_151] at com.netflix.eureka.transport.JerseyReplicationClient.createReplicationClient(JerseyReplicationClient.java:170) ~[eureka-core-1.9.2.jar!/:1.9.2]
解決辦法,配置主機名
echo `hostname` vi /etc/hosts 127.0.0.1 hostname localhost
自我保護模式
當註冊服務由於網絡或其餘緣由出現故障而關停時,Eureka不會剔除服務註冊,而是等待其修復,能夠經過以下配置剔除不健康節點,這是AP的一種實現。server: eureka.server.enable-self-preservation//(設爲false,關閉自我保護) eureka.server.eviction-interval-timer-in-ms //清理間隔(單位毫秒,默認是60*1000) client: eureka.client.healthcheck.enabled = true //開啓健康檢查(須要spring-boot-starter-actuator依賴) eureka.instance.lease-renewal-interval-in-seconds =30 //租期更新時間間隔(默認30秒) eureka.instance.lease-expiration-duration-in-seconds =90 //租期到期時間(默認90秒)
若是 Eureka Server 每分鐘收到心跳續約的數量低於一個閾值(instance的數量*(60/每一個instance的心跳間隔秒數)*自我保護係數),而且持續15分鐘,就會觸發自我保護。在自我保護模式中,Eureka Server會保護服務註冊表中的信息,再也不註銷任何服務實例。當它收到的心跳數從新恢復到閾值以上時,該Eureka Server節點就會自動退出自我保護模式。它的設計哲學前面提到過,那就是寧肯保留錯誤的服務註冊信息,也不盲目註銷任何可能健康的服務實例。該模式能夠經過 eureka.server.enable-self-preservation = false 來禁用,同時 eureka.instance.lease-renewal-interval-in-seconds能夠用來更改心跳間隔,eureka.server.renewal-percent-threshold 能夠用來修改自我保護係數(默認0.85)。server: eureka: server: enableSelfPreservation: false evictionIntervalTimerInMs: 3000 client: eureka: instance: leaseRenewalIntervalInSeconds:30 leaseExpirationDurationInSeconds: 90
Region 與 Zone 均是 AWS 的概念。在非 AWS 環境下,咱們能夠先簡單地將 region 理解爲 Eureka集 羣,zone 理解成機房。
REFER:https://github.com/Microsoft/api-guidelineshttp://projects.spring.io/spring-cloud/微服務架構初探http://www.iteye.com/news/32932