Nacos
一、下載下傳安裝
1、下載下傳
linux:https://github.com/alibaba/nacos/releases/download/2.0.4/nacos-server-2.0.4.tar.gz
執行下載下傳指令
wget https://github.com/alibaba/nacos/releases/download/2.0.4/nacos-server-2.0.4.tar.gz
解壓安裝包
tar -zxxvf nacos-server-2.0.4.tar.gz nacos/
2、linux部署
(1)建立資料庫名為nacos,執行conf目錄下的nacos-mysql.sql腳本,初始化資料庫
(2)進入到bin目錄編輯啟動腳本(startup.sh)
(3)進入conf目錄編輯application.properties
(4)在bin目錄下啟動:
./startup.sh -m standalone //standalone代表着單機模式運作,非叢集模式
(5)配置開機自啟
①添加檔案nacos.service vim /lib/systemd/system/nacos.service 并且增加如下資訊 (nacos路徑替換成自己的路徑即可)
[Unit]
Description=nacos
After=network.target
[Service]
Type=forking
ExecStart=/usr/nacos-server-1.1.3/nacos/bin/startup.sh -m standalone
ExecReload=/usr/nacos-server-1.1.3/nacos/bin/shutdown.sh
ExecStop=/usr/nacos-server-1.1.3/nacos/bin/shutdown.sh
PrivateTmp=true
[Install]
WantedBy=multi-user.target
②編輯nacos/bin目錄下的startup.sh, 修改JAVA_HOME的路徑,注釋其他三項
③執行以下指令
1. 重新加載所有service服務
systemctl daemon-reload
2. 開機啟動nacos.service
systemctl enable nacos.service
3. 檢視該service是否開機啟用
systemctl is-enabled nacos.service
4. 啟動該服務
systemctl start nacos.service
可能報錯: Job for nacos.service failed because the control process exited with error code. See "systemctl status nacos.service" and "journalctl -xe" for details.
5. 檢視該服務狀态
systemctl status nacos.service
二、nacos注冊中心
1、通路nacos:http://localhost:8848/nacos
初始賬号密碼:nacos/nacos.
2、項目在nacos的注冊
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
spring:
application:
name: sca-provider #服務注冊的服務名 ,注意服務名的橫線
cloud:
nacos:
discovery:
server-addr: localhost:8848 #向nacos控制台注冊
3、啟動該工程檢視是否注冊成功
用戶端定時(5秒)向nacos發送請求(心跳包),中斷15秒,nacos用戶端顯示不健康,30秒認為中斷死亡
三、遠端調用
1、restTemplate遠端調用
什麼是restTemplate:傳統情況下在java代碼裡通路restful服務,一般使用Apache的HttpClient。不過此種方法使用起來太過繁瑣。spring提供了一種簡單便捷的模闆類來進行操作,這就是RestTemplate。
在SpringCloud的項目中,我們使用了自動配置的OAuth2RestTemplate,RestTemplate,但是在使用這些restTemplate的時候,url必須是服務的名稱,如果要調用真實的域名或者ip的url,會有錯誤
@Bean
public RestTemplate restTemplate(){ //基于此對象實作遠端服務調用
return new RestTemplate();
}
restTemplate實作遠端調用,此方法是将該類交給spring管理
@Autowired
private RestTemplate restTemplate; // 實作遠端調用服務
restTemplate.getForObject(url, String.class);//參數一調用遠端的url,參數二為該方法傳回值類型的class對象
2、loadBalancerClient遠端調用負載均衡用戶端
LoadBalancerClient: 是 SpringCloud 提供的一種負載均衡用戶端,Ribbon 負載均衡元件内部也是內建了 LoadBalancerClient 來實作負載均衡。
@Autowired
private LoadBalancerClient loadBalancerClient; //此對象負責從nacos服務中發現和擷取服務執行個體
// /ˈbælənsə(r)/ /ˈklaɪənt/
@GetMapping("/controller/doRestEcho02")
public String doRestEcho02() {
ServiceInstance serviceInstance = loadBalancerClient.choose("sca-provider");
String url = String.format("http://%s:%s/provider/echo/%s",
serviceInstance.getHost(),
serviceInstance.getPort(), appName);
//從nacos擷取provider服務注冊資訊
System.out.println("url :" + url);
return restTemplate.getForObject(url, String.class);
}
3、loadBalancer注解簡化服務擷取過程
在restTemplate交給spring管理的方法上加上@loadBalancer,在該步驟請求發送時,底層對該請求攔截,然後底層執行choose等一系列方法,擷取host和port進行請求拼接
@Autowired
private RestTemplate loadBalancedRestTemplate;
@GetMapping("/controller/doRestEcho03")
public String oRestEcho03() {
String serviceId = "sca-provider";
String url = String.format("http://%s/provider/echo/%s", serviceId, appName);
return loadBalancedRestTemplate.getForObject(url, String.class);//在該步驟請求發送時,底層對該請求攔截,
// 然後執行方法二的choose等一系列方法,擷取host和port進行請求拼接
}
4、OpenFeign實作遠端服務調用,實作代碼結構的優化
什麼是OpenFeign
OpenFeign是一種聲明式、模闆化的HTTP用戶端(僅在Application Client中使用)(稱OpenFeign作用:聲明式服務調用)。聲明式調用是指,就像調用本地方法一樣調用遠端方法,無需感覺操作遠端http請求。學習完OpenFeign後可以不使用RestTemplate進行調用。
- OpenFeign是Spring Cloud的子項目,而Feign是Netflix公司研發的;
- Feign不支援SpringMVC的注解,另外Feign已不再維護,OpenFeign正常維護;
(1)添加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
(2)在啟動類上添加@EnableFeignClients,作用類似于@MapperScan
(3)service層建立接口
@Autowired
private RemoteProviderService remoteProviderService;
@GetMapping("/controller/doFeignEcho/{msg}")
public String doFeignEcho(@PathVariable String msg) {
return remoteProviderService.echoMassage(msg);
}
5、Ribbon負載均衡政策
- Ribbon是Netflix開源的負載均衡元件,可以用來做用戶端負載均衡,調用注冊中心的服務;
- OpenFeign與Feign都内置了Ribbon,用于實作負載均衡;
Nacos中的負載均衡底層是通過Ribbon實作,Ribbon中定義了一些負載均衡算法,然後基于這些算法從服務執行個體中擷取一個執行個體為消費方法提供服務。
随機政策 輪詢政策 重試政策 最低并發政策 可用過濾政策 響應時間權重重政策 區域權重政策
四、Nacos服務配置中心
配置中心的作用:動态管理釋出配置,無需重新開機服務配置經常變化的配置資訊,例如連接配接池,日志、線程池、限流熔斷規則等。
(1)添加服務配置依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
(2)将項目中application.yml的名字修改為bootstrap.yml(啟動優先級最高),并添加配置中心配置
cloud:
nacos:
discovery: #配置服務注冊中心位址
server-addr: 127.0.0.1:8848
config: #配置服務配置中心位址
server-addr: 127.0.0.1:8848
file-extension: yml
五、Nacos配置管理模型
1、Namespace:命名空間
Nacos中的命名空間一般用于配置隔離,這種命名空間的定義一般會按照環 境(開發,生 産等環境)進行設計和實作.我們預設建立的配置都存儲到了 public命名空間
更換命名空間:
在xml檔案config下新增namespace: (命名空間的id)
2、Group:分組
當我們在指定命名空間下,按環境或服務做好了配置以後,有時還需要基于 服務做分組配置, 例如,一個服務在不同時間節點(節假日,活動等)切換 不同的配置
更換分組:
在xml檔案config下新增group: 分組名稱
3、Service/DataId:共享配置
在xml檔案config下新增
shared-configs[0]: #該命名空間下共享配置的引用,共享配置不止一個,使用下标依次引用。
data-id: app-public.yml #該命名空間下共享配置的 Data id的值
refresh: true #支援配置中心共享配置改變,動态重新整理該共享配置。 預設fales
#group: DEFAULT_GROUP #該命名空間下分組名稱。#DEFAULT_GROUP,作為共享配置,建立時預設分組
名。
4、具體配置
六、實時nacos中的配置參數
寫一個Controller試試看,這裡代碼中需要加上 @RefreshScope 注解,注解作用就是當nacos中的配置檔案更新的時候,同步更新到代碼中!
@RestController
@RequestMapping("/TestController")
@RefreshScope
public class TestController {
@Value("${pattern.envSharedValue}")
private String myName;
@GetMapping("/test1")
public String test1() {
return myName;
}
}
Sentinel
作用:分布式系統的流量防衛兵
下載下傳網址:https://github.com/alibaba/Sentinel/releases
知識補充:限流算法
計數器、令牌桶、漏鬥算法,滑動視窗算法
Sentinel 預設的限流算法是滑動視窗算法
一、Sentinel環境搭建
(1)添加依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
(2)配置bootstrap.yml
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8180 # 指定sentinel控制台位址。
(3)找到目錄執行運作指令
java-Dserver.port=8180-Dcsp.sentinel.dashboard.server=localhost:8180-Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
idea啟動Sentinel
-Dserver.port=8180
-Dcsp.sentinel.dashboard.server=localhost:8180
-Dproject.name=sentinel-dashboard
-jar
D:\javaXM\sentinel-1.8.1\sentinel-dashboard-1.8.1.jar
二、Sentinel限流
QPS(代表每秒請求次數)單機門檻值(設定請求次數)為1,代表每秒請求不超過1次,超過做限流處理,處理方式直接調用失敗。
流控模式:
直接,關聯和鍊路
Sentinel的限流效果:快速失敗,預熱,排隊等待
鍊路模式執行個體:
/**
@SentinelResource使用此注解描述的方法,在此方法被通路時,會sentinel的簇點鍊路中顯示,此注解中指定的
名字就是資源名。此注解中的blockHandlerClass用于指定,出現限流異常時的異常處理類,blockHandler屬性
用于指定異常處理類中的方法(此方法的傳回類型,參數要與 @SentinelResource注解描述的方法參數一緻,可
以BlockException異常類型參數,而且方法必須是靜态.)fallbackClass 用于指定業務異常處理類,fallback
用于指向業務處理類中的異常處理方法(此方法的傳回類型,參數要與@SentinelResource注解描述的方法參
數一緻,可以加Throwable異常類型參數)
*/
@SentinelResource(value="doGetResource",
blockHandlerClass = ResourceBlockHandler.class,
blockHandler = "call",
fallback = "call",
fallbackClass = ResourceFallbackHandler.class)
public String doGetResource(){
return "do get resource";
}
說明:流控模式為鍊路模式時,Sentinel Web過濾器預設聚合所有URL的入口為sentinel_spring_web_context,在application.yml添加如下語句來關閉URL PATH聚合,入口名就不為預設
sentinel:
web-context-unify: false
三、Sentinel熔斷降級
作用:對調用鍊路中不穩定的資源進行熔斷降級
熔斷政策:
①慢調用比例:請求數超過3時,平均響應時間超過200毫秒的有30%,則對請求進行熔斷,熔斷時長為10秒鐘,10秒以後恢複正常。
②異常比例
③異常數
四、Sentinel 異常處理
系統提供了預設的異常處理機制,如果預設處理機制不滿足我們需求,我們可以自己進行定義
實作方式:定義方式上可以直接或間接實作BlockExceptionHandler接口,并将對象交給spring管理。
@Slf4j
@Component
public class ServiceBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
BlockException e) throws Exception {
//設定響應資料編碼
response.setCharacterEncoding("utf-8");
//告訴用戶端響應資料的類型,以及用戶端顯示内容的編碼
response.setContentType("text/html;charset=utf-8");
//向用戶端響應一個json格式的字元串
//String str="{\"status\":429,\"message\":\"通路太頻繁了\"}";
Map<String,Object> map=new HashMap<>();
map.put("status", 429);
map.put("message","通路太頻繁了");
//将map集合變為json格式的字元串
String jsonStr=new ObjectMapper().writeValueAsString(map);
PrintWriter out = response.getWriter();
out.print(jsonStr);
out.flush();
out.close();
}
}
五、Sentinel 熱點規則
作用:對經常使用的資料做配置
①寫方法
@GetMapping("/sentinel/findById")
@SentinelResource("resource")
public String doFindById(@RequestParam("id") Integer id){
return "resource id is "+id;
}
②設定限流的熱點
資源名:@SentinelResource注解的值
參數索引:@SentinelResource注解的方法參數下标,0代表第一個參數,1代表第二個參數。
單機門檻值以及統計視窗時長表示在此視窗時間超過門檻值就限流。
參數例外項:表示參數為5時門檻值為100,其它參數值門檻值為1.
六、Sentinel 系統規則
作用:監控伺服器的狀态,保證伺服器正常的運作
Sentinel的常用系統規則:
RT,QPS,CPU,線程,Load-linux,unix
七、Sentinel授權規則
作用:根據黑白名單規則,限制請求是否通過,隻有請求來源位于不在黑名單或則在白名單内時才可通過;若配置黑名單則請求來源位于黑名單時不通過。
基于參數授權規則的實作:
①定義請求解析器:
用于對請求進行解析(RequestOriginParser接口的實作類),并傳回解析結果,sentinel底層在
攔截到使用者請求以後,會對請求資料基于此對象進行解析,判定是否符合黑白名單規則
@Component
public class DefaultRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
String origin = request.getParameter("origin");//這裡的參數名會與請求中的參數名一緻
return origin;
}
}
②定義流控規則
資源名:即限流規則的作用對象
流控應用:對應的黑名單/白名單中設定的規則值,多個值用逗号隔開.
③執行資源通路
基于請求ip等方式進行黑白名單的規則設計:
①定義請求解析器:
@Component
public class DefaultRequestOriginParser implements RequestOriginParser {
//解析請求源資料
@Override
public String parseOrigin(HttpServletRequest request) {
//擷取通路請求中的ip位址,基于ip位址進行黑白名單設計(例如在流控應用欄寫ip位址)
String ip= request.getRemoteAddr();
System.out.println("ip="+ip);
return ip;
}//授權規則中的黑白名單的值,來自此方法的傳回值
}
②定義流控規則
Gateway網關
作用:一個各種服務通路的入口,在項目中簡化前端的調用邏輯,同時也簡化内部服務之間互相調用的複雜度
特點:
(1)性能強勁:是第一代網關Zuul的1.6倍。
(2)依賴Netty與WebFlux(Spring5.0),不是傳統的Servlet程式設計模型 (Spring MVC就是基于此模型實作),學習成本高。
(3)需要Spring Boot 2.0及以上的版本,才支援
一、配置流程
(1)導入依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactI
</dependency>
(2)application.yml(假如已有則無須建立)中添加相關配置,設定uri實作負載均衡
gateway: #和nacos同一級
routes: #配置網關路由規則
- id: route01 #路由id,自己指定一個唯一值即可
uri: lb://sca-provider
#uri: http://localhost:8082/ #網關幫我們轉發的url(url是uri 的子集,uri是統一資源标
識符)
predicates: #斷言(謂此):比對請求規則
- Path=/nacos/provider/echo/**
- Before=2021-01-30T00:00:00.000+08:00
- Method=GET
#請求路徑定義,此路徑對應uri中的資源,**代表傳入的參數
filters: #網關過濾器,用于對謂詞中的内容進行判斷分析以及處理
- StripPrefix=1 #轉發之前去掉path中第一層路徑
Predicate(斷言)又稱謂詞,用于條件判斷,隻有斷言結果都為真,才會真正的執行路由
二、斷言的類型
(1)基于Datetime類型的斷言工廠,此類型的斷言根據時間做判斷,主要有三個:
AfterRoutePredicateFactory:判斷請求日期是否晚于指定日 期
BeforeRoutePredicateFactory:判斷請求日期是否早于指定 日期
BetweenRoutePredicateFactory:判斷請求日期是否在指定 時間段内
例:-After=2020-12-31T23:59:59.789+08:00[Asia/Shanghai]:判斷請求日期是否晚于指定日期
(2)基于header的斷言工廠HeaderRoutePredicateFactory,判斷請求Header是否具有給定名稱且值與正規表達式比對
例:-Header=X-Request-Id, \d+
(3)基于Method請求方法的斷言工廠,MethodRoutePredicateFactory
接收一個參數,判斷請求類型是否跟指定的類型比對
例:-Method=GET
(4)基于Query請求參數的斷言工廠,QueryRoutePredicateFactory
接收兩個參數,請求param和正規表達式, 判斷請求參數是否具 有給定名稱且值與正規表達式比對.
例:-Query=pageSize,\d+
三、網關限流
(1)添加依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
(2)添加Sentinel 控制台位址
sentinel:
transport:
dashboard: localhost:8180 #Sentinel 控制台位址
eager: true #取消Sentinel控制台懶加載,即項目啟動即連接配接
(3)添加sentinel的jvm參數,通過此菜單可以讓網關服務在sentinel控制台顯示不一樣的菜單,代碼如下:-Dcsp.sentinel.app.type=1
四、特殊菜單中自定義API次元限流
作用:自定義API分組,是一種更細粒度的限流規則定義,它允許我們利用sentinel提供的API,将請求路徑進行分組,然後在組上設定限流規則
第一步:建立API分組
第二步:建立分組流控規則
第三步:定制流控網關傳回值
@Configuration
public class GatewayConfig {
public GatewayConfig(){
GatewayCallbackManager.setBlockHandler( new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(
ServerWebExchangeserverWebExchange,
Throwable throwable) {
Map<String,Object> map=new HashMap<>();
map.put("state",429);
map.put("message","two many request");
String jsonStr=JSON.toJSONString(map);
return ServerResponse.ok().body(Mono.just(jsonStr),String.class);
}
});
}
}
五、定制流控網關傳回值
1、設定攔截條件,傳回true放行,傳回false表示攔截
/*MVC中的攔截器對象*/
@Slf4j
public class TimeAccessInterceptor implements HandlerInterceptor {
/*此方法在執行目标controller方法之前執行,傳回值為true表示放行該請求*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
LocalTime now= LocalTime.now();//JDK8中的時間對象(推薦使用)
int hour=now.getHour();//擷取目前時間對應小時
//System.out.println("hour="+hour);
log.info("hour {}",hour);
/*在規定時間範圍内(6點到22點)允許通路,将請求放行*/
if(hour<=6||hour>=22)
throw new RuntimeException("請在6~10點進行通路");
return true;
}
}
被限流時定制傳回錯誤資訊
@Configuration
public class GatewayConfig {
public GatewayConfig(){
GatewayCallbackManager.setBlockHandler( new BlockRequestHandler(){
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
Map<String,Object> map=new HashMap<>();
map.put("state",429);
map.put("message","two many request");
String jsonStr=JSON.toJSONString(map);
return ServerResponse.ok().body(Mono.just(jsonStr),String.class);
}
});
}
}