摘要
??今天終于有了點(diǎn)空閑時間窃判,所以更新了一下代碼生成器钞楼,修復(fù)了用戶反饋的bug,本次更新主要增加了dubbo和springcloud腳手架的下載功能袄琳,架子是本人親自搭建询件,方便自由擴(kuò)展或者小白學(xué)習(xí)使用,你也許會問為什么它們不能像springboot一樣通過配置的方式生成項(xiàng)目唆樊,我只能回答:理論上是可以的宛琅,以后有時間會摸索可行之道,但是我覺得微服務(wù)框架業(yè)務(wù)復(fù)雜多變逗旁,不如直接使用腳手架自由擴(kuò)展來的方便夯秃,所以目前是采用了這樣一種方式。本篇博客將具體介紹腳手架每個部分的功能模塊,然后暢想一下微服務(wù)技術(shù)的未來發(fā)展趨勢仓洼。
dubbo腳手架
??dubbo曾經(jīng)風(fēng)靡一時介陶,但是逐步被springcloud所替代,所以dubbo的腳手架我做的相對簡易色建,以表緬懷之情哺呜。
??代碼生成器獲取dubbo腳手架十分簡單,如下:
??鼠標(biāo)點(diǎn)擊一下便可自動下載到桌面
??然后看一下腳手架的目錄結(jié)構(gòu):
??項(xiàng)目導(dǎo)入到了idea當(dāng)中箕戳,因?yàn)閐ubbo需要zookeeper依賴某残,所以需要配置zookeeper注冊中心,相信你可以自己解決~
??具體的細(xì)節(jié)請參考我的dubbo+zookeeper對比springCloud及分布式項(xiàng)目搭建詳解此篇博客陵吸,這個腳手架就是博客當(dāng)中講述的demo項(xiàng)目玻墅。
springcloud腳手架
??把springcloud腳手架下載下來導(dǎo)入到idea當(dāng)中,項(xiàng)目結(jié)構(gòu)如下:
??下面對每個module的配置進(jìn)行簡要講解壮虫,其他的細(xì)節(jié)讀者可以使用生成器下載自行查看澳厢。
cloud_eureka模塊
??此模塊主要負(fù)責(zé)服務(wù)發(fā)現(xiàn)注冊,相當(dāng)于dubbo的zookeeper囚似,只不過springCloud使用eureka來進(jìn)行服務(wù)的發(fā)現(xiàn)和注冊剩拢,相信大家都知道CAP原則,即一致性饶唤,可用性和分區(qū)容錯性徐伐,只要是分布式項(xiàng)目,一般都具備分區(qū)容錯性(簡單理解募狂,一個節(jié)點(diǎn)掛了办素,其他節(jié)點(diǎn)可以正常提供服務(wù))。
??zookeeper本身就不是為高可用設(shè)計(jì)的祸穷,節(jié)點(diǎn)之間的數(shù)據(jù)會保持高度的同步摸屠,并且一旦發(fā)生網(wǎng)絡(luò)隔離,zookeeper內(nèi)部會進(jìn)行master選舉粱哼,這個選舉流程是十分緩慢的季二,長達(dá)30到120秒,對于一個要不斷向外界提供服務(wù)的系統(tǒng)來說揭措,這將是非常致命的胯舷!所以dubbo+zookeeper總體來說符合CP原則。
??springcloud的服務(wù)注冊中心eureka則不同绊含,eureka每個節(jié)點(diǎn)都是平等的桑嘶,不會有選舉master節(jié)點(diǎn)這一說法,并且本身具有自我保護(hù)機(jī)制躬充,具備服務(wù)的高度可用性逃顶,相對的讨便,它無法做到數(shù)據(jù)的強(qiáng)一致,也就是無法保證在每個節(jié)點(diǎn)上始終獲取的都是最新的數(shù)據(jù)以政,但我們可以在程序設(shè)計(jì)的時候保證結(jié)果的最終一致性霸褒。所以springcloud總體來說符合AP原則。
??讓我們看一下cloud_eureka的yml配置盈蛮,如下:通過加載不同的yml废菱,就可以分別啟動server1和server2構(gòu)成eureka集群,負(fù)責(zé)服務(wù)發(fā)現(xiàn)和注冊的職責(zé)抖誉。
??application.yml:
#注冊中心應(yīng)用名稱
spring:
application:
name: eureka-server
#使用的配置文件名 `java -jar -Dspring.profiles.active=serverX demo.jar`啟動serverX配置
profiles:
active: server1
??application-server1.yml:
#注冊中心運(yùn)行的端口號
server:
port: 8001
#注冊中心應(yīng)用名稱
#spring:
# application:
# name: eureka-server
#eureka.server.enableSelfPreservation:是否向注冊中心注冊自己
#通過eureka.client.registerWithEureka:false和fetchRegistry:false來表明自己是一個eureka server.
eureka:
# 自我保護(hù)機(jī)制
#server:
#enableSelfPreservation: false #關(guān)閉eureka的自我保護(hù) 小規(guī)模項(xiàng)目關(guān)閉比較好
#eviction-interval-timer-in-ms: 5000 #清理間隔時間殊轴,單位為毫秒(默認(rèn)值60 * 1000)
#use-read-only-response-cache: false
instance:
hostname: server1
prefer-ip-address: false
# ip-address: 172.193.225.185
# instance-id: ${spring.cloud.client.ipAddress}:${server.port}
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://server2:8002/eureka/
??application-server2.yml:
#注冊中心運(yùn)行的端口號
server:
port: 8002
#注冊中心應(yīng)用名稱
#spring:
# application:
# name: eureka-server
#eureka.server.enableSelfPreservation:是否向注冊中心注冊自己
#通過eureka.client.registerWithEureka:false和fetchRegistry:false來表明自己是一個eureka server.
eureka:
# 自我保護(hù)機(jī)制
#server:
#enableSelfPreservation: false #關(guān)閉eureka的自我保護(hù) 小規(guī)模項(xiàng)目關(guān)閉比較好
#eviction-interval-timer-in-ms: 3000 #清理間隔時間,單位為毫秒(默認(rèn)值60 * 1000)
#use-read-only-response-cache: false
instance:
hostname: server2
prefer-ip-address: false
# ip-address: 172.193.225.185
# instance-id: ${spring.cloud.client.ipAddress}:${server.port}
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://server1:8001/eureka/
cloud_zuul模塊
??此模塊是所有微服務(wù)的網(wǎng)關(guān)袒炉,這里采用的是zuul旁理,現(xiàn)在spring官方逐漸放棄了zuul,而是采用了自己的gateway網(wǎng)關(guān)組件我磁,因?yàn)閦uul是io阻塞的孽文,但在配置上可以類比zuul的配置。網(wǎng)關(guān)組件也是需要在eureka中進(jìn)行注冊的十性。
??application.yml如下叛溢,ribbon和hystrix的超時時間需要特別配置一下塑悼,不然項(xiàng)目啟動之后第一次通過網(wǎng)關(guān)訪問服務(wù)大概率會報(bào)hystrix timeout的超時錯誤(默認(rèn)超時時間很短)劲适,ribbon負(fù)責(zé)負(fù)載均衡,hystrix負(fù)責(zé)服務(wù)熔斷厢蒜,所以配置上服務(wù)熔斷的時間應(yīng)該大于負(fù)載均衡的總時間霞势,否則會一直有warn提示。
服務(wù)熔斷的超時時間計(jì)算公式如下:
(1+MaxAutoRetries + MaxAutoRetriesNextServer)* ReadTimeout斑鸦,加1是因?yàn)槭状卧L問不計(jì)入重試次數(shù)愕贡,MaxAutoRetries為同一臺實(shí)例最大調(diào)用次數(shù),默認(rèn)為1巷屿,MaxAutoRetriesNextServer為切換其他實(shí)例的最大次數(shù)固以,默認(rèn)為1,所以熔斷器的超時時間要大于重試時間嘱巾,不然重試就失去了意義憨琳,這里通過計(jì)算超時時間為20000,所以hystrix的超時時間設(shè)置為比20000稍大的30000即可旬昭。
#網(wǎng)關(guān)
spring:
application:
name: cloud-zuul
eureka:
client:
service-url:
defaultZone: http://server1:8001/eureka/,http://server2:8002/eureka/
instance:
prefer-ip-address: true
server:
port: 7001
zuul:
routes:
cloud-service1: #測試service1
path: /service1/**
serviceId: cloud-service1
cloud-service2: #測試service1
path: /service2/**
serviceId: cloud-service2
host:
connect-timeout-millis: 15000
socket-timeout-millis: 10000
ribbon:
ConnectTimeout: 5000
ReadTimeout: 5000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 30000
cloud_config模塊
??此模塊為springcloud配置中心篙螟,可以從遠(yuǎn)程git倉庫拉取配置文件,同時它不需要注冊到eureka當(dāng)中问拘。
??application.yml內(nèi)容如下:rabbitmq的配置主要是實(shí)現(xiàn)服務(wù)總線的作用遍略。用戶向config發(fā)送http://localhost:6001/actuator/bus-refresh請求惧所,config會向rabbitmq發(fā)送配置更新的消息,同時配置了服務(wù)總線的微服務(wù)模塊會監(jiān)聽到此消息绪杏,就會重新從遠(yuǎn)程拉取配置文件并重新加載下愈,這樣我們在遠(yuǎn)程倉庫修改了配置文件無需重啟項(xiàng)目就可以實(shí)現(xiàn)配置的更新。
server:
port: 6001
spring:
application:
name: cloud-config
cloud:
config:
server:
git:
uri: https://gitee.com/zrxjava/cloudModel_config.git
rabbitmq:
host: 127.0.0.1
username: guest
password: guest
#刷新總線的接口
management:
endpoints:
jmx:
exposure:
exclude: bus-refresh
cloud_service1模塊
??service1為其中的一個微服務(wù)模塊寞忿,同時它也注冊在eureka當(dāng)中驰唬,在service1中,使用了feign來調(diào)用service2腔彰,我們知道叫编,微服務(wù)可以通過ribbon和feign來調(diào)用,不同的是霹抛,ribbon采用restTemplate的方式調(diào)用搓逾,feign則是把ribbon封裝了一層,采用接口形式調(diào)用杯拐,并且默認(rèn)支持負(fù)載均衡霞篡,同時也可選擇開啟服務(wù)熔斷,feign客戶端代碼如下:
package consumer.client;
import consumer.client.impl.Service2ClientImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
@Component //僅僅是為了屏蔽idea誤顯示的注入錯誤
@FeignClient(value = "cloud-service2", fallback = Service2ClientImpl.class)
public interface Service2Client {
@GetMapping("/test/do")
public String test();
}
package consumer.client.impl;
import consumer.client.Service2Client;
import org.springframework.stereotype.Component;
//熔斷器執(zhí)行的方法
@Component
public class Service2ClientImpl implements Service2Client {
@Override
public String test() {
return "觸發(fā)熔斷器端逼!";
}
}
??service1的配置文件通過config配置中心管理朗兵,啟動service1的時候會加載bootstrap.yml的配置,從gitee上拉取配置文件顶滩,config配置中心主要是為了方便運(yùn)維余掖,配置上springcloud-bus后可以無需重啟項(xiàng)目加載配置文件,實(shí)乃運(yùn)維之福音礁鲁。bootstrap.yml內(nèi)容如下:
spring:
cloud:
config:
name: service1 #對應(yīng)git服務(wù)器上的name #name-profile
profile: dev #對應(yīng)git服務(wù)器上的profile
label: master #提交到master分支
uri: http://localhost:6001 #config的訪問地址
??gitee倉庫service-dev.yml內(nèi)容如下:
#注冊中心應(yīng)用名稱
spring:
application:
name: cloud-service1
rabbitmq:
host: 127.0.0.1
username: guest
password: guest
eureka:
client:
service-url:
defaultZone: http://server1:8001/eureka/,http://server2:8002/eureka/
instance:
prefer-ip-address: true
server:
port: 9001
feign:
hystrix:
enabled: true
ribbon:
ConnectTimeout: 5000
ReadTimeout: 5000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 30000
cloud_service2模塊
??service2跟service1同樣注冊進(jìn)了eureka中盐欺,同時也僅僅是注冊進(jìn)入了eureka中供service1調(diào)用,在真實(shí)的項(xiàng)目當(dāng)中仅醇,每個微服務(wù)是可以互相調(diào)用的冗美,只是我在這里偷了個懶,沒有配置feign的客戶端調(diào)用析二,也就是說粉洼,它同樣可以調(diào)用service1。
??application.yml如下:
#注冊中心應(yīng)用名稱
spring:
application:
name: cloud-service2
eureka:
client:
service-url:
defaultZone: http://server1:8001/eureka/,http://server2:8002/eureka/
instance:
prefer-ip-address: true
server:
port: 9002
測試
??首先我們啟動兩個eureka構(gòu)成集群叶摄,分別使用server1和server2文件啟動項(xiàng)目(先啟動的一方由于另一方?jīng)]有啟動會報(bào)錯属韧,當(dāng)另一方啟動完畢報(bào)錯即會自動消失,因?yàn)閮煞绞腔ハ嘧孕纬筛呖捎眉海┳佳瑁瑔油戤吅蟠旖#L問http://localhost:8001/即可看到server1界面,如下:
??同樣柱衔,server2也是可以正常訪問的樊破,這里就不再截圖了愉棱。
??接下里啟動配置中心,注意service1的yml需要通過config遠(yuǎn)程獲取哲戚,所以需要先啟動配置中心config奔滑,然后再分別啟動service1和service2,最后啟動zuul顺少。如果沒有配置rabbitmq朋其,啟動config和service1會報(bào)錯失敗(提示無法連接rabbitmq服務(wù))脆炎,不啟動它們也可梅猿。全部啟動完畢后,發(fā)現(xiàn)eureka注冊中心已經(jīng)有了各自的服務(wù)注冊信息秒裕,如圖:
??如上圖袱蚓,我們成功啟動了兩個service微服務(wù)和zuul服務(wù)網(wǎng)關(guān)。在這里eureka界面的紅色字體是由于eureka的自我保護(hù)機(jī)制觸發(fā)的几蜻,并不是報(bào)錯喇潘,當(dāng)eureka收到的最后一分鐘服務(wù)實(shí)例續(xù)約的總數(shù)/每分鐘期望收到的續(xù)約數(shù)<85%的時候,便會觸發(fā)自我保護(hù)機(jī)制告訴你可能有節(jié)點(diǎn)出了問題(比如網(wǎng)絡(luò)延遲梭稚,并不是服務(wù)真的掛了)颖低,但是它不會去剔除它,會保留其注冊信息弧烤,等到節(jié)點(diǎn)恢復(fù)正常仍然可以繼續(xù)工作忱屑,這樣使得整個服務(wù)更加高可用。
??最后我們通過zuul網(wǎng)關(guān)地址訪問service1的服務(wù)(service1會通過feign調(diào)用service2)扼褪,訪問http://localhost:7001/service1/test/do(如果沒有啟動config和service1想幻,訪問http://localhost:7001/service2/test/do)粱栖,如下:
??這樣一來话浇,整個流程就結(jié)束了,springcloud的核心組件也就講解完畢闹究。
微服務(wù)遐想
??值得一提的是幔崖,在真實(shí)的微服務(wù)項(xiàng)目中,服務(wù)的數(shù)量遠(yuǎn)遠(yuǎn)不止這些渣淤,代碼生成器也只是幫助你搭建了基本的架構(gòu)模型赏寇。所以如果通過人工部署管理的方式會變得異常困難,但后來隨著容器化技術(shù)的發(fā)展价认,通過dockerfile把每個服務(wù)生成鏡像在dokcer容器中運(yùn)行漸漸成為一種主流的部署運(yùn)維方式嗅定,并且通過maven插件可以一鍵構(gòu)建dockerfile文件生成鏡像并上傳至docker私服,通過docker私服便可以上傳我們自己的微服務(wù)鏡像文件并十分方便的運(yùn)行它們用踩,通過jenkins持續(xù)集成渠退,同時也讓微服務(wù)發(fā)布更加的容易忙迁,最后為了統(tǒng)一管理docker容器,k8s超過docker swarm成為容器化應(yīng)用的新一代寵兒碎乃,時代在飛速發(fā)展,技術(shù)的迭代也同樣迅速!
??前陣子跟朋友微信閑聊俗壹,了解到Service Mesh技術(shù)正在悄然興起宾符,大廠已經(jīng)有了落地應(yīng)用,簡單理解梗掰,service mesh把每個微服務(wù)做了進(jìn)一步的解耦嵌言,把通信相關(guān)的操作(負(fù)載均衡,斷路器等)抽離了出來及穗,為每個微服務(wù)生成了一個代理服務(wù)呀页,而微服務(wù)做到了真正只需要關(guān)心業(yè)務(wù)。以前的微服務(wù)是單輪車拥坛,現(xiàn)在變成了雙輪車蓬蝶,所以有人也稱它為“邊車模式“,把每個代理服務(wù)用線連接起來猜惋,組成了一個錯綜復(fù)雜的網(wǎng)格丸氛,service mesh也就由此而來,后來演化出了集中式的控制面板來管理一個個的網(wǎng)格著摔,代表作品:Istio缓窜。
??但同樣的,由于service mesh接管了網(wǎng)絡(luò)流量谍咆,系統(tǒng)的穩(wěn)定性就會依賴于service mesh禾锤,同時相比之前,額外引入的大量service mesh實(shí)例對運(yùn)維和管理來說也是一個巨大的挑戰(zhàn)摹察。
??service mesh是未來微服務(wù)的發(fā)展趨勢恩掷,歷史也總是驚人的相似,最開始的時候供嚎,人們?yōu)榱私鉀Q端到端的通信問題黄娘,tcp協(xié)議橫空出世,多機(jī)通信從此變得簡單可靠克滴。如今我們來到了微服務(wù)時代逼争,為了屏蔽分布式系統(tǒng)的通信復(fù)雜性,service mesh應(yīng)運(yùn)而生劝赔。這讓我們回歸業(yè)務(wù)誓焦,聚焦真正的價值!
代碼生成器:點(diǎn)擊下載