SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式

微服務(wù):
- 拆分(單體項(xiàng)目拆分為許多個(gè)獨(dú)立的項(xiàng)目,獨(dú)立開(kāi)發(fā)和部署。形成服務(wù)集群)
- (異步通信可以大大的提高并發(fā),秒殺、等大的場(chǎng)景下可以去利用。)


自動(dòng)化部署
持續(xù)集成

單體架構(gòu)
單體架構(gòu):將業(yè)務(wù)的所有功能集中在一個(gè)項(xiàng)目中假發(fā),打成一個(gè)包部署。
優(yōu)點(diǎn):
架構(gòu)簡(jiǎn)單
部署成本低(負(fù)載均衡的集群)
缺點(diǎn):
耦合度高
分布式架構(gòu)
分布式架構(gòu):根據(jù)業(yè)務(wù)功能對(duì)系統(tǒng)進(jìn)行拆分,每個(gè)業(yè)務(wù)模塊作為獨(dú)立項(xiàng)目開(kāi)發(fā),稱(chēng)為一個(gè)服務(wù)。
優(yōu)點(diǎn):
降低服務(wù)耦合
有利于服務(wù)升級(jí)拓展

分布式架構(gòu)要考慮的問(wèn)題:

微服務(wù):
微服務(wù)就是一種經(jīng)過(guò)良好框架設(shè)計(jì)的分布式架構(gòu)方案,微服務(wù)架構(gòu)特征:
- 單一職責(zé):微服務(wù)拆分力度更小,每一個(gè)服務(wù)都對(duì)應(yīng)唯一的業(yè)務(wù)能力,做到單一職責(zé),避免重復(fù)業(yè)務(wù)開(kāi)發(fā)。
- 面向服務(wù): 微服務(wù)對(duì)外暴露業(yè)務(wù)接口
- 自治: 團(tuán)隊(duì)獨(dú)立、技術(shù)獨(dú)立、數(shù)據(jù)獨(dú)立、部署獨(dú)立
- 隔離性強(qiáng): 服務(wù)調(diào)用做好隔離、容錯(cuò)、降級(jí),避免出現(xiàn)級(jí)聯(lián)問(wèn)題

實(shí)現(xiàn)了cloud的接口規(guī)范,


SpringCloud
- SpringCloud是目前國(guó)內(nèi)使用最廣泛的微服務(wù)框架。官網(wǎng)地址:https://spring.io/projects/spring-cloud

springboot和springcloud版本兼容性:

服務(wù)拆分注意事項(xiàng)

微服務(wù)遠(yuǎn)程調(diào)用

1)注冊(cè)RestTemplate


提供者與消費(fèi)者
一個(gè)服務(wù)既可以是提供者,也可以是消費(fèi)者。


Eureka注冊(cè)中心
作用:
服務(wù)消費(fèi)者和服務(wù)提供者統(tǒng)稱(chēng)為Eureka客戶端。
1)注冊(cè)服務(wù)信息
2)拉去服務(wù)的信息
3)負(fù)載均衡
4)遠(yuǎn)程調(diào)用
(服務(wù)每隔30s都會(huì)向Eureka發(fā)送一次心跳,確認(rèn)自己的狀態(tài))心跳續(xù)約,每30s/次


搭建EurekaServer
搭建EurekaServer服務(wù)步驟如下:
1.創(chuàng)建項(xiàng)目,引入spring-cloud-starter-eureka-server的依賴(lài)
2.編寫(xiě)啟動(dòng)類(lèi),添加@EnableEurekaServer注解
3.添加application.yml文件,配置如下信息:
server:
?port: 9090
# 單機(jī)版
eureka:
?instance:
??hostname: localhost #eureka服務(wù)端的實(shí)例名稱(chēng)
??lease-expiration-duration-in-seconds: 15
??lease-renewal-interval-in-seconds: 5
?client:
??register-with-eureka: false #false表示不向注冊(cè)中心注冊(cè)自己
??fetch-registry: false #false表示自己端就是注冊(cè)中心,職責(zé)就是維護(hù)服務(wù)實(shí)例,并不需要去檢索服務(wù)
??service-url: #設(shè)置與eureka server交互的地址查詢服務(wù)和注冊(cè)服務(wù)都需要依賴(lài)這個(gè)地址
???defaultZone: #地址信息http://${eureka.instance.hostname}:${server.port}/eureka/



