SpringCloude快速入門

近期簡單了解一下SpringCloude微服務,本文主要就是我學習中所記錄的筆記,然后具體原理可能等以后再來深究,本文可能有些地方用詞不專業還望包容一下,感興趣可以參考官方文檔來深入學習一下微服務,然后我的下一步學習就是docker和linux了。

nacos:?Nacos 快速開始 | Nacos 官網

sentinel:?home | Sentinel

seata:?Seata Java Download | Apache Seata


單體架構

域名主要是綁定IP方便記名字,然后節點就是服務器的專業說法,當然一臺服務器也可以同時部署數據庫和應用(好處就是部署簡單)

一臺服務器性能有限,比如請求數量過多就不夠了

集群架構(大量公司常用)

多個服務干同一件事就是集群,干不同事就是分布式

對服務器(節點)做的復制品即為副本,而這些服務器構成的一個整體就叫做集群

域名不能單獨指向任何一個副本(否則和單體架構沒區別)必須通過網關(一般也需要部署在一個服務器上邊,比如Nginx),所以域名必須綁定網關的公網IP(網關需要完成功能:請求的路由,而且里邊我記得conf配置文件可以配置訪問的IP來實現負載均衡),數據庫也可能產生瓶頸,所以依然可以多復制幾個節點構成數據庫集群。然后比如雙十一流量大就可以擴容幾個副本,然后等流量過去在釋放服務器來釋放資源。

缺點: 1.維護和模塊化升級比較麻煩,牽一發而動全身,每次都要重新打包部署 2.如果涉及到多個語言交互就不能簡單打jar包部署服務器了

分布式架構

每個應用/數據庫可以按照業務功能模塊拆成一個個小應用(微服務)還實現了數據隔離,比如訂單找商品要,而不是直接連上商品的數據庫

當然為了增加并發量,仍然可以使用副本思想,比如商品肯定使用的最多,那么每臺服務器都部署一份,其余也可以看情況選擇部署幾份

注意:

1.一個服務器不能全部部署多個商品副本(微服務),因為如果這個服務器宕機其他服務器也不能正常工作了,即單點故障

2.如果需要訪問的業務在別的服務器,那么就需要遠程調用(類似HttpClient吧)獲取返回的json數據即可(這是最常用的一種RPC方式)。

3.注冊中心組件包含服務中心服務注冊功能: 通過注冊中心可以知道微服務在哪個服務器存在,并且調用時也可以從注冊中心知道業務在哪里(服務發現),而且這時候還可以用到網關(使用負載均衡,比如一種模式是按順序先后訪問,還有按權重等)。

4.每個微服務都可以保存在配置中心來統一管理。

5.高并發情況下,如果一個微服務卡頓導致整個調用鏈卡頓(有很多個請求,就執行了很多調用鏈),然后可能導致資源耗盡,即服務器雪崩。所以需要服務熔斷(可以設置規則,比如幾秒內有多少占比卡頓,那么以后的請求即快速釋放掉,防止占用資源)。


總結: 分布式就是一個大型應用被拆分成很多小應用分布部署在各個機器。一種架構(工作)方式

集群: 只是一種物理形態,只要部署在多個機器上就可以稱為集群。

網關: 這里的請求路由就可以配置規則,比如以order開頭就要轉給訂單所在的服務器(這時候需要問注冊中心)

分布式事務: 比如下完訂單和給用戶加積分倆個是一個整體,如果是單架構,則@Transactional基本可以解決,現在因為每個數據庫可能在不同服務器,所以就不能像以前那樣。

上述的各種方法即可解決各種問題。

Nacos

1.服務注冊

1.<packaging>pom</packaging>寫上就可以管理其他子項目,并且自身不用寫代碼了,一般最外層管理版本,再來一層來寫公共依賴,里邊再重新寫多個模塊即可。

所有服務創建后都應該經過注冊中心來注冊服務

在bin目錄下 startup.cmd -m standalone 以單機模式啟動(集群以后再了解吧)

然后輸入: localhost:8848/nacos 即可成功訪問

由于每個微服務都繼承了父類的springboot依賴,所以每個微服務也是springboot應用,然后也是定義application類,讓springboot應用跑起來。配置的yml文件也寫好基本就能成功了

<!--這里父項目指定了版本,所以不用寫version,而且所管理的子項目也會一起引入依賴-->
<!--一般是外層的pom來引入方便統一管理,并且都需要這個依賴-->
<!--服務發現-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--遠程調用-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

可以配置端口號,防止占用 --server.port=8084

2.服務發現

第一步就是查看已經注冊的微服務

