分布式和微服务区别_深度解析spring cloud分布式微服务的实现
分布式系統(tǒng)
微服務(wù)就是原來臃腫的項(xiàng)目拆分為多個模塊互不關(guān)聯(lián)。如:按照子服務(wù)拆分、數(shù)據(jù)庫、接口,依次往下就更加細(xì)粒度,當(dāng)然運(yùn)維也就越來越難受了。
分布式則是偏向與機(jī)器將諾大的系統(tǒng)劃分為多個模塊部署在不同服務(wù)器上。
微服務(wù)和分布式就是作用的“目標(biāo)不一樣”。
微服務(wù)與Cloud
微服務(wù)是一種概念,spring-cloud是微服務(wù)的實(shí)現(xiàn)。
微服務(wù)也不一定必須使用cloud來實(shí)現(xiàn),只是微服務(wù)中有許多問題,如:負(fù)載均衡、服務(wù)注冊與發(fā)現(xiàn)、路由等等。
而cloud則是將這些處理問題的技術(shù)整合了。
Spring-Cloud 組件
Eureka
Eureka是Netifix的子模塊之一,Eureka有2個組件,一個EurekaServer 實(shí)現(xiàn)中間層服務(wù)器的負(fù)載均衡和故障轉(zhuǎn)移,一個EurekaClient它使得與server交互變得簡單。
Spring-Cloud封裝了Netifix公司開發(fā)的Eureka模塊來實(shí)現(xiàn)服務(wù)注冊和發(fā)現(xiàn)。
通過Eureka的客戶端 Eureka Server維持心跳連接,維護(hù)可以更方便監(jiān)控各個微服務(wù)的運(yùn)行。
角色關(guān)系圖
Eureka使用
客戶端
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> server: port: 4001 eureka: client: serviceUrl: defaultZone: http://localhost:3000/eureka/ #eureka服務(wù)端提供的注冊地址 參考服務(wù)端配置的這個路徑 instance: instance-id: admin-1 #此實(shí)例注冊到eureka服務(wù)端的唯一的實(shí)例ID prefer-ip-address: true #是否顯示IP地址 leaseRenewalIntervalInSeconds: 10 #eureka客戶需要多長時間發(fā)送心跳給eureka服務(wù)器,表明它仍然活著,默認(rèn)為30 秒 (與下面配置的單位都是秒) leaseExpirationDurationInSeconds: 30 #Eureka服務(wù)器在接收到實(shí)例的最后一次發(fā)出的心跳后,需要等待多久才可以將此實(shí)例刪除,默認(rèn)為90秒spring: application: name: server-admin #此實(shí)例注冊到eureka服務(wù)端的name服務(wù)端
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter- netflix-eureka-server</artifactId> </dependency> yml文件聲明 server: port: 3000 eureka: server: enable-self-preservation: false #關(guān)閉自我保護(hù)機(jī)制 eviction-interval-timer-in-ms: 4000 #設(shè)置清理間隔 (單位:毫秒 默認(rèn)是60*1000) instance: hostname: localhost client: registerWithEureka: false #不把自己作為一個客戶端注冊到自己身上 fetchRegistry: false #不需要從服務(wù)端獲取注冊信息 (因?yàn)樵谶@里自己就是服務(wù)端,而且已經(jīng)禁用自己注冊了) serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka 在SpringBoot 啟動項(xiàng)目中加入注解:@EnableEurekaServer 就可以啟動項(xiàng)目了,訪問對應(yīng)地址就可以看到界面。Eureka 集群
服務(wù)啟動后Eureka Server會向其他服務(wù)server 同步,當(dāng)消費(fèi)者要調(diào)用服務(wù)提供者,則向服務(wù)注冊中心獲取服務(wù)提供者的地址,然后將提供者的地址緩存到本地,下次調(diào)用時候直接從本地緩存中獲取
yml 服務(wù)端
server: port: 3000 eureka: server: enable-self-preservation: false #關(guān)閉自我保護(hù)機(jī)制 eviction-interval-timer-in-ms: 4000 #設(shè)置清理間隔 (單位:毫秒 默認(rèn)是60*1000) instance: hostname: eureka3000.com client: registerWithEureka: false #不把自己作為一個客戶端 注冊到自己身上 fetchRegistry: false #不需要從服務(wù)端獲取注冊信息 (因?yàn)樵谶@里自己就是服務(wù)端,而且已經(jīng)禁用自己注冊了) serviceUrl: defaultZone: http://eureka3001.com:3001/eureka, http://eureka3002.com:3002/eureka (這里不注冊自己,注冊到其他服務(wù)上面以為會同步。)yml 客戶端
server: port: 4001 eureka: client: serviceUrl: defaultZone:http://localhost:3000/eureka/,http:// eureka3001.com:3001/eureka,http://eureka3002.com:3 002 /eureka #eureka服務(wù)端提供的注冊地址 參考服務(wù)端配置的這個路徑 instance: instance-id: admin-1 #此實(shí)例注冊到eureka服務(wù)端的唯一的實(shí)例ID prefer-ip-address: true #是否顯示IP地址 leaseRenewalIntervalInSeconds: 10 #eureka客戶需要多長時間發(fā) 送心跳給eureka服務(wù)器,表明它仍然活著,默認(rèn)為30 秒 (與下面配置的單位都是秒) leaseExpirationDurationInSeconds: 30 #Eureka服務(wù)器在 接收到實(shí)例的最后一次發(fā)出的心跳后,需要等待多久才可以將此實(shí)例刪除,默認(rèn)為90秒spring: application: name: server-admin #此實(shí)例注冊到eureka服務(wù)端的nameCAP定理
C:Consistency 一致性 A:Availability 可用性 P:Partition tolerance 分區(qū)容錯性 這三個指標(biāo)不能同時達(dá)到Partition tolerance
分區(qū)容錯性,大多數(shù)分布式系統(tǒng)都部署在多個子網(wǎng)絡(luò)。每一個網(wǎng)絡(luò)是一個區(qū)。區(qū)間的通信是可能失敗的如一個在本地,一個在外地,他們之間是無法通信的。分布式系統(tǒng)在設(shè)計的時候必須要考慮這種情況。
Consistency
一致性,寫操作后的讀取,必須返回該值。如:服務(wù)器A1和服務(wù)器A2,現(xiàn)在發(fā)起操作將A1中V0改為V1,用戶去讀取的時候讀到服務(wù)器A1得到V1,如果讀到A2服務(wù)器但是服務(wù)器
還是V0,讀到的數(shù)據(jù)就不對,這就不滿足一致性。
所以讓A2返回的數(shù)據(jù)也對,的讓A1給A2發(fā)送一條消息,把A2的V0變?yōu)閂1,這時候不管從哪里讀取都是修改后的數(shù)據(jù)。
Availability
可用性就是用戶只要給出請求就必須回應(yīng),不管是本地服務(wù)器還是外地服務(wù)器只要接收到就必須做出回應(yīng),不管數(shù)據(jù)是否是最新必須做出回應(yīng),負(fù)責(zé)就不是可用性。
C與A矛盾
一致性和可用性不能同時成立,存在分區(qū)容錯性,通信可能失敗。
如果保證一致性,A1在寫操作時,A2的讀寫只能被鎖定,只有等數(shù)據(jù)同步了才能讀寫,在鎖定期間是不能讀寫的就不符合可用性。
如果保持可用性,那么A2就不會被鎖定,所以一致性就不能成立。
綜上 無法做到一致性和可用性,所以系統(tǒng)在設(shè)計的時候就只能選其一。
Eureka與Zookeeper
Zookeeper遵循的是CP原則保持了一致性,所以在master節(jié)點(diǎn)因?yàn)榫W(wǎng)絡(luò)故障與剩余“跟隨者”接點(diǎn)失去聯(lián)系時會重新選舉“領(lǐng)導(dǎo)者”,選取“領(lǐng)導(dǎo)者”大概會持續(xù)30-120s的時間,且選舉的時候整個zookeeper是不可用的。導(dǎo)致在選舉的時候注冊服務(wù)癱瘓。
Eureka在設(shè)計的時候遵循AP可用性。Eureka各個接點(diǎn)是公平的,沒有主從之分,down掉幾個幾點(diǎn)也沒問題,其他接點(diǎn)依然可以支持注冊,只要有一臺Eureka在,注冊就可以用,只不過查詢到的數(shù)據(jù)可能不是最新的。Eureka有自我保護(hù)機(jī)制,如果15分鐘之內(nèi)超過85%接點(diǎn)都沒有正常心跳,那么Eureka認(rèn)為客戶端與注冊中心出現(xiàn)故障,此時情況可能是
Eureka不在從注冊列表移除因?yàn)殚L時間沒有瘦到心跳而過期的服務(wù)。
Eureka仍然能夠接收注冊和查詢,但不會同步到其他接點(diǎn)。
當(dāng)網(wǎng)絡(luò)穩(wěn)定后,當(dāng)前的 實(shí)例注冊信息會更新到其他接點(diǎn)。
Ribbon
rebbon主要提供客戶端的負(fù)載均衡,提供了一套完善的客戶端的配置。Rebbin會自動幫助你基于某種規(guī)則(如:簡單的輪詢,隨機(jī)鏈接等)。
服務(wù)端的負(fù)載均衡是一個url通過一個代理服務(wù)器,然后通過代理服務(wù)器(策略:輪詢,隨機(jī) ,權(quán)重等等),反向代理到你的服務(wù)器。
客戶端負(fù)載均衡是通過一個請求在客戶端已經(jīng)聲明了要調(diào)用那個服務(wù),然后通過具體算法來完成負(fù)載均衡。
Ribbon使用
引入依賴,Eureka以及把Ribbon集成在里面。
使用Ribbon只有在RestTemplate上面加入@LoadBalanced注解。
Feign負(fù)載均衡
feign是一個聲明式的webService客戶端,使用feign會讓編寫webService更簡單,就是定義一個接口加上注解。
feign是為了編寫java http客戶端更加簡單,在Ribbon+RestTemplate此基礎(chǔ)上進(jìn)一步封裝,簡化了使用Spring Cloud Ribbon時,自動封裝服務(wù)調(diào)用客戶端的開發(fā)量。
Feign使用
引入依賴 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> 在啟動類上加@EnableFeignClients 然后在接口上加@FeignClient("SERVER-POWER")注解其中參數(shù)就是服務(wù)的名字。Feign集成Ribbon
利用Ribbon維護(hù)服務(wù)列表信息,融合了Ribbon的負(fù)載均衡配置,與Ribbon不同的是Feign只需要定義服務(wù)綁定接口以聲明的方式,實(shí)現(xiàn)簡答的服務(wù)調(diào)用。
hystrix斷路器
是一種用于處理分布式系統(tǒng)延遲和容錯的開源庫。在分布式系統(tǒng)中許多依賴不可避免的會調(diào)用失敗,比如超時、異常等,斷路器保證出錯不會導(dǎo)致整體服務(wù)失敗,避免級聯(lián)故障。
斷路器其實(shí)就是一種開關(guān)設(shè)置,類似保險絲,像調(diào)用方返回一個符合預(yù)期的、可處理的備選響應(yīng),而不是長時間等待或者拋出無法處理的異常,保證服務(wù)調(diào)用方線程不會被長時間 不必要占用,從而避免了在分布式系統(tǒng)中蔓延,乃至雪崩。
微服務(wù)中 client->微服務(wù)A->微服務(wù)B->微服務(wù)C->微服務(wù)D,其中微服務(wù)B異常了,所有請求微服務(wù)A的請求都會卡在B這里,就會導(dǎo)致線程一直累積在這里,那么其他微服務(wù)就沒有可用線程,導(dǎo)致整個服務(wù)器雪崩。
針對這方案有 服務(wù)限流、超時監(jiān)控、服務(wù)熔斷、服務(wù)降級
降級 超時
降級就是服務(wù)響應(yīng)過長 ,或者不可用了,就是服務(wù)調(diào)用不了了,我們不能把錯誤信息返回出來,或者長時間卡在哪里,所以要準(zhǔn)備一個策略當(dāng)發(fā)生這種問題我們直接調(diào)用這個方法快速返回這個請求,不讓他一直卡在那。
要在調(diào)用方做降級(要不然那個微服務(wù)都down掉了在做降級就沒有意義)。
引入hystrix依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> 在啟動類上加入@EnableHystrix 或者@EnableCircuitBreaker。 @RequestMapping("/feignPower.do") @HystrixCommand(fallbackMethod = "fallbackMethod") public Object feignPower(String name){ return powerServiceClient.power(); } fallbackMethod: public Object fallbackMethod(String name){ System.out.println(name); return R.error("降級信息"); } 這里的降級信息具體內(nèi)容根據(jù)業(yè)務(wù)需求來,比如返回一個默認(rèn)的查詢信息等等。 hystrix有超時監(jiān)聽,當(dāng)你請求超過1秒 就會超時,這個是可以配置的這里的降級信息具體內(nèi)容根據(jù)業(yè)務(wù)需求來,比如返回一個默認(rèn)的查詢信息等等。
hystrix有超時監(jiān)聽,當(dāng)你請求超過1秒 就會超時,這個是可以配置的
降級什么用
第一他可以監(jiān)聽服務(wù)有沒有超時。第二報錯了他這里直接截斷了沒有讓請求一直卡在這個。
其實(shí)降級,當(dāng)你系統(tǒng)迎來高并發(fā)的時候,這時候發(fā)現(xiàn)系統(tǒng)馬上承載不了這個大的并發(fā) ,可以先關(guān)閉一些不重要 的微服務(wù)(就是在降級方法返回一個比較友好的信息)把資源讓出來給主服務(wù),其實(shí)就是整體資源不夠用了,忍痛關(guān)閉某些服務(wù),待過渡后再打開。
熔斷限流
熔斷就像生活中的跳閘,比如電路故障了,為了防止事故擴(kuò)大,這里切斷你的電源以免意外發(fā)生。當(dāng)一個微服務(wù)調(diào)用多次,hystrix就會采取熔斷 機(jī)制,不在繼續(xù)調(diào)用你的方法,會默認(rèn)短路,5秒后試探性的先關(guān)閉熔斷機(jī)制,如果在這時候失敗一次會直接調(diào)用降級方法,一定程度避免雪崩,
限流,限制某個微服務(wù)使用量,如果線程占用超過了,超過的就會直接降級該次調(diào)用。
Feign整合hystrix
feign默認(rèn)支持hystrix,需要在yml配置中打開。 feign: hystrix: enabled: true降級方法 @FeignClient(value = "SERVER-POWER", fallback = PowerServiceFallBack.class) public interface PowerServiceClient {@RequestMapping("/power.do") public Object power(@RequestParam("name") String name); }在feign客戶端的注解上 有個屬性叫fallback 然后指向一個類 PowerServiceClient @Component public class PowerServiceFallBack implements PowerServiceClient { @Override public Object power(String name) { return R.error("測試降級"); } }Zuul 網(wǎng)關(guān)
zuul包含了對請求的路由和過濾兩個主要功能
路由是將外部請求轉(zhuǎn)發(fā)到具體的微服務(wù)實(shí)例上。是實(shí)現(xiàn)統(tǒng)一入口基礎(chǔ)而過濾器功能負(fù)責(zé)對請求的處理過程干預(yù),是實(shí)現(xiàn)請求校驗(yàn)等功能。
Zuul與Eureka進(jìn)行整合,將zuul注冊在Eureka服務(wù)治理下,同時從Eureka獲取其他服務(wù)信息。(zuul分服務(wù)最終還是注冊在Eureka上)
路由
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> 最后要注冊在Eureka上所以需要引入eureka依賴 YML server: port: 9000 eureka: client: serviceUrl: defaultZone: http://localhost:3000/eureka/ #eureka服務(wù)端提供的注冊地址 參考服務(wù)端配置的這個路徑 instance: instance-id: zuul-0 #此實(shí)例注冊到eureka服務(wù)端的唯一的實(shí)例ID prefer-ip-address: true #是否顯示IP地址 leaseRenewalIntervalInSeconds: 10 #eureka客戶需要多長時間發(fā)送心跳給eureka服務(wù)器,表明它仍然活著,默認(rèn)為30 秒 (與下面配置的單位都是秒) leaseExpirationDurationInSeconds: 30 #Eureka服務(wù)器在接收到實(shí)例的最后一次發(fā)出的心跳后,需要等待多久才可以將此實(shí)例刪除,默認(rèn)為90秒spring: application: name: zuul #此實(shí)例注冊到eureka服務(wù)端的name 啟動類 @EnableZuulProxy在實(shí)際開發(fā)當(dāng)中我們肯定不會/server-power這樣通過微服務(wù)調(diào)用, 可能只要一個/power就好了 zuul: routes: mypower: serviceId: server-power path: /power/** myorder: serviceId: server-order path: /order/** 注意/**代表是所有層級 /* 是代表一層。 一般我們會禁用服務(wù)名調(diào)用 ignored-services:server-order 這樣就不能通過此服務(wù)名調(diào)用, 不過這個配置如果一個一個通微服務(wù)名字設(shè)置太復(fù)雜 一般禁用服務(wù)名 ignored-services:“*” 有時候要考慮到接口調(diào)用需要一定的規(guī)范,比如調(diào)用微服務(wù)URL需要前綴/api,可以加上一個prefix prefix:/api 在加上strip-prefix: false /api前綴是不會出現(xiàn)在路由中 zuul: prefix: /api ignored-services: "*" stripPrefix: false routes: product: serviceId: server-product path: /product/** order: serviceId: server-order path: /order/**過濾器
過濾器(filter)是zuul的核心組件,zuul大部分功能是通過過濾器實(shí)現(xiàn)的,zuul中定義了4種標(biāo)準(zhǔn)過濾器類型,這些過濾器類型對應(yīng)與請求的生命周期,
PRE:這種過濾器在請求路由前被調(diào)用,可利用過濾器進(jìn)行身份驗(yàn)證,記錄請求微服務(wù)的調(diào)試信息等。
ROUTING:這種過濾器將請求路由到微服務(wù),這種過濾器用于構(gòu)建發(fā)送給微服務(wù)請求,并使用 Apache HttpClient或Netfix Ribbon請求微服務(wù)。
POST:這種過濾器在路由微服務(wù)后執(zhí)行,可用來相應(yīng)添加標(biāo)準(zhǔn)的HTTP Header、收集統(tǒng)計信息和指標(biāo)、將響應(yīng)從微服務(wù)發(fā)送給客戶端。
ERROR:在其他階段發(fā)送錯誤時執(zhí)行過濾器
繼承ZuulFilter
@Component public class LogFilter extends ZuulFilter { @Override public String filterType() { return FilterConstants.PRE_TYPE; }@Override public int filterOrder() { return FilterConstants.PRE_DECORATION_FILTER_ORDER+1; }@Override public boolean shouldFilter() { return true; }@Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); //被代理到的微服務(wù) String proxy = (String)ctx.get("proxy"); //請求的地址 String requestURI = (String)ctx.get("requestURI"); //zuul路由后的url System.out.println(proxy+"/"+requestURI); HttpServletRequest request = ctx.getRequest(); String loginCookie = CookieUtil.getLoginCookie(request); ctx.addZuulRequestHeader("login_key",loginCookie); return null; } }由此可知道自定義zuul Filter要實(shí)現(xiàn)以下幾個方法。
filterType:返回過濾器類型,有pre、route、post、erro等幾種取值
filterOrder:返回一個int值指定過濾器的順序,不同過濾器允許返回相同數(shù)字。
shouldFilter:返回一個boolean判斷過濾器是否執(zhí)行,true執(zhí)行,false不執(zhí)行。
run:過濾器的具體實(shí)現(xiàn)。
Spting-Cloud默認(rèn)為zuul編寫并開啟一些過濾器。如果要禁用部分過濾器,只需在application.yml里設(shè)置zuul…disable=true,例如zuul.LogFilter.pre.disable=true
zuul也整合了了hystrix和ribbon的, 提供降級回退,繼承FallbackProvider 類 然后重寫里面的方法。
總結(jié)
以上是生活随笔為你收集整理的分布式和微服务区别_深度解析spring cloud分布式微服务的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python种颜色循环_Python 实
- 下一篇: 一维数组和二维数组的区别_数组指针和指针