Ribbon負(fù)載均衡
負(fù)載均衡流程

攔截客戶端發(fā)起的http請(qǐng)求(客戶端http請(qǐng)求攔截器)接口
實(shí)現(xiàn)類(lèi) loadbalan
獲取請(qǐng)求uri,根據(jù)uri獲取host(主機(jī)名/服務(wù)名),
拉取服務(wù)列表

getserver()負(fù)載均衡,(取出一個(gè))
內(nèi)部調(diào)用chooseserver(),[選擇服務(wù)]
rule.choose() 規(guī)則
ctrl+h查看實(shí)現(xiàn)類(lèi)
randomrule (隨機(jī))
roundrobinrule(輪詢調(diào)度--輪詢負(fù)載均衡)
默認(rèn):ZoneAvoidanceRule



負(fù)載均衡策略:
通過(guò)定義IRule實(shí)現(xiàn)跨越修改負(fù)載均衡規(guī)則,有兩種方式:
- 代碼方式: 在order-service中的orderApplication類(lèi)中,定義一個(gè)新的irule:(作用于全局,即無(wú)論調(diào)用哪一個(gè)服務(wù)都是隨機(jī)的。)
- 配置文件方式: 在 order-service的application.yml文件中,添加新的配置也可以修改規(guī)則。

饑餓加載
ribbon默認(rèn)是采用懶加載,即第一次訪問(wèn)時(shí)才會(huì)去創(chuàng)建LoadBalanceClient,請(qǐng)求時(shí)間會(huì)很長(zhǎng)。而饑餓加載則會(huì)在項(xiàng)目啟動(dòng)時(shí)創(chuàng)建,降低第一次訪問(wèn)的耗時(shí),通過(guò)下面配置開(kāi)啟饑餓加載:
ribbon:
eager-load:
enable: true #開(kāi)啟饑餓加載
clients: userserver #指定對(duì)userservice這個(gè)服務(wù)饑餓加載
【拉去服務(wù)日志,即所謂懶加載。將會(huì)緩存在內(nèi)存中?!?/p>


Nacos注冊(cè)中心
功能: 服務(wù)的注冊(cè)和發(fā)現(xiàn);分布式配置
https://nacos.io/zh-cn/docs/quick-start.html
啟動(dòng)命令:
startup.cmd -m standalone (-m: 配置; standalone : 單機(jī)啟動(dòng))
依賴(lài),組測(cè)中心地址
服務(wù)跨集群調(diào)用問(wèn)題
服務(wù)調(diào)用是盡可能的選擇本地集群服務(wù),跨集群調(diào)用延遲較高
本地集群不可訪問(wèn)時(shí),再去訪問(wèn)其他集群。
(防止跨集群調(diào)用)
無(wú)集群情況下:

配置集群信息:



本地+隨機(jī)(優(yōu)先選擇本地集群,然后根據(jù)隨機(jī)方式進(jìn)行負(fù)載和均衡)

根據(jù)權(quán)重負(fù)載均衡
實(shí)際部署中會(huì)出現(xiàn)這樣的場(chǎng)景:
- 服務(wù)器設(shè)備性能有差異,部分實(shí)例所在機(jī)器性能較好,另一些較差,我們希望性能好的機(jī)器承擔(dān)更多的用戶請(qǐng)求。
Nacos提供了權(quán)重配置來(lái)控制訪問(wèn)頻率,權(quán)重越大則訪問(wèn)頻率越高。
1.在Nacos控制臺(tái)可以設(shè)置實(shí)例的權(quán)重值,首先選中實(shí)力后面的編輯按鈕
2.將權(quán)重設(shè)置為0.1(一般0 ~ 1)

如果權(quán)重為0,服務(wù)將不會(huì)被訪問(wèn)。
(版本升級(jí))

環(huán)境隔離-namespace
Nacos中服務(wù)存儲(chǔ)和數(shù)據(jù)存儲(chǔ)的最外層都是一個(gè)名為namespace的東西,用來(lái)做最外層隔離

服務(wù)劃分,實(shí)例劃分是基于業(yè)務(wù)/地域做得。
namespace基于環(huán)境做的隔離
新建一個(gè)命名空間信息,生成一個(gè)id(uuid)


添加namespace:

最終效果:

分組之后會(huì)出現(xiàn)無(wú)法訪問(wèn)(環(huán)境隔離)