@SpringBootTest
public class DiscoveryTest {@AutowiredDiscoveryClient discoveryClient;@AutowiredNacosServiceDiscovery nacosServiceDiscovery;
?@Testvoid discoveryClientTest(){for (String service : discoveryClient.getServices()) {System.out.println(service);// 獲取每個服務名下的相應的ip+端口discoveryClient.getInstances(service).forEach(instance -> {System.out.println("ip: " + instance.getHost() + " port: " + instance.getPort());});}}
}

3.遠程調用(編碼式)

實體類: 除了可以pojo,也可以寫成bean

localhost:8081/order/create?userId=1&productId=6

 ?  /*** 目前url其實也寫死了,所有后續負載均衡要改進一下* @param productId* @return*/private Product getProductFromRemote(Long productId) {// 1. 獲取到商品服務所在的所有機器ip+port// 目前我門已經知道serviceId了,所以為了方便演示就不獲取了List<ServiceInstance> instances = discoveryClient.getInstances("service-product");ServiceInstance serviceInstance = instances.get(0); // 隨便用一個// 后邊的即是定義的controller層地址String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/product/" + productId;log.info("遠程地址為: {}", url);// 2. 開始發送請求Product product = restTemplate.getForObject(url, Product.class);return product;}

負載均衡

<!--訂單要對訪問的商品做負載均衡-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
哪個業務需要就引入

默認是輪詢,如果想要制定其他規則,需要手寫。

方式一: 底層原理
private Product getProductFromRemoteWithLoadBalancer(Long productId) {// 1. 獲取到商品服務所在的所有機器ip+port// 目前我門已經知道serviceId了,所以為了方便演示就不獲取了ServiceInstance choose = loadBalancerClient.choose("service-product");// 后邊的即是定義的controller層地址String url = "http://" + choose.getHost() + ":" + choose.getPort() + "/product/" + productId;log.info("遠程地址為: {}", url);// 2. 開始發送請求Product product = restTemplate.getForObject(url, Product.class);return product;
}

方式二: @LoadBalanced注解

在需要進行負載均衡訪問的配置類加上該注解就可以自動調用方法了

@Configuration
public class OrderConfig {
?/*** 線程安全,這樣直接引入bean對象,這個方法就會自動調用哦* @return*/@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}
private Product getProductFromRemoteWithLoadBalancerAnnotation(Long productId) {// service-product會被動態替換成相應的ip和端口號String url = "http://service-product/product/" + productId;log.info("遠程地址為: {}", url);// 2. 開始發送請求Product product = restTemplate.getForObject(url, Product.class);return product;
}

面試考點

總結就是如果第一次調用時,會先向注冊中心拿到ip和port并存儲到緩存中,之后如果注冊中心沒有更新,則會直接向緩存中拿ip和port,這樣不僅提高了效率,還保證了注冊中心宕機也會使用(當然前提你的ip和port都是能夠正常訪問的而且第一次不成功沒有存緩存,所以就失敗了)

4.配置中心

修改配置時只需在配置中心修改,這樣就能實時推送,并且不需要停機重新打包

配置中心基本使用:

yml格式的話,信息配置都要正確,也可以使用Properties。這里導入的nacos不寫地址就是默認的

方式一: @Value+@RefreshScope 獲取綁定值

@value就是獲取yml中自定義綁定的屬性值

@RefreshScope可以激活配置屬性的自動刷新功能,不用重啟就能拿到配置集的信息。

方式二: @ConfigurationProperties

專門抽取一個類來獲取綁定的屬性值,可以實現無感自動刷新。

方式三 編碼監聽配置變化

面試考點

后導入優先,外部優先。

1.如果配置中心和本身項目中定義的yml里的數據重復了,優先使用配置中心。

2.如果import: nacos:service-product.yml, classpath:application.yml,則后邊的會覆蓋前面的

5.數據隔離

nacos: Namespace(命名空間: 區分多種環境)=>Group(分組: 區分多套微服務)=>Data-id(數據集: 區分多種配置)

而在springboot中可以讓開發、測試、生成環境都綁定一套名稱空間,項目啟動時任意激活一個環境就可以按需加載使用。

注意其實命名都行,不過盡量規范就行,而且這個其實也不是真實的微服務名稱,只不過方便統一管理

小結

6.OpenFeign

遠程調用(聲明式)(重點)

補充小知識
@FeignClient("service-product") 可以指定微服務,如果微服務不存在的話
@FeignClient(value = "test-client", url = "http://xxx.com" ) 我們指定的url是協議加域名,后面的請求路徑則mvc注解來寫
這里:前面的即為協議-http,而后邊第一個/前面的即為域名xxx.com或者localhost:8080,最后的一部分即為請求路徑(比如@GetMapping(/ order)里邊指定的內容),而請求路徑后面也可能帶上參數來相互傳遞

小技巧

1.調用業務api: 如果是我們自己寫得客戶端想要用openfeign在一個業務調用其他業務的方法,可以直接將該controller層該方法和mvc注解復制一下即可,這時只要傳遞的參數正確一般都能正常訪問。

2.調用第三方api: 這時就需要參照第三方接口文檔來定義。

3.客戶端負載均衡: openFeign其實已經利用負載均衡算法選了一個地址調用。我們可以自己調整來解決高并發。

4.服務端負載均衡: 第三方一般只暴露了一個固定的地址,所以其內部自行進行負載均衡,我們就無需考慮。

進階配置

日志

首先需要配置一下yml:

超時控制

我們即使不設置,連接超時默認10s,讀取超時默認60s。

在yml中配置一下即可。

重試機制

如果遠程調用超時失敗后,還可以多次嘗試,仍然失敗則返回錯誤。

如上圖所示的默認配置: 初始定位100mm,那么每次失敗后的間隔時間就會100依次乘1.5,最大間隔定義為1s,然后嘗試次數為5次。

方式一: yml中配置

方式二: 手動配置

@Configuration // 表示可以有多個Bean
public class OrderConfig {
?/*** 線程安全,這樣直接引入bean對象,這個方法就會自動調用哦* @return*/@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
?/*** 配置事務,yml中也可以配置* @return*/@BeanLogger.Level feignLoggerLevel(){return Logger.Level.FULL; // 固定寫法,注意包導入feign下的}
?@BeanRetryer retryer(){return new Retryer.Default(10, 1000, 4);}
}

攔截器

@Component加上就可以全局攔截自動生效,如果想要局部攔截可以不加,直接在yml中配置。

包括請求攔截器(常用)和響應攔截器(用的較少)

@Component
public class XTokenInterceptor implements RequestInterceptor {/*** 注意這個繼承的是feign里邊的攔截器方法* @param requestTemplate (詳細信息封裝在了這個模板中)*/@Overridepublic void apply(RequestTemplate requestTemplate) {System.out.println("攔截器啟動");requestTemplate.header("X-token", UUID.randomUUID().toString());}
}

Fallback兜底

注意此時必須用到sentinel才可以

/*** 也是實現了自己寫得接口,只有失敗才會觸發* @FeignClient(value = "service-product", fallback = ProductFeignClientFallback.class)* 實現接口內的上述注解也不能少* 也要放在容器中*/
@Component
public class ProductFeignClientFallback implements ProductFeignClient {@Overridepublic Product getByProductId(Long productId) {System.out.println("兜底回調...");Product product = new Product();product.setId(productId);product.setPrice(new BigDecimal("999"));product.setProductName("隱藏商品");product.setNum(0);
?return product;}
}

7.Sentinel(可保護資源)

定義的規則可以存到Nacos、Zookeeper等配置中心來持久化使用

服務保護(限流||熔斷降級)

一般三步:1.定義資源 2.定義資源的保護規則 3.如何處理違反規則的異常

首先需要下載sentinel-dashboard-1.8.8.jar包然后cmd java - jar啟動即可(如果想修改端口也可以寫),然后默認用戶名和密碼都是sentinel

然后我們的項目微服務需要配置連接上sentinel控制臺即可,然后每個微服務都需要保護,所以依賴寫在最外邊。

/*** controller中是默認都為資源* 然后這個業務層我們也可以手動設置資源名讓它也被保護起來*/
@SentinelResource("createOrder")
@Override
public Order createOrder(Long productId, Long userId) {...}

當然在控制臺指定規則后所顯示的默認錯誤頁面不是json數據,傳遞給前端不友好,所以我們可以自定義異常處理器來解決

異常處理

如果不需要返回兜底數據,那么我們直接全局異常處理器即可顯示,而下方的各種異常如果使用了都可以覆蓋這個最外層的處理

/*** 是下邊這倆個異常的結合* @ControllerAdvice* @ResponseBody*/
@RestControllerAdvice
public class GlobalExceptionHandler {
?@ExceptionHandler(Exception.class) // 捕捉所有異常public R handleException(Exception e) {return R.error("全局異常處理");}
}

處理Web接口

注意: 此異常處理器只能處理默認的資源(比如controller下的各種mvc請求),而@SentinelResource自定義的資源不會處理,因為倆者底層不太一樣。

在exception包下新建一個處理類即可,不過注意由于sentinel在內存中,所以每次重啟項目都需要重新配置規則

@Component // 也是放進容器中即可
public class MyBlockExceptionHandler implements BlockExceptionHandler {private ObjectMapper objectMapper = new ObjectMapper();/*** resourceName就是我們控制臺定義的資源名稱*/@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response,String resourceName, BlockException e) throws Exception {response.setContentType("application/json;charset=utf-8"); // 設置編碼格式,最開始就設置PrintWriter writer = response.getWriter();R error = R.error(resourceName + "被Sentinel限流了,請稍后再試,原因: " + e.getMessage()+ "  錯誤類: " + e.getClass());String json = objectMapper.writeValueAsString(error); // 可以用jackson來轉換成json字符串// 阿里的fastjson也行,不過jackson框架中常使用writer.write(json);writer.flush();writer.close();}
}

處理@SentinelResource(一般標注在非controller層)
 ?  /*** controller中是默認都為資源* 然后這個業務層我們也可以手動設置資源名讓它也被保護起來* blockHandler = "createOrderFallback"注意需要指定一下就會調用我們寫得兜底回調* 一般用這個blockHandler就行*/@SentinelResource(value = "createOrder", blockHandler = "createOrderFallback")@Overridepublic Order createOrder(Long productId, Long userId) {// 獲取商品
// ? ? ?  Product product = getProductFromRemoteWithLoadBalancerAnnotation(productId);Product product = productFeignClient.getByProductId(productId);Order order = new Order();order.setId(1L);// 獲取總金額// 因為類型不同,所以轉換一下BigDecimal sum = product.getPrice().multiply(new BigDecimal(product.getNum()));order.setTotalAmount(sum);order.setUserId(userId);order.setNickName("清然");order.setAddress("萬達超市");// 遠程查詢商品列表,也是轉換一下order.setProductList(Arrays.asList(product));
?return order;}
?/*** 參數寫法基本和我們的業務保持一致,然后加上BlockException可以了解出現了什么異常* 區分一下這是保護方法的兜底回調,以前的是OpenFeign超時配置的兜底回調*/public Order createOrderFallback(Long productId, Long userId, BlockException e){Order order = new Order();order.setId(0L);order.setTotalAmount(new BigDecimal("0"));order.setUserId(userId);order.setNickName("雅小姐");order.setAddress("異常位置: " + e.getClass());
?return order;}

處理OpenFeign

這個我們之前寫過,所以也會自動生效的

/*** 訂單中專門用Feign來調用商品微服務*/
@FeignClient(value = "service-product", fallback = ProductFeignClientFallback.class) // 訂單客戶端專門用來調用商品服務
public interface ProductFeignClient {
?// mvc注解此時標注在Feign上,所以是發送請求@GetMapping("/product/{id}") // 這個是路徑,不包含httpProduct getByProductId(@PathVariable("id") Long productId);// 如果用String則單純返回json字符串,而用Product則會自動封裝成該對象
}
/*** 也是實現了自己寫得接口,只有失敗才會觸發* @FeignClient(value = "service-product", fallback = ProductFeignClientFallback.class)* 實現接口內的上述注解也不能少* 也要放在容器中*/
@Component
public class ProductFeignClientFallback implements ProductFeignClient {@Overridepublic Product getByProductId(Long productId) {System.out.println("兜底回調...");Product product = new Product();product.setId(productId);product.setPrice(new BigDecimal("999"));product.setProductName("隱藏商品");product.setNum(0);
?return product;}
}

注意這個用到的是OpenFeign的注解,所以寫法是接口加繼承,如果用SentinelResource注解則可以在一個類下寫

Sphu

這個就是硬編碼的方式來處理,手動try-catch

try (Entry entry = SphU.entry("orderService")) {// 處理訂單邏輯System.out.println("訂單處理中...");
} catch (
BlockException ex) {// 觸發限流,返回友好提示System.out.println("當前請求過多,請稍后重試");
}

流控規則

閾值類型: 1.QPS(每秒的請求數,底層通過計數器來統計,輕量速度快) 2.并發線程數(配合線程池,控制線程池中的數量,可能涉及線程調度)

是否集群: 1.單機均攤(比如每個機器都1s內可以處理5個請求) 2.總體閾值(1s內一共可以處理5個請求)

流控模式(只有快速失敗才適用)

1.直接(默認模式,這樣只要資源訪問量大就做限流處理)

2.鏈路策略: 如果是倆個上下文,則必須先在yml中關閉,然后這樣每個不同請求路徑都是一個鏈路,否則所有請求默認都在一個下邊

spring:cloud:openfeign:client:config:default:
# ? ? ? ? ?  loggerLevel: full # 日志級別connectTimeout: 4000 #以mm為單位readTimeout: 2000 #2sservice-product: # 精確設置微服務名
# ? ? ? ? ?  loggerLevel: full # 日志級別connectTimeout: 5000 #以mm為單位readTimeout: 2000 #2s
# ? ? ? ? ?  request-interceptors:
# ? ? ? ? ? ?  - com.daxz.order.interceptor.XTokenInterceptor
# ? ? ? ? ?  retryer: feign.Retryer.Defaultsentinel:transport:dashboard: localhost:8080 # 指定sentinel控制臺地址eager: true # 關閉懶加載(指只有真正發送請求時才開始建立連接,這樣可以適當減小開銷)為了方便,我們先關閉web-context-unify: false # 關閉,這樣可以開啟鏈路模式
?
feign:sentinel:enabled: true

3.當系統出現資源競爭時,可以采用關聯策略。(可以指定哪個資源要優先進行)

流控效果

1.快速失敗: 沒有超出閾值就交給業務處理,否則直接拋出異常

2.Warm Up: 有冷啟動時間

3.勻速排隊: 表示QPS的閾值在1s內均分,比如QPS=2,則500mm一個,不支持QPS>1000,因為這樣失效,而且會設置超時時間,沒排上隊就拋出異常即可。

熔斷規則

熔斷一般用于遠程調用(所以盡量自己編寫好兜底回調),并且熔斷配置在調用方

我們初始自定義的超時時間或者編寫的程序出現錯誤(比如1/0)都可以叫做異常,然后兜底返回。

錯誤糾正: 上邊的統計時長應該是熔斷策略開始統計的時間,超過最小請求數才會進行該過程。

最大RT就是預定時長。

熱點規則

實際上比流控規則就多了一條對指定參數的限制,更細致一點

// 測試了一個秒殺方法
@GetMapping("/seckill")
// 此時又重新起個名字,因為熱點規則對Web不是自動適配的,還需要手寫
@SentinelResource(value = "seckill-order", fallback = "seckillFallback")
public Order seckill(Long userId, Long productId) {Order order = orderService.createOrder(productId, Long.MAX_VALUE);return order;
}
?
// 上述的兜底回調方法
public Order seckillFallback(Long userId, Long productId, Throwable e) {Order order = new Order();order.setId(productId);order.setUserId(userId);order.setAddress("秒殺失敗,原因是: " + e.getMessage());return order;
}

參數索引也是從0開始表示代碼中的第一個參數。

當然如果required = false,表示可以沒有參數,這樣沒有的話就不會觸發相應的規則,如果defaultValue = ... 仍然有默認參數會除法規則

注意: @SentinelResource中的 blockHandler可以專門處理BlockException流控異常,如果使用fallback需要寫為Throwable所有異常

因為fallback還能處理1/0等業務異常,所以范圍比BlockException更大。

授權規則和系統規則

這些基本沒啥用,因為基本都需要相互訪問,授權規則沒啥用,而系統規則則不太精確,以后k8s會更加精確,所以系統規則也不用管。

持久化

由于sentinel是在內存中,所以idea每次重啟都會丟失,這時候只需要將其配置存儲到nacos并且還可以連接數據庫,這樣就不會消失了。

8.Gateway

網關

屬于架構部分,所以可以直接創建在最外層即可,而且也能自動負載均衡

<dependencies><!--也需要nacos--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--響應式網關--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--也需要負載均衡--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
</dependencies>

路由

指routes下的id、uri、斷言規則、過濾器等每組整體稱作路由

配置好ym就可以簡單測試訪問網關。

server:port: 80
spring:profiles:include: routeapplication:name: gatewaycloud:nacos:server-addr: localhost:8848
#這樣可以通過網關來訪問 localhost/api/order/請求路徑即可訪問
spring:cloud:gateway:routes:- id: order-route # 我們起的名稱uri: lb://service-order # lb表示負載均衡的訪問我們項目的微服務名稱predicates: # 表示遵守的規則,也是各種集合,比如路徑規則- Path=/api/order/**# 還有更多規則,以后可以慢慢學- id: product-routeuri: lb://service-productpredicates:- Path=/api/product/**

原理

首先配置的id是全局唯一,然后滿足斷言規則(可以有多個),然后轉給uri目的地,這其中還可以有Filter過濾器。

注意: 如果不指定order排序(數字越小優先級越高),那么就自定向下匹配,如果滿足某id下的斷言后,其余就不會生效。

spring:cloud:gateway:routes:# 這就是個例子,當然很多網站可能都要登錄,所以匹配時可能也是錯誤頁面- id: test-routeuri: https://www.bilibili.com/ #https://cn.bing.compredicates:- Path=/**order: 10- id: order-route # 我們起的名稱uri: lb://service-order # lb表示負載均衡的訪問我們項目的微服務名稱predicates: # 表示遵守的規則,也是各種集合,比如路徑規則- Path=/api/order/**# 還有更多規則,以后可以慢慢學order: 0- id: product-routeuri: lb://service-productpredicates:- Path=/api/product/**order: 1
#如果不指定order,則順序匹配了規則,這樣即使localhost/api/order/config也不會正常訪問我們的地址

斷言

短寫法
  • Path=/api/order/** yml中各種名稱來自于斷言工廠xxxRoutePredicateFactory,然后里邊Config.class基本就是這些名稱來源了

長寫法

各種規則

上邊是一個Query例子。

自定義斷言工廠

這樣自定義配置后yml就可以用到了,斷言邏輯,還有我們參數的順序也是自己指定,然后長短寫法都ok

過濾器

大多就是修改請求和響應,比如請求頭、響應體。

如果想要微服務都生效可以使用默認filter

spring:cloud:gateway:routes:# 這就是個例子,當然很多網站可能都要登錄,所以匹配時可能也是錯誤頁面- id: test-routeuri: https://cn.bing.compredicates:- Path=/**order: 10- id: order-route # 我們起的名稱uri: lb://service-order # lb表示負載均衡的訪問我們項目的微服務名稱predicates: # 表示遵守的規則,也是各種集合,比如路徑規則- Path=/api/order/** # 匹配后也會按照這個請求發給微服務,如果不想全部修改微服務請求就可以重寫路徑filters: #RewritePath=/api/order/?(?<segment>.*), /${segment} 這種就是正則來重寫路徑
# ? ? ? ? ?  - AddResponseHeader=X-Response-saber, Love 也可以自定義請求頭信息# 還有更多規則,以后可以慢慢學order: 0- id: product-routeuri: lb://service-productpredicates:- Path=/api/product/**order: 1default-filters: # 全局過濾器,所有請求都會經過- AddResponseHeader=X-Response-saber, Love
# ? ? ?  - AddRequestHeader=X-Request-role, violet 這個是提供給后端服務,所以瀏覽器不可見
#如果不指定order,則順序匹配了規則,這樣即使localhost/api/order/config也不會正常訪問我們的地址

也可以自定義一個全局filter:

package com.daxz.filter;
?
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
?
/*** 用響應完成時間-請求開始時間就能知道響應時間(即請求耗費了多久)*/
@Component // 也要加注入容器
@Slf4j
public class RtGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// filter中exchange包裝了請求和響應ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String uri = request.getURI().toString(); // 拿到請求地址long start = System.currentTimeMillis();log.info("請求地址[{}], 請求時間: {}", uri, start);// =================以上是前置邏輯,然后我們就可以用chain放行=================// 不過由于Mono是異步響應式,所以不能單純在下方寫后置邏輯,會瞬間執行// 流式處理加鏈式方法Mono<Void> filter = chain.filter(exchange).doFinally((result) -> {long end = System.currentTimeMillis();log.info("請求地址[{}], 響應時間: {}", uri, end - start);});// ================如果是用傳統的servlet則需要在下面寫后置邏輯================return filter;}
?// 可以指定順序@Overridepublic int getOrder() {return 0;}
}

自定義過濾器工廠

和上邊的斷言工廠也一樣,就是yml中可以寫自定義的內容,具體的原理以后可以再深入學習

全局跨越

原始方案是給每個controller代碼都加上@CrossOrigin即可解決,不過有些麻煩,所以可以編寫跨域filter來解決跨域問題

spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowed-origin-patterns: '*'allowed-headers: '*'allowed-methods: '*'

9.Seata

以前是一條連接里邊的事務才可以一起提交,一起回滾。傳統事務是連接級別,所以微服務自治數據庫即使加上事務,有多個連接則沒有用

注意,目前是每個微服務都有獨立的數據庫,而不是一個數據庫里邊有微服務對應的多張表,那樣就是單純的單體/集群架構了。

當然如果是對一個數據庫中的各種表進行操作,引入事務注解還是可以操作的。

監聽8091,但也提供web頁面在7091,然后高版本好像有些問題,推薦2.1

必須引入TC才能管理事務

resource下配置file.conf即可連上seata,具體原理可以單獨學學

service {#transaction service group mappingvgroupMapping.default_tx_group = "default"#only support when registry.type=file, please don't set multiple addressesdefault.grouplist = "127.0.0.1:8091"#degrade, current not supportenableDegrade = false#disable seatadisableGlobalTransaction = false
}

只需要在最大的方法事務,標注全局事務即可@GlobalTransactional(可以在service層標注,因為這里集中處理了事務)

@GlobalTransactional原理

二階提交協議

前鏡像: 在調用sql方法前來執行一次查詢操作

后鏡像: 更新后在執行一次查詢操作

還牽扯到全局鎖,可以多看幾遍了解原理

全部成功后才會刪除undo_log。

肯定效率不太高,以后深入學習再了解吧。

四種事務模式
AT模式
XA模式

AT和XA都是自動的,不過XA不會出現臟讀(可以搜搜),但效率低

TCC模式

這就是廣義事務(分三步),狹隘事務就是單純指對數據庫操作,當然TCC需要手寫

Saga模式

長事務,具體原理可以上網了解

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90979.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90979.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90979.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GPT Agent與Comet AI Aent瀏覽器對比橫評

1. 架構設計差異GPT Agent的雙瀏覽器架構&#xff1a;文本瀏覽器&#xff1a;專門用于高效處理大量文本內容&#xff0c;適合深度信息檢索和文獻追蹤&#xff0c;相當于Deep Research的延續可視化瀏覽器&#xff1a;具備界面識別與交互能力&#xff0c;可以點擊網頁按鈕、識別圖…

應用信息更新至1.18.0

增加DO權限 增加權限管理&#xff08;需DO支持&#xff09; 增加應用凍結隱藏&#xff08;需DO支持&#xff09; 增加權限委托&#xff08;需DO支持&#xff09; 增加特殊組件 ...

常用git命令集錦

git init 初始化 將當前目錄初始化為 git 本地倉庫&#xff0c;此時會在本地創建一個 .git 的文件夾 git init -q 靜默執行&#xff0c;就是在后臺執行 git init --bare –bare 參數,一般用來初始化一個空的目錄&#xff0c;作為遠程存儲倉庫 git init --template dir –templa…

skywalking安裝

一、簡介 SkyWalking是一款用于分布式系統跟蹤和性能監控的開源工具。它可以幫助開發人員了解分布式系統中不同組件之間的調用關系和性能指標&#xff0c;從而進行故障排查和性能優化。 它支持多種語言和框架&#xff0c;包括Java、.NET、Node.js等。它通過在應用程序中插入代…

利用DataStream和TrafficPeak實現大數據可觀察性

可觀察性工作流對于深入了解應用程序的健康狀況、客戶流量和整體性能至關重要。然而&#xff0c;要實現真正的可觀察性還面臨一些挑戰&#xff0c;包括海量的流量數據、數據保留、實施時間以及各項成本等。TrafficPeak是一款為Akamai云平臺打造&#xff0c;簡單易用、可快速部署…

jQuery 最新語法大全詳解(2025版)

引言 jQuery 作為輕量級 JavaScript 庫&#xff0c;核心價值在于 簡化 DOM 操作、跨瀏覽器兼容性和高效開發。盡管現代框架崛起&#xff0c;jQuery 仍在遺留系統維護、快速原型開發中廣泛應用。本文涵蓋 jQuery 3.6 核心語法&#xff0c;重點解析高效用法與最佳實踐。 一、jQu…

Android 15 修改截圖默認音量大小

概述 在 Android 15 中,截圖音效的默認音量可能過大,影響用戶體驗。本文將介紹如何通過修改系統源碼來調整截圖音效的默認音量大小。 修改位置 需要修改的文件路徑: frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundProvider.kt…

Python爬蟲實戰:快速采集教育政策數據(附官網工具庫API)

解鎖教育政策研究的數據金礦&#xff0c;用技術提升學術效率 在教育政策研究領域&#xff0c;獲取最新、最全面的政策文本是學術工作的基礎。傳統手動收集方式效率低下且容易遺漏關鍵政策&#xff0c;而Python爬蟲技術為教育研究者提供了高效的數據采集解決方案。本文將系統介…

驗證回文串-leetcode

如果在將所有大寫字符轉換為小寫字符、并移除所有非字母數字字符之后&#xff0c;短語正著讀和反著讀都一樣。則可以認為該短語是一個 回文串 。 字母和數字都屬于字母數字字符。 給你一個字符串 s&#xff0c;如果它是 回文串 &#xff0c;返回 true &#xff1b;否則&#xf…

嵌入式學習日志(十)

10 學習指針1 指針核心定義與本質1.1 指針與指針變量1、指針即地址&#xff0c;指針變量是存放地址的變量&#xff0c;其大小與操作系統位數相關&#xff1a;64 位系統中占 8 字節&#xff0c;32 位系統中占 4 字節。2、指針的核心功能是通過地址間接訪問目標變量&#xff0…

Anaconda創建環境報錯:CondaHTTPEFTOT: HTTP 403 FORBIDDEN for url

一、快速解決方案這類報錯的原因通常是由于 conda 無法訪問鏡像源或權限被服務器拒絕&#xff0c;以下是常見原因和對應的解決方案&#xff1a;檢查鏡像源拼寫是否正確conda config --show channels清華源鏡像示例如果不正確&#xff0c;先清除舊配置del %USERPROFILE%\.condar…

亞馬遜地址關聯暴雷:新算法下的賬號安全保衛戰

2025年Q3&#xff0c;上千個店鋪因共享稅代地址、海外倉信息重疊等問題被批量凍結&#xff0c;為行業敲響了“精細化合規”的警鐘。事件復盤&#xff1a;地址成為關聯風控的“致命開關”稅代機構違規引發“多米諾效應”事件的導火索指向稅代機構“saqibil”&#xff0c;其為降低…

在本地環境中運行 ‘dom-distiller‘ GitHub 庫的完整指南

在本地環境中運行 ‘dom-distiller’ GitHub 庫的完整指南 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家&#xff0c;覺得好請收藏。點擊跳轉到網站。 1. 項目概述 ‘dom-distiller’ 是一個用于將網頁…

11. isaacsim4.2教程-Transform 樹與Odometry

1. 前言學習目標在本示例中&#xff0c;你將學習如何&#xff1a;使用 TF 發布器將相機作為 TF 樹的一部分發布在 TF 上發布機械臂&#xff0f;可動結構&#xff08;articulation&#xff09;的樹狀結構發布里程計&#xff08;Odometry&#xff09;消息開始之前前置條件已完成 …

安寶特新聞丨安寶特與Logivations正式建立合作伙伴關系,共筑物流新未來

近日&#xff0c;安寶特與物流創新企業Logivations簽署合作協議&#xff0c;雙方將深度融合技術專長&#xff0c;共同為客戶提供高效、精準的智能物流解決方案&#xff0c;助力企業實現從人工巡檢到智能管控的跨越式升級。 關于Logivations Logivations是一家深耕物流與供應鏈…

第三階段—8天Python從入門到精通【itheima】-139節(pysqark實戰-前言介紹)

目錄 139節——pysqark實戰-前言介紹 1.學習目標 2.spark是什么 3.如下是詳細介紹 PySpark 的兩種使用方式&#xff0c;并提供具體的代碼示例【大數據應用開發比賽的代碼熟悉如潮水一般沖刷我的記憶】&#xff1a; 一、本地模式&#xff08;作為 Python 第三方庫使用&#…

redis數據庫的四種取得 shell方法

Redis作為高性能內存數據庫&#xff0c;若配置不當&#xff08;特別是未授權訪問&#xff09;&#xff0c;將面臨極高安全風險。攻擊者可利用漏洞實現遠程代碼執行&#xff08;GetShell&#xff09;&#xff0c;嚴重威脅數據安全與服務器控制權。本文深入剖析此類漏洞的核心原理…

墨者:SQL過濾字符后手工繞過漏洞測試(萬能口令)

1. 墨者學院&#xff1a;SQL過濾字符后手工繞過漏洞測試(萬能口令)&#x1f680; 2. 漏洞背景分析&#x1f50d; 近期發現某登錄系統存在SQL注入漏洞&#xff0c;攻擊者可通過構造特殊用戶名admin,a,a)#繞過身份驗證。本文將深入解析其工作原理&#xff0c;并演示完整滲透測試流…

Kafka 順序消費實現與優化策略

在 Apache Kafka 中&#xff0c;實現順序消費需要從 Kafka 的架構和特性入手&#xff0c;因為 Kafka 本身是分布式的消息系統&#xff0c;默認情況下并不完全保證全局消息的順序消費&#xff0c;但可以通過特定配置和設計來實現局部或完全的順序消費。以下是實現 Kafka 順序消費…

CSP-J 2022_第三題邏輯表達式

題目 邏輯表達式是計算機科學中的重要概念和工具&#xff0c;包含邏輯值、邏輯運算、邏輯運算優先級等內容。 在一個邏輯表達式中&#xff0c;元素的值只有兩種可能&#xff1a;0&#xff08;表示假&#xff09;和 1&#xff08;表示真&#xff09;。元素之間有多種可能的邏輯運…