摘要
??今天終于有了點空閑時間,所以更新了一下代碼生成器,修復了用戶反饋的bug,本次更新主要增加了dubbo和springcloud腳手架的下載功能,架子是本人親自搭建,方便自由擴展或者小白學習使用,你也許會問為什么它們不能像springboot一樣通過配置的方式生成項目,我只能回答:理論上是可以的,以后有時間會摸索可行之道,但是我覺得微服務框架業(yè)務復雜多變,不如直接使用腳手架自由擴展來的方便,所以目前是采用了這樣一種方式。本篇博客將具體介紹腳手架每個部分的功能模塊,然后暢想一下微服務技術的未來發(fā)展趨勢。
dubbo腳手架
??dubbo曾經(jīng)風靡一時,但是逐步被springcloud所替代,所以dubbo的腳手架我做的相對簡易,以表緬懷之情。
??代碼生成器獲取dubbo腳手架十分簡單,如下:
??鼠標點擊一下便可自動下載到桌面
??然后看一下腳手架的目錄結構:
??項目導入到了idea當中,因為dubbo需要zookeeper依賴,所以需要配置zookeeper注冊中心,相信你可以自己解決~
??具體的細節(jié)請參考我的dubbo+zookeeper對比springCloud及分布式項目搭建詳解此篇博客,這個腳手架就是博客當中講述的demo項目。
springcloud腳手架
??把springcloud腳手架下載下來導入到idea當中,項目結構如下:
??下面對每個module的配置進行簡要講解,其他的細節(jié)讀者可以使用生成器下載自行查看。
cloud_eureka模塊
??此模塊主要負責服務發(fā)現(xiàn)注冊,相當于dubbo的zookeeper,只不過springCloud使用eureka來進行服務的發(fā)現(xiàn)和注冊,相信大家都知道CAP原則,即一致性,可用性和分區(qū)容錯性,只要是分布式項目,一般都具備分區(qū)容錯性(簡單理解,一個節(jié)點掛了,其他節(jié)點可以正常提供服務)。
??zookeeper本身就不是為高可用設計的,節(jié)點之間的數(shù)據(jù)會保持高度的同步,并且一旦發(fā)生網(wǎng)絡隔離,zookeeper內(nèi)部會進行master選舉,這個選舉流程是十分緩慢的,長達30到120秒,對于一個要不斷向外界提供服務的系統(tǒng)來說,這將是非常致命的!所以dubbo+zookeeper總體來說符合CP原則。
??springcloud的服務注冊中心eureka則不同,eureka每個節(jié)點都是平等的,不會有選舉master節(jié)點這一說法,并且本身具有自我保護機制,具備服務的高度可用性,相對的,它無法做到數(shù)據(jù)的強一致,也就是無法保證在每個節(jié)點上始終獲取的都是最新的數(shù)據(jù),但我們可以在程序設計的時候保證結果的最終一致性。所以springcloud總體來說符合AP原則。
??讓我們看一下cloud_eureka的yml配置,如下:通過加載不同的yml,就可以分別啟動server1和server2構成eureka集群,負責服務發(fā)現(xiàn)和注冊的職責。
??application.yml:
#注冊中心應用名稱
spring:
application:
name: eureka-server
#使用的配置文件名 `java -jar -Dspring.profiles.active=serverX demo.jar`啟動serverX配置
profiles:
active: server1
??application-server1.yml:
#注冊中心運行的端口號
server:
port: 8001
#注冊中心應用名稱
#spring:
# application:
# name: eureka-server
#eureka.server.enableSelfPreservation:是否向注冊中心注冊自己
#通過eureka.client.registerWithEureka:false和fetchRegistry:false來表明自己是一個eureka server.
eureka:
# 自我保護機制
#server:
#enableSelfPreservation: false #關閉eureka的自我保護 小規(guī)模項目關閉比較好
#eviction-interval-timer-in-ms: 5000 #清理間隔時間,單位為毫秒(默認值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:
#注冊中心運行的端口號
server:
port: 8002
#注冊中心應用名稱
#spring:
# application:
# name: eureka-server
#eureka.server.enableSelfPreservation:是否向注冊中心注冊自己
#通過eureka.client.registerWithEureka:false和fetchRegistry:false來表明自己是一個eureka server.
eureka:
# 自我保護機制
#server:
#enableSelfPreservation: false #關閉eureka的自我保護 小規(guī)模項目關閉比較好
#eviction-interval-timer-in-ms: 3000 #清理間隔時間,單位為毫秒(默認值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ǎng)關,這里采用的是zuul,現(xiàn)在spring官方逐漸放棄了zuul,而是采用了自己的gateway網(wǎng)關組件,因為zuul是io阻塞的,但在配置上可以類比zuul的配置。網(wǎng)關組件也是需要在eureka中進行注冊的。
??application.yml如下,ribbon和hystrix的超時時間需要特別配置一下,不然項目啟動之后第一次通過網(wǎng)關訪問服務大概率會報hystrix timeout的超時錯誤(默認超時時間很短),ribbon負責負載均衡,hystrix負責服務熔斷,所以配置上服務熔斷的時間應該大于負載均衡的總時間,否則會一直有warn提示。
服務熔斷的超時時間計算公式如下:
(1+MaxAutoRetries + MaxAutoRetriesNextServer)* ReadTimeout,加1是因為首次訪問不計入重試次數(shù),MaxAutoRetries為同一臺實例最大調(diào)用次數(shù),默認為1,MaxAutoRetriesNextServer為切換其他實例的最大次數(shù),默認為1,所以熔斷器的超時時間要大于重試時間,不然重試就失去了意義,這里通過計算超時時間為20000,所以hystrix的超時時間設置為比20000稍大的30000即可。
#網(wǎng)關
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配置中心,可以從遠程git倉庫拉取配置文件,同時它不需要注冊到eureka當中。
??application.yml內(nèi)容如下:rabbitmq的配置主要是實現(xiàn)服務總線的作用。用戶向config發(fā)送http://localhost:6001/actuator/bus-refresh請求,config會向rabbitmq發(fā)送配置更新的消息,同時配置了服務總線的微服務模塊會監(jiān)聽到此消息,就會重新從遠程拉取配置文件并重新加載,這樣我們在遠程倉庫修改了配置文件無需重啟項目就可以實現(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為其中的一個微服務模塊,同時它也注冊在eureka當中,在service1中,使用了feign來調(diào)用service2,我們知道,微服務可以通過ribbon和feign來調(diào)用,不同的是,ribbon采用restTemplate的方式調(diào)用,feign則是把ribbon封裝了一層,采用接口形式調(diào)用,并且默認支持負載均衡,同時也可選擇開啟服務熔斷,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配置中心主要是為了方便運維,配置上springcloud-bus后可以無需重啟項目加載配置文件,實乃運維之福音。bootstrap.yml內(nèi)容如下:
spring:
cloud:
config:
name: service1 #對應git服務器上的name #name-profile
profile: dev #對應git服務器上的profile
label: master #提交到master分支
uri: http://localhost:6001 #config的訪問地址
??gitee倉庫service-dev.yml內(nèi)容如下:
#注冊中心應用名稱
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同樣注冊進了eureka中,同時也僅僅是注冊進入了eureka中供service1調(diào)用,在真實的項目當中,每個微服務是可以互相調(diào)用的,只是我在這里偷了個懶,沒有配置feign的客戶端調(diào)用,也就是說,它同樣可以調(diào)用service1。
??application.yml如下:
#注冊中心應用名稱
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構成集群,分別使用server1和server2文件啟動項目(先啟動的一方由于另一方?jīng)]有啟動會報錯,當另一方啟動完畢報錯即會自動消失,因為兩方是互相注冊形成高可用集群),啟動完畢后,訪問http://localhost:8001/即可看到server1界面,如下:
??同樣,server2也是可以正常訪問的,這里就不再截圖了。
??接下里啟動配置中心,注意service1的yml需要通過config遠程獲取,所以需要先啟動配置中心config,然后再分別啟動service1和service2,最后啟動zuul。如果沒有配置rabbitmq,啟動config和service1會報錯失?。ㄌ崾緹o法連接rabbitmq服務),不啟動它們也可。全部啟動完畢后,發(fā)現(xiàn)eureka注冊中心已經(jīng)有了各自的服務注冊信息,如圖:
??如上圖,我們成功啟動了兩個service微服務和zuul服務網(wǎng)關。在這里eureka界面的紅色字體是由于eureka的自我保護機制觸發(fā)的,并不是報錯,當eureka收到的最后一分鐘服務實例續(xù)約的總數(shù)/每分鐘期望收到的續(xù)約數(shù)<85%的時候,便會觸發(fā)自我保護機制告訴你可能有節(jié)點出了問題(比如網(wǎng)絡延遲,并不是服務真的掛了),但是它不會去剔除它,會保留其注冊信息,等到節(jié)點恢復正常仍然可以繼續(xù)工作,這樣使得整個服務更加高可用。
??最后我們通過zuul網(wǎng)關地址訪問service1的服務(service1會通過feign調(diào)用service2),訪問http://localhost:7001/service1/test/do(如果沒有啟動config和service1,訪問http://localhost:7001/service2/test/do),如下:
??這樣一來,整個流程就結束了,springcloud的核心組件也就講解完畢。
微服務遐想
??值得一提的是,在真實的微服務項目中,服務的數(shù)量遠遠不止這些,代碼生成器也只是幫助你搭建了基本的架構模型。所以如果通過人工部署管理的方式會變得異常困難,但后來隨著容器化技術的發(fā)展,通過dockerfile把每個服務生成鏡像在dokcer容器中運行漸漸成為一種主流的部署運維方式,并且通過maven插件可以一鍵構建dockerfile文件生成鏡像并上傳至docker私服,通過docker私服便可以上傳我們自己的微服務鏡像文件并十分方便的運行它們,通過jenkins持續(xù)集成,同時也讓微服務發(fā)布更加的容易,最后為了統(tǒng)一管理docker容器,k8s超過docker swarm成為容器化應用的新一代寵兒,時代在飛速發(fā)展,技術的迭代也同樣迅速!
??前陣子跟朋友微信閑聊,了解到Service Mesh技術正在悄然興起,大廠已經(jīng)有了落地應用,簡單理解,service mesh把每個微服務做了進一步的解耦,把通信相關的操作(負載均衡,斷路器等)抽離了出來,為每個微服務生成了一個代理服務,而微服務做到了真正只需要關心業(yè)務。以前的微服務是單輪車,現(xiàn)在變成了雙輪車,所以有人也稱它為“邊車模式“,把每個代理服務用線連接起來,組成了一個錯綜復雜的網(wǎng)格,service mesh也就由此而來,后來演化出了集中式的控制面板來管理一個個的網(wǎng)格,代表作品:Istio。
??但同樣的,由于service mesh接管了網(wǎng)絡流量,系統(tǒng)的穩(wěn)定性就會依賴于service mesh,同時相比之前,額外引入的大量service mesh實例對運維和管理來說也是一個巨大的挑戰(zhàn)。
??service mesh是未來微服務的發(fā)展趨勢,歷史也總是驚人的相似,最開始的時候,人們?yōu)榱私鉀Q端到端的通信問題,tcp協(xié)議橫空出世,多機通信從此變得簡單可靠。如今我們來到了微服務時代,為了屏蔽分布式系統(tǒng)的通信復雜性,service mesh應運而生。這讓我們回歸業(yè)務,聚焦真正的價值!
代碼生成器:點擊下載