Spring cloud 鏈路追蹤: sleuth、zipkin
鏈路追蹤的概念:
當我們的微服務結構逐漸龐大,微服務的數量就會大量的增加,這時,微服務之間的呼叫關係和故障定位,以及效能分析的難度都大大增加,我們迫切的需要一個集中監控和記錄這些應用之間的呼叫記錄和呼叫關係,並監控他們的時間,這樣就可以實現故障快速定位與排除,整體效能監控等工作,來保證整體微服務的可用性.
要做到這種鏈路追蹤,需要做到一些什麼呢?
一個完整的鏈路呼叫關係稱之為trace
我們應該有一個唯一的ID在整條呼叫鏈路內.traceId
每一次呼叫也會有一個ID,用來定位呼叫位置. spanId
四種事件:
CS :client send/start 客戶端/消費者發出⼀個請求,描述的是⼀個span開始
SR: server received/start 服務端/⽣產者接收請求 SR-CS屬於請求傳送的⽹絡延遲
SS: server send/finish 服務端/⽣產者傳送應答 SS-SR屬於服務端消耗時間
CR:client received/finished 客戶端/消費者接收應答 CR-SS表示回覆需要的時間(響應的⽹絡延遲)
鏈路追蹤的應用:
微服務:
新增spring-cloud-starter-sleuth依賴
配置檔案新增日誌配置
logging:
level:
org.springframework.web.servlet.DispatcherServlet: debug
org.springframework.cloud.sleuth: debug
在日誌中即可看到鏈路追蹤的原始資訊
鏈路追蹤的監控zipkin 應用:
zipkin的server微服務:
新增依賴:
zipkin-server(與spring的log4j2衝突,需要exclusion掉spring-boot-starter-log4j2的依賴)
zipkin-autoconfigure-ui(zipkin UI介面)
配置檔案配置:
management:
metrics:
web:
server:
auto-time-requests: false # 關閉⾃動檢測請求
其他微服務(zipkin的客戶端):
配置檔案配置:
zipkin:
base-url: http://127.0.0.1:9411 # zipkin server的請求地址
sender:
# web 客戶端將蹤跡⽇志資料通過⽹絡請求的⽅式傳送到服務端,另外還有配置
# kafka/rabbit 客戶端將蹤跡⽇志資料傳遞到mq進⾏中轉
type: web
sleuth:
sampler:
# 取樣率 1 代表100%全部採集 ,預設0.1 代表10% 的請求蹤跡資料會被採集
# ⽣產環境下,請求量⾮常⼤,沒有必要所有請求的蹤跡資料都採集分析,對於⽹絡包括server端壓⼒都是⽐較⼤的,可以配置取樣率採集⼀定⽐例的請求的蹤跡資料進⾏分析即可
probability: 1
ip:port 啟動zipkin的微服務,在設定了zipkin的客戶端呼叫後,zipkin的監控即可檢視該呼叫鏈路
鏈路追蹤的監控zipkin的監控記錄持久化到資料庫 應用:
新增依賴:
zipkin-autoconfigure-storage-mysql
mysql依賴
druid依賴
spring-jdbc依賴
配置檔案配置資料來源
Spring cloud Oauth2 認證服務:
Oauth2的概念:
每個微服務都會有相應的驗證來過濾請求是否合法,當微服務的數量增多,那麼每個微服務都需要單獨驗證 這勢必會影響使用者體驗,如何設定一次認證 全域性通用?這就是Oauth2統一認證服務的作用.
Oauth2的流程:
使用者想要發起請求,需要先向認證伺服器獲取token,該token需要在請求每個微服務時攜帶,攜帶著token去訪問的微服務在認證伺服器中稱之為資源伺服器,資源伺服器收到請求後,將token傳送給認證伺服器進行驗證,驗證合格後再處理正常的請求,否則退回該請求,返回token驗證失敗,token也不是一直有效的,我們可以設定token的有效期來控制一次登入的有效時間,申請token時,認證伺服器會同時生成一個比token有效時間更長的refreshToken,當token失效後,可以使用refreshToken向認證伺服器請求重新整理token,當refreshToken也失效了後,本次token請求徹底失效,需要重新請求token
Oauth2的經典應用場景:
三方應用申請使用我方的一些訪問請求,三方應用可向我方申請token,持有該token後即可向我方傳送請求.
Oauth2的token頒發方式:
1:授權碼 authorization-code
2:密碼 password
3:隱藏式 inmlicit
4:客戶端憑證 client credentials
*常用為密碼式
應用:
認證伺服器:
引入依賴
設定配置類,新增Oauth2的開關注解
實現三個configer方法:
安全設定configure 設定訪問許可權
允許form提交
允許訪問該token認證介面 /oauth/token_key permitAll()
驗證令牌 /oauth/token_check permitAll()
客戶端詳細配置configure ClientDetailServiceConfigure.class
初始化到記憶體或者資料庫.記憶體就是inMemory()
設定client id和secret.
設定resourceIds.
設定oauth token頒發方式.
設定scopes.
token配置的configure:
設定tokenStore(token的儲存方式)
new一個該Store物件
設定tokenServices() token的有效期等資訊
new一個該service物件 然後如下設定
設定是否重新整理令牌
設定token有效期
設定token重新整理令牌的有效時間
設定使用者名稱密碼校驗配置類
建立認證管理器的bean
實現父類configure方法 AuthenticationManagerBuider
例項化使用者物件
獲取token的endpoint:
ip:port/oauth/token?client_id=?&client_secret=?&username=?&password=?&grant_type=?
client_id:客戶端ID
client_secret:客戶端金鑰
username:使用者名稱
password:密碼
grant_type:token頒發方式
驗證token:
ip:port/oauth/check_token?token=?(注意Oauth2的2.3.7版本開始check_token不能使用GET請求,強制POST)
資源伺服器:
繼承ResourceServerConfigurerAdapter類
實現configure(ResourceServerSecurityConfigurer resources)方法,與認證伺服器互動的config
RemoteTokenServices 遠端認證服務例項,通過該例項設定一系列認證:
setCheckTokenEndpointUrl() 設定認證伺服器URL
setClientId() 設定客戶端ID
setClientSecret() 設定安全碼
tokenServices()裝載遠端服務
實現configure(HttpSecurity http)方法,設定哪些請求URL字首需要認證.
antMatchers().authenticated()新增需要驗證的字首
Oauth2 + jwt的統一認證:
jwt為java web token,既token的內容不再簡單是一個字串,而是將所需要的請求引數等資訊都封裝到token中,通過資源伺服器和認證伺服器協商統一的加密演算法進行加密,從中得到的一個token,而這個token不需要像傳統Oauth2一樣每次執行認證的請求都要去認證伺服器進行校驗,而在資源伺服器通過一協商統一的演算法即可進行校驗,極大減輕了認證伺服器的壓力.
jwt的結構:
Header演算法設定
payload負載區(放置請求引數).
signature加密區(根據統一加密演算法對前兩個區進行整體加密.)
jwt的應用:
驗證伺服器端:
token詳情configure(AuthorizationServerEndpointsConfigurer endpoints)中的tokenStore方法生成的tokenStore進行修改,從Memory改成JWTtoken生成.
Jwt的令牌轉換器生成需要設定簽名金鑰和驗證金鑰資訊,要設定一個金鑰(用MD5專門生成一個也可以,自己寫也行).
JwtAccessTokenConverter令牌轉換器
setSigningKey()設定簽名金鑰
setVerifier()設定驗證金鑰 MacSigner對稱加密 RSA非對稱加密
AuthorizationServerTokenServices的生成方法中新增令牌增強方法:
setTokenEnhancer() 設定令牌增強,將jwt令牌轉換器傳入實現增強
資源伺服器端:
不需要與認證伺服器進行遠端認證,本地即可認證.
TokenStore的生成方式改為JwtToken
configure(ResourceServerSecurityConfigurer resources)方法中不需要設定遠端認證了,只要:
resourceId() 設定資源ID
tokenStore()設定token管理
stateless()設定為無狀態
Oauth2的資料庫持久化:
建立表oauth_clients_details,欄位在JdbcClientDetailsService中提供規範.
建立users表的持久層.
編寫UserDetailsService介面實現類,實現資料庫載入使用者資訊.
實現loadUserByUsername()方法
WebSecurityConfigurerAdapter實現類中的configure(AuthenticationManagerBuilder auth)進行改造,不需要再自己生成一個userDetails物件而是通過上面的實現類進行獲取
userDetailsService(實現類物件)
passwordEncoder()這個還是要的 設定密碼編碼
Oauth2+JWTtoken 擴充套件:
在oauth2+jwt中的payload裡新增自定義資訊
應用:
認證伺服器端:
重寫DefaultAccessTokenConverter類的convertAccessToken()方法
super.convertAccessToken 拿到父類裝載好的map
用spring mvc上下文物件RequestContextHolder 獲取request物件獲得請求的一些資訊
裝入父類裝在的map中
返回
資源伺服器端:
重寫DefaultAccessTokenConverter類的extractAuthentication()方法
super.extractAuthentication獲取到認證物件
setDetails()將map傳入進去,提供給SecruityContextHolder上下文物件獲取Details
返回
Controller就可以通過SecruityContextHolder.getContext().getAuthentication().getDetails().getDecodedDetails來獲取到我們放進去的map.
Jwt的擴充開發
jwt可以單獨使用,自己開發一個生成和校驗的程式碼,需要自己擴充一下(這個很重要)
Spring Cloud 二代 SCA 阿里巴巴的元件
市場主流還是SCN,SCA還沒有被廣泛流行.2018年阿里的SCA注入spring cloud孵化器
元件結構:
Nacos:服務註冊中心、配置中心
Sentinel哨兵:熔斷器、限流
dubbo:rpc遠端呼叫
Seata:分散式事物
Nacos:
服務發現、配置管理和服務管理平臺
特點:
動態的配置服務功能 config bus
服務的註冊發現與管理,健康檢查 eureka
動態DNS服務 可使用域名
服務和後設資料管理,nacos有管理平臺,可以檢視註冊的服務資訊,管理權重,優雅下線
Nacos的服務端:
一些概念:
分組:屬於nacos資料模型的一個概念,用於配置中心的場景.
保護閾值:0-1浮點,健康例項數佔總服務例項的比例,
當有100個例項,但只剩兩個健康的例項,如果不做任何操作,那麼消費者會把所有的請求都壓在這兩個健康的例項,那麼流量洪峰來到,這兩個例項也會很快崩潰變為不健康.這就造成這個服務徹底不可用而導致雪崩效應,這個閾值的設定就是為了避免雪崩,當不健康的數佔的比例超過這個閾值,nacos就會保護系統可用,將所有例項開放給消費者,保證整體的可用性.
服務路由型別:做多資料中心的就近訪問
例項的臨時和持久化,臨時例項需要客戶端向nacos傳送心跳錶明自己活著,而持久化的例項,nacos還會反向的去健康檢查來檢視客戶端的健康程度.如mysql不會傳送心跳,就需要nacos主動去檢查
動態上下線:下線不代表例項關閉,只是消費者無法使用.
權重:權重越大,流量越大,設定為0就等同於下線了
叢集配置:服務-叢集-例項
如同tomcat,不用自己搭建,去github下載壓縮包即可
conf下:
application.properties 配置nacos
log日誌檔案
sql需要持久化的sql語句
linux下啟動命令 ./startup.sh -m standalone(單例模式)
介面訪問:localhost:8848/login
微服務端(客戶端)應用:
父工程需要引入spring-cloud-alibaba依賴
引入spring-cloud-starter-alibaba-nacos-discovery去掉eureka的依賴
配置檔案可以去掉eureka的配置了
cloud:
nacos:
discovery:
server-addr:
@EnableDiscovery通用註解 支援nacos 不用修改
Nacos的資料模型:
namespace、group、叢集 都是為了對服務、配置檔案的歸類管理. 如隔離:不同namespace的服務不能相互訪問,同一namespace不同group也可以設定不能互相訪問
如同maven的gav座標,maven鎖定jar包,nacos鎖定服務.
namespace+group+service 定位服務
namespace+group+dataId 定位配置檔案
nameSpace可以針對開發環境設定,group可針對開發部門設定,Service就是具體的服務了
nacos的層級結構:
服務下設N個叢集,叢集下設N個例項,可以通過這種層級關係來設定不同的隔離級別.進行同一個服務的不同環境隔離區分. 比如叢集可按地區分配.同一服務不同地區部署,設定不同的地區叢集.達到不同的效果,可實現就近訪問.可按伺服器規模分配等
名稱空間(不同之間不可訪問)->服務(不同不可訪問)->分組->叢集(不同之間可訪問)->例項
Nacos持久化:
配置nacos配置檔案中的屬性:
spring.datasource.platfor
db.num
db.url
db.user
db.password
Nacos叢集搭建:
leader模式,需要最少三個例項才能成為叢集
應用:
配置檔案:
nacos.inteutils.ip-address 設定叢集本機的IP
conf配置檔案:
設定叢集中其他例項的IP
啟動模式 -m cluster(叢集模式)
客戶端應用:
跟eureka一樣,把服務端的ip "," 隔開
Nacos 配置中心
之前是把配置檔案扔在git上,nacos就不需要了 是配置在nacos server中, bus也不用了 nacos直接支援動態重新整理
應用:
服務端:(都在web頁面中配置)
利用名稱空間的特點,設定三個nameSpace對應三個應用環境
在名稱空間下新建配置:
dataId:配置檔名稱
group:專案分組或者部門分組(預設也行)
配置內容可多種檔案yaml
描述等
微服務端:
引入spring-cloud-starter-alibaba-nacos-config依賴
配置檔案:
cloud:
nacos:
config:
server-addr:
namespace:設定的是ID 不是名字
group: 預設可不寫
dataId:
預設分成了三個段,由${spring.application.name} - ${spring-profile-active} . ${file-extension} 組成的,如果不想使用預設,那麼:
第一段設定是spring.cloud.nacos.config.prefix設定,預設${spring.application.name}
第二段如果沒有是不會拼的,包括前面那個"-",
第三段設定是spring.cloud.nacos.config.file-extension,預設是properties
註解還是@RefreshScope
整體比spring-config + bus方便好用
可否從nacos獲取多個dataId的配置資訊?是可以的!
配置檔案:
cloud:
nacos:
config:
ext-config[index]:
dataId:
group:
refresh:設定了才會動態重新整理
nacos配置優先順序問題:
主要配置是最高的,擴充套件配置其次,擴充套件配置之間的優先順序看ext-config後的index index越大,優先順序越高,也符合了spring的配置檔案約定,後覆蓋前的.
SCA Sentinel哨兵 分散式系統流量防衛:
負責流量控制、熔斷降級元件 替代Hystrix的,針對問題,服務雪崩、服務降級、熔斷、限流
Hystrix其實是入侵式元件...因為需要在程式碼中進行配置.入侵了我們的程式碼.
如果是Sentinel的話就不需要了,它已經整合了dsahboard turbine,也不用寫程式碼進行配置,而是通過控制檯配置,其實Sentinel已經把環境設定好了,不需要我們去新增,我們需要的只是把規則屬性傳送給微服務端,Sentinel所在的微服務就會載入並開始執行.
Sentinel結構:
核心庫:不依賴任何庫,執行所有java環境 對dubbo和spring cloud支援很好
控制檯:監控、規則傳送
Sentinel特性:
實戰經驗豐富.阿里巴巴雙十一全是它扛
完善的監控 監控實時全面
廣泛的開源生態 不依賴任何jar包
完善的SPI擴充套件 可以自行通過SPI進行擴充套件
Sentinel的應用:
dashboard監控應用直接下載一個jar進行執行即可(就是一個spring boot程式)
微服務端:
引入依賴
Spring-cloud-starter-alibaba-sentinel
配置檔案:
cloud:
sentinel:
transport:
dashboard: dashboard的地址
port:8719 被佔用了就加1 加到能用為止 dashboard向微服務端傳送規則和限流的埠
Sentinel的概念:
資源:任何能發起請求的服務、程式碼、應用程式 都可稱之為資源
規則:圍繞資源,我們可以根據情況來指定一系列的規則.流量控制、熔斷降級、系統保護,可以動態調整.
Sentinel流量控制:
根據併發效能設定一些限流控制,如QPS(每秒可請求數) 只能為1 那麼我們可以限制只能為1,多出的那些部分直接拒絕
UI模組:
資源名:被訪問的url
來源:可針對哪些來源進性限制
閾值型別:QPS和執行緒數 QPS每秒請求 執行緒數:請求的執行緒數
閾值:具體限制的數量
流控模式:直接(不考慮其他)、關聯(關聯的資源達到設定的閾值限制本資源.支付、下單、庫存方面需要保證一致性的地方,可以用關聯限流)、鏈路(根據呼叫鏈路進行限流,從鏈路的某一個位置做為入口進行關聯,然後該條鏈路入口資源達到閾值後,就限制本資源.適用於複雜的呼叫鏈路下,保證其他鏈路能夠正常訪問本資源.)
流控效果:快速失敗(直接返回失敗)、warm up(預熱模式,開始階段為設定閾值/3,當預熱時間過後(自己設定),恢復到正常設定閾值)、排隊等待(當請求量超出閾值,超出的部分進入等待模式,等待時間超過設定的超時時間了,就拒絕,請求是勻速處理的,所以當佇列達到一定數量後,超出這個數量的請求就會失敗,具體佇列等待時間是這麼計算,QPS計算:1s/閾值 = 每個請求處理時間, 超時時間/請求處理時間 就是最大有效佇列的數量)
Sentinel降級規則:
資源出現不穩定情況:超時、異常增多,我們需要針對這個資源進行直接失敗,來保證上游正常.
UI模組:(*為邏輯說明)
資源名:
*降級策略觸發點:QPS>=5時
*熔斷策略:在指定的時間視窗內,將熔斷請求,過了視窗時間,就恢復請求,不像Hystrix那樣放一個請求去測試是否正常來恢復,而是直接恢復
降級策略:RT(RT會計算平均響應時間,如果時間超過閾值,)、異常比例(異常的數量佔總請求的百分比(0-1浮點),就熔斷)、異常數(分鐘內異常達到一定數量,就熔斷,注意:不要求QPS>=5,時間視窗不能小於60s)
Sentinel dashboard其他功能:
熱點規則:
根據熱點引數索引來進行限流(有限制)
系統規則:
根據系統引數進行閾值的流控.如CPU使用率.總QPS.匯流排程數.總的平均響應時間RT,都是針對於單個伺服器來講
授權規則:
針對具體資源進行具體的許可權控制.
叢集流控:
對整體叢集環境進行控制(需要改造開源控制檯,阿里的套路.)
機器列表:
當前與Sentinel互動的機器列表
Sentinel自定義兜底方法:
新增註解@SentinelResource(value = "資源方法名稱" blockHandler=兜底方法名,blockHandlerClass = 兜底方法提取類)
兜底的方法與Hystrix要求一樣 但兜底方法的引數需要多一個BlockException block用來接收異常來執行這個兜底方法
提取到類時 兜底方法需要是靜態的
他不會兜底我們java的異常 需要在註解設定fallbackClass 來指定java兜底類或者fallback 設定兜底方法 來兜底java的異常
Nacos+Sentinel規則持久化:
規則資料是dashboard傳送給微服務儲存的,當微服務關閉,那麼這些規則也跟著丟失,當我們將規則資料儲存到nacos的話,下線再上線就不會丟失
應用:
微服務端:
引入依賴sentinel-datasource-nacos
配置檔案:
cloud:
sentinel:
datasouce:
規則資料名稱自定義:
server-addr:
data-id:扔給一個配置檔案裡
groupId:分組 沒有寫DEFAULT_GROUP
data-type: json
rule-type: flow來自於RuleType類的型別(記不住可以參照去設定)
nacos服務端:
建立相應的配置檔案:(限流) FlowRule類原始碼可檢視
limitApp:來源應用
grade:閾值型別 0執行緒數 1QPS
count: 閾值
strategy: 流控方式 0直接 1關聯 2鏈路
controlBeahvior:流控效果 0快速失敗1預熱2等待
clusterMode:叢集模式
(降級) DegradeRule類原始碼可檢視
resource:資源
grade:降級策略 0RT、1異常比例、2異常數
count:閾值
timewindow:時間視窗
只能通過nacos設定 不能通過Sentinel修改,否則無法同步到nacos
Nacos+Sentinel+dubbo:
排除掉openFeign和ribbon
依賴包除了dubbo還有sentinel-apache-dubbo-adpter介面卡依賴
配置檔案:
dubbo的配置
scan:
base-packages:
protocol:
name: dubbo
port: -1 自增 從20880開始
registry: 掛載到springcloud的註冊中心 spring cloud用哪個 dubbo就用什麼
address: 用上面spring-cloud://localhost
整合特殊配置:
spring:
main:
#spring boot 2.1需要設定
allow-bean-definition-overriding:true
消費者配置:
引入依賴
配置檔案:
dubbo:
registry:
address: 用spring-cloud的配置中心
cloud:
subscribed-services: 提供的application-name 多個,隔開
整合特殊配置:
spring:
main:
#spring boot 2.1需要設定
allow-bean-definition-overriding:true