注冊(cè)中心細(xì)節(jié)分析

差別在于服務(wù)提供者的健康檢測(cè)(臨時(shí)實(shí)例和非臨時(shí)實(shí)例,默認(rèn)為true,所有的均為臨時(shí)實(shí)例)

nacos不會(huì)把非臨時(shí)實(shí)力從列表中剔除,而僅僅是標(biāo)記為不健康了。等待此服務(wù)恢復(fù)健康


臨時(shí)實(shí)例和非臨時(shí)實(shí)例
服務(wù)注冊(cè)到nacos時(shí),可以選擇注冊(cè)為臨時(shí)或非臨時(shí)實(shí)例,通過(guò)下面的配置來(lái)設(shè)置。

非臨時(shí)實(shí)例掛機(jī)前后對(duì)比
【掛機(jī)前】

【掛機(jī)后】

(除非手動(dòng)提出,否則服務(wù)將一直存在)
(臨時(shí)服務(wù)掛機(jī)后將會(huì)失去監(jiān)控,--從列表中消失)

ap:強(qiáng)調(diào)服務(wù)的可用性;cp: 強(qiáng)調(diào)數(shù)據(jù)可靠性和一致性
目錄:


nacos配置調(diào)用
統(tǒng)一配置管理
- 配置更新熱更新
(服務(wù)配置和本地配置結(jié)合使用,可以直接在配置服務(wù)上更新配置信息,)


dateid:配置文件名稱(chēng),不建議使用application.yml,會(huì)產(chǎn)生沖突,命名規(guī)則: [服務(wù)名稱(chēng)]-[運(yùn)行環(huán)境].[后綴名(yml全稱(chēng)yaml)示例: userserver-dev.yaml
配置內(nèi)容:(需要做熱更新的配置,不需要變更的配置可以不使用,一般開(kāi)關(guān)類(lèi)的配置,模板類(lèi)型的,)
logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss
【示例圖】

配置獲取步驟如下:

去哪讀取,讀取誰(shuí)?

spring提供bootstrap.yml文件

1.引入配置
<!--springcloudalibaba nacos客戶端配置文件依賴(lài)--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
2.在userservice中的resource目錄添加一個(gè)bootstrap.yml文件,這個(gè)文件是引導(dǎo)文件,優(yōu)先級(jí)高于application.yml:

配置自動(dòng)刷新
nacos中的配置文件變更后,微服務(wù)無(wú)需重啟就可以自動(dòng)感知。不過(guò)需要通過(guò)下面兩種配置實(shí)現(xiàn):
- 方式一: 在@Value注入的變量所在類(lèi)上添加注解@RefreshScope

方式二:使用@ConfigurationProperties注解
(完成配置的自動(dòng)加載)

推薦使用第二種

多環(huán)境配置共享
(開(kāi)發(fā)、生產(chǎn)、測(cè)試環(huán)境一直,)
微服務(wù)啟動(dòng)時(shí)會(huì)從nacos讀取多個(gè)配置文件:
- [spring.application.name]-[spring.profiles.active].yaml,例如: userservice-dev.yaml
- [spring.application.name].yaml,例如: userservice.yaml,
無(wú)論profile(環(huán)境)如何變化,[spring.application.name].yaml這個(gè)文件一定會(huì)加載,因此多環(huán)境共享可以寫(xiě)入這個(gè)文件。
自動(dòng)激活環(huán)境的簡(jiǎn)單操作,避免更改代碼
(選中項(xiàng)目,右鍵,選擇edit configration,)

運(yùn)行日志查看:

當(dāng)userservice和本地代碼都有的時(shí)候,屬性以u(píng)serservice.yaml為準(zhǔn)。
配置文件優(yōu)先級(jí):
[spring.application.name]-[spring.profiles.active].yaml > [spring.application.name].yaml > 本地代碼環(huán)境
多種配置的優(yōu)先級(jí):
- 服務(wù)名-profile.yaml > 服務(wù)名.yaml > 本地配置


nacos集群搭建:

(默認(rèn)集群?jiǎn)?dòng))

Feign遠(yuǎn)程調(diào)用(http客戶端)
feign代替RestTemplate
RestTemplate方式調(diào)用存在的問(wèn)題:

存在下面的問(wèn)題:
- 代碼可讀性差,編程體驗(yàn)不統(tǒng)一
- 參數(shù)復(fù)雜URL難以維護(hù)
feign是一個(gè)聲明式的http客戶端,官網(wǎng)地址: https://github.com/OpenFeign/feign
其作用就是幫助優(yōu)雅的實(shí)現(xiàn)http請(qǐng)求發(fā)送,
1.引入依賴(lài):
<!--feign 依賴(lài) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2.啟動(dòng)類(lèi)添加注解開(kāi)啟feign功能
@EnableFeignClients

3.編寫(xiě)feign客戶端

4.feign代替restTeplate


自定義配置

避免網(wǎng)絡(luò)波動(dòng)導(dǎo)致的訪問(wèn)結(jié)果失敗

將會(huì)打印日志:
2022-04-03 21:42:30.946?WARN 28168 --- [nio-9081-exec-7] c.alibaba.cloud.nacos.ribbon.NacosRule??: A cross-cluster call occurs,name = orderserver, clusterName = HN, instance = [Instance{instanceId='192.168.0.103#9091#DEFAULT#DEFAULT_GROUP@@orderserver', ip='192.168.0.103', port=9091, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='DEFAULT', serviceName='DEFAULT_GROUP@@orderserver', metadata={preserved.register.source=SPRING_CLOUD}}]


Feign使用優(yōu)化
Feign底層客戶端實(shí)現(xiàn):
- URLConnection: 默認(rèn)實(shí)現(xiàn),不支持連接池(性能不太好)
- Apache HttpClient: 支持連接池
- OKHttp: 支持連接池
因此優(yōu)化Feign的性能主要包括:
使用連接池替代默認(rèn)的URLConnection
日志級(jí)別,最好用basic或none
Feign使用優(yōu)化-連接池配置
Feign添加HttpClient的支持
引入依賴(lài):
<!--httpclient的依賴(lài)--> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>
配置連接池
feign: client: config: # default: 全局配置,orderserver(服務(wù)名): 局域配置 default: # 日志級(jí)別 full BASIC 就是基本的請(qǐng)求和相應(yīng)信息 loggerLevel: BASIC httpclient: # 開(kāi)啟feign對(duì)httpclient的支持 enabled: true # 最大連接數(shù) max-connections: 200 # 每個(gè)路徑的最大連接數(shù) feign.httpclient.max-connections-per-route: 50

最佳實(shí)踐
- 方式一(繼承): 給消費(fèi)者的feignclient和提供者的controller定義統(tǒng)一的父接口作為標(biāo)準(zhǔn)

不推薦該方式,因?yàn)闀?huì)造成緊耦合,而且這種繼承方案對(duì)于springmvc不起作用
方式二(抽?。?將feignclient抽取為獨(dú)立模塊,并且把接口有關(guān)的pojo,默認(rèn)的feign配置都放到這個(gè)模塊中,提供給所有消費(fèi)者使用。

//如果feignclient不在SpringBootApplication掃描范圍內(nèi),這些FeignClients無(wú)法使用有兩種解決方案 //第一 指定所在包 //@EnableFeignClients(basePackageClasses = "com.estelle.feign") //方式二 指定 字節(jié)碼 //@EnableFeignClients(clients = {OrderClient.class})

區(qū)別在于 掃描包方案屬于全拿來(lái),批量搞;字節(jié)碼方案屬于精準(zhǔn)打擊(更推薦第二種方案,不用的加載進(jìn)來(lái)浪費(fèi))

統(tǒng)一網(wǎng)關(guān)Gateway服務(wù)網(wǎng)關(guān)
為什么需要網(wǎng)關(guān)
網(wǎng)關(guān)功能:
- 身份認(rèn)證和權(quán)限校驗(yàn)
- 服務(wù)路由、負(fù)載均衡
- 請(qǐng)求限流(限定流量)

springcloud網(wǎng)關(guān)的實(shí)現(xiàn)包括兩種:
- gateway(新版)
- zuul(早期版本)
zuul是基于servlet的實(shí)現(xiàn),屬于阻塞式編程。而springcloudgateway則是基于spring5中提供的webflux,屬于響應(yīng)式編程的實(shí)現(xiàn),具備更好的性能。

Gateway快速入門(mén)
搭建網(wǎng)關(guān)服務(wù)
1.創(chuàng)建model,引入gateway依賴(lài)和nacos的服務(wù)發(fā)現(xiàn)依賴(lài):
<!--nacos 服務(wù)發(fā)現(xiàn)依賴(lài) --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--網(wǎng)關(guān)依賴(lài)--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>

2.編寫(xiě)路由配置及nacos地址

spring: application: # 服務(wù)名稱(chēng) name: gateway # cloud部署 cloud: gateway: lowerCaseServiceId: true # 網(wǎng)關(guān)路由配置 routes: # 路由id,自定義,需要唯一 - id: user-service # 路由目標(biāo)地址 lb: loadbalance,后面跟服務(wù)名 uri: lb://userserver # 路由規(guī)則: 判斷請(qǐng)求是否符合路由規(guī)則的條件 predicates: # 按照路徑匹配,表示/user開(kāi)頭的請(qǐng)求都會(huì)路由到這里 - Path=/user/** - RemoteAddr= 192.168.0.103, 127.0.0.1 - id: order-service uri: lb://orderserver predicates: - Path=/order/** - RemoteAddr= 192.168.0.103, 127.0.0.1 nacos: discovery: server-addr: 127.0.0.1:8848

路由斷言工廠 Route Predicate Fattory



讀取用戶配置的斷言規(guī)則,解析成對(duì)應(yīng)的判斷條件

過(guò)濾器工廠
gatewayfilter是網(wǎng)關(guān)中提供的一種過(guò)濾器,可以對(duì)進(jìn)入網(wǎng)關(guān)的請(qǐng)求和微服務(wù)返回的響應(yīng)做處理:
請(qǐng)求頭加上信息等等,


通過(guò)名字做簡(jiǎn)單推測(cè),決定使用哪個(gè)過(guò)濾器

默認(rèn)過(guò)濾器配置方法:


全局過(guò)濾器 GlobalFilter
全局過(guò)濾器的作用也是處理一切進(jìn)入網(wǎng)關(guān)的請(qǐng)求和微服務(wù)響應(yīng),與gatewayFilter的作用一樣。
區(qū)別在于gatewayfilter通過(guò)配置定義,處理邏輯是固定的,而globalfilter的邏輯需要自己攜帶寫(xiě)代碼實(shí)現(xiàn)。
定義方式就是實(shí)現(xiàn)globalfilter接口。


過(guò)濾器的執(zhí)行順序
請(qǐng)求進(jìn)入網(wǎng)關(guān)會(huì)碰到三類(lèi)過(guò)濾器: 當(dāng)前路由的過(guò)濾器、defaultfilter、globalfilter
請(qǐng)求路由后,會(huì)將當(dāng)前路由過(guò)濾器和defaultfilter、globalfilter,合并到一個(gè)過(guò)濾器鏈(集合)中,排序后依次執(zhí)行每個(gè)過(guò)濾器

過(guò)濾器執(zhí)行順序:
- 每一個(gè)過(guò)濾器都必須指定一個(gè)int類(lèi)型的order值,order值越小,優(yōu)先級(jí)越高,執(zhí)行順序越靠前。
- globalfilter通過(guò)實(shí)現(xiàn)ordered接口或者添加@order注解來(lái)指定order值,由開(kāi)發(fā)人員自己指定
- 路由過(guò)濾器和defaultfilter的order由spring指定,默認(rèn)按照聲明順序從1遞增。
- 當(dāng)過(guò)濾器的order值一樣時(shí),會(huì)按照defaultfilter > 路由過(guò)濾器 > globalfilter的順序執(zhí)行


跨域問(wèn)題處理
跨域:域名不一致就是跨域,主要包括:
- 域名不同: www.taobao.com和www.taobao.org和www.jd.com和miaosha.jd.com
- 域名相同,端口不同: localhost:8080和localhost:8081
跨域問(wèn)題:瀏覽器禁止請(qǐng)求的發(fā)起者與服務(wù)端發(fā)生跨域ajax請(qǐng)求,請(qǐng)求被瀏覽器攔截的問(wèn)題。
解決方案: CORS
瀏覽器問(wèn)下服務(wù)器,是否允許跨域

CROS里面有一次詢問(wèn)(),是options,默認(rèn)是被攔截的。性能上有一定損耗(一定時(shí)間內(nèi)將不會(huì)再發(fā)起詢問(wèn),有效期的作用)
/** 攔截一切請(qǐng)求
