創(chuàng)業(yè)公司就應(yīng)該技術(shù)選型 Spring Cloud Alibaba , 開(kāi)箱即用
大家好,我是Tom哥~
互聯(lián)網(wǎng)時(shí)代,面對(duì)復(fù)雜業(yè)務(wù),講究 分而治之。將一個(gè)大的單體系統(tǒng)拆分為若干個(gè)微服務(wù),保證每個(gè)系統(tǒng)的職責(zé)單一,可以垂直深度擴(kuò)展。
但是一個(gè)個(gè)獨(dú)立的微服務(wù)像一座座孤島,如何將他們串聯(lián)起來(lái),才能發(fā)揮最大價(jià)值。
這時(shí),我們就要提微服務(wù)的生態(tài)圈。
那么微服務(wù)生態(tài)圈都有哪些模塊?他們的作用分別是什么?
服務(wù)的注冊(cè)、發(fā)現(xiàn)。生產(chǎn)者啟動(dòng)時(shí),會(huì)將自己的信息注冊(cè)上報(bào),這樣調(diào)用方只需連接注冊(cè)中心,根據(jù)一定的負(fù)載算法,就可以與服務(wù)提供方建立連接,從而實(shí)現(xiàn)應(yīng)用間的解耦。
- 服務(wù)調(diào)用。通過(guò)多種協(xié)議(如:HTTP等)實(shí)現(xiàn)目標(biāo)服務(wù)的真正調(diào)用。
- 負(fù)載均衡。主要是提供多種負(fù)載算法,滿(mǎn)足不同業(yè)務(wù)場(chǎng)景下的集群多實(shí)例的選擇機(jī)制
- 服務(wù)的穩(wěn)定性。提供了服務(wù)熔斷、限流、降級(jí)
- 分布式配置中心。應(yīng)用的配置項(xiàng)統(tǒng)一管理,修改后能動(dòng)態(tài)生效
- 消息隊(duì)列。非核心邏輯從同步流程抽離,解耦,異步化處理,縮短RT時(shí)間
- 網(wǎng)關(guān)。將一些通用的處理邏輯,如:限流、鑒權(quán)、黑白名單、灰度等抽取到一個(gè)單獨(dú)的、前置化系統(tǒng)統(tǒng)一處理。
- 監(jiān)控。監(jiān)控系統(tǒng)的健康狀況
- 分布式鏈路追蹤。查看接口的調(diào)用鏈路,為性能優(yōu)化、排查問(wèn)題提供輸入
- 自動(dòng)化部署。持續(xù)集成,快速部署應(yīng)用。
圍繞這些功能模塊,Spring Cloud Alibaba 為我們提供了微服務(wù)化開(kāi)發(fā)的一站式解決方案,我們只需要少量的Spring 注解 和 yaml配置,便可以快速構(gòu)建出一套微服務(wù)系統(tǒng)。真的是創(chuàng)業(yè)者的福音。
那么這套生態(tài)規(guī)范都提供了哪些技術(shù)框架呢?
一、Spring Boot(服務(wù)基座)
Spring Boot 是Spring框架的擴(kuò)展,提供更加 豐富的注解,根據(jù) 約定勝于配置 原則,與市場(chǎng)主流的開(kāi)源框架打通, 設(shè)計(jì)了 Starter 和 AutoConfiguration 機(jī)制,簡(jiǎn)化配置流程,通過(guò)簡(jiǎn)單的jar包引入,快速具備組件集成能力。大大提高了程序員的開(kāi)發(fā)效率。
特點(diǎn):
- 提供了豐富的注解,不要在XML文件中定義各種繁瑣的bean配置
- 內(nèi)嵌 Web容器,如:Tomcat(默認(rèn))、Jetty、Undertow
- 集成了主流開(kāi)源框架,根據(jù)項(xiàng)目依賴(lài)自動(dòng)配置
二、Nacos(注冊(cè)中心、分布式配置中心)
Nacos 是阿里巴巴的開(kāi)源的項(xiàng)目,全稱(chēng) Naming Configuration Service ,專(zhuān)注于服務(wù)發(fā)現(xiàn)和配置管理領(lǐng)域。
Nacos 致力于幫助您發(fā)現(xiàn)、配置和管理微服務(wù)。Nacos 提供了一組簡(jiǎn)單易用的特性集,幫助您快速實(shí)現(xiàn)動(dòng)態(tài)服務(wù)發(fā)現(xiàn)、服務(wù)配置、服務(wù)元數(shù)據(jù)及流量管理。功能齊全,可以替換之前的 Spring Cloud Netflix Eureka、Spring Cloud Config、Spring Cloud Bus,野心巨大。
客戶(hù)端語(yǔ)言方面目前支持 Java,go 、python、 C# 和 C++等主流語(yǔ)言
開(kāi)源地址:https://github.com/alibaba/nacos
Nacos 有一個(gè)控制臺(tái),可以幫助用戶(hù)管理服務(wù),監(jiān)控服務(wù)狀態(tài)、應(yīng)用的配置管理。
集群化部署:
由于 Nacos 是單節(jié)點(diǎn),無(wú)論做為注冊(cè)中心還是分布式配置中心,一旦服務(wù)器掛了,作為底層服務(wù)引發(fā)的麻煩還是非常大的。如何保證其高可用?
Nacos 官方提供的集群部署架構(gòu)圖:
??https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html??
在nacos的解壓目錄nacos/conf目錄下,有配置文件cluster.conf,每行配置成 ip:port。(一般配置3個(gè)或3個(gè)以上節(jié)點(diǎn))
# ip:port
200.8.9.16:8848
200.8.9.17:8848
200.8.9.18:8848
這樣保證客戶(hù)端只需要寫(xiě)一次,由 Leader節(jié)點(diǎn)將數(shù)據(jù)同步到其他節(jié)點(diǎn),保證各個(gè)節(jié)點(diǎn)的數(shù)據(jù)一致性
對(duì)于上層的SLB,我們可以采用 Nginx 或者 OpenResty,在 upstream 模塊里配置 Nacos 的集群IP 地址列表,實(shí)現(xiàn)負(fù)載均衡功能。
另外,借助Nginx的心跳檢測(cè),當(dāng)某臺(tái) Nacos 服務(wù)掛掉后,SLB 會(huì)自動(dòng)屏蔽,將流量切換到其他 Nacos 實(shí)例。
當(dāng)然 OpenResty 也可能成為單點(diǎn)故障,為了保證高可用,我們需要借助 Keepalived
客戶(hù)端請(qǐng)求 VIP,然后請(qǐng)求打到了 OpenResty,由 OpenResty 轉(zhuǎn)發(fā)給具體的某個(gè) Nacos 節(jié)點(diǎn)。
OpenResty 只有一個(gè)節(jié)點(diǎn)提供服務(wù),另一個(gè)暫停狀態(tài),如果 master 節(jié)點(diǎn)宕機(jī),那 backup 接替繼續(xù)工作。從而解決了單點(diǎn)故障問(wèn)題。
Keepalived 作為一種高性能的服務(wù)器高可用或熱備解決方案,用來(lái)防止服務(wù)器單點(diǎn)故障的發(fā)生。市面資料很多,下文鏈接是《Keepalived+Nginx部署方案》具體操作步驟
??https://help.fanruan.com/finereport/doc-view-2905.html??
三、RestTemplate + Ribbon (遠(yuǎn)程調(diào)用)
Spring Cloud Ribbon 基于 Netflix Ribbon 封裝的負(fù)載均衡框架。內(nèi)部集成了多種負(fù)載算法,如:隨機(jī)、輪詢(xún)等。
與注冊(cè)中心打通,能自動(dòng)獲取服務(wù)提供者的地址列表。結(jié)合自身的負(fù)載算法,選擇一個(gè)目標(biāo)實(shí)例發(fā)起服務(wù)調(diào)用。
Ribbon 也提供了擴(kuò)展接口,支持自定義負(fù)載均衡算法。
public class CustomRule extends AbstractLoadBalancerRule {
private AtomicInteger count = new AtomicInteger(0);
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
private Server choose(ILoadBalancer loadBalancer, Object key) {
List<Server> allServers = loadBalancer.getAllServers();
int requestNumber = count.incrementAndGet();
if (requestNumber >= Integer.MAX_VALUE) {
count = new AtomicInteger(0);
}
if (null != allServers) {
int size = allServers.size();
if (size > 0) {
int index = requestNumber % size;
Server server = allServers.get(index);
if (null == server || !server.isAlive()) {
return null;
}
return server;
}
}
return null;
}
}
缺點(diǎn):
調(diào)用方每次發(fā)起遠(yuǎn)程服務(wù)調(diào)用時(shí),都需要填寫(xiě)遠(yuǎn)程目標(biāo)地址,還要配置各種參數(shù),非常麻煩,不是很方便
// 注冊(cè)到Nacos的應(yīng)用名稱(chēng)
private final String SERVER_URL = "http://nacos-provider-demo";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/hello")
public String hello() {
// 遠(yuǎn)程服務(wù)調(diào)用
return restTemplate.getForObject(SERVER_URL + "/hello", String.class);
}
四、OpenFeign(遠(yuǎn)程調(diào)用)
RestTemplate + Ribbon 每次發(fā)起遠(yuǎn)程服務(wù)調(diào)用時(shí),都需要填寫(xiě)遠(yuǎn)程目標(biāo)地址,還要配置各種參數(shù),非常麻煩。
Feign 是一個(gè)輕量級(jí)的 Restful HTTP 客戶(hù)端,內(nèi)嵌了 Ribbon 作為客戶(hù)端的負(fù)載均衡。面向接口編程,使用時(shí)只需要定義一個(gè)接口并加上@FeignClient注解,非常方便。
OpenFeign 是 Feign 的增強(qiáng)版。對(duì) Feign 進(jìn)一步封裝,支持 Spring MVC 的標(biāo)準(zhǔn)注解和HttpMessageConverts
依賴(lài)包:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@FeignClient(value = "${provider.name}")
public interface OrderService {
// 調(diào)用服務(wù)提供者的 /create_order 接口
@RequestMapping(value = "/create_order",method = RequestMethod.GET)
public String createOrder();
其中,@FeignClient(value = "${provider.name}") 定義了服務(wù)提供方的工程名,底層自動(dòng)打通了注冊(cè)中心,會(huì)拿到 artifactId 對(duì)應(yīng)的IP列表,根據(jù)一定的負(fù)載均衡算法,可以將請(qǐng)求打到目標(biāo)服務(wù)器上。
OpenFeign 默認(rèn)等待接口返回?cái)?shù)據(jù)的時(shí)間是 1 秒,超過(guò)這個(gè)時(shí)間就會(huì)報(bào)錯(cuò)。如果想調(diào)整這個(gè)時(shí)間,可以修改配置項(xiàng) feign.client.config.default.readTimeout
五、Dubbo Spring Cloud(遠(yuǎn)程調(diào)用)
RestTemplate + Ribbon 和 OpenFeign 都是基于HTTP協(xié)議調(diào)用遠(yuǎn)程接口。而 Dubbo Spring Cloud 是基于 TCP 協(xié)議來(lái)調(diào)用遠(yuǎn)程接口。相比 HTTP 的大量的請(qǐng)求頭,TCP 更輕量級(jí)。
Dubbo Spring Cloud = Spring Cloud + Dubbo
特性:
- 支持多種注冊(cè)中心,用于服務(wù)的注冊(cè)、發(fā)現(xiàn)
- 內(nèi)置多種負(fù)載均衡策略
- 服務(wù)粒度是面向接口,支持 TCP 輕量級(jí)協(xié)議
- 容易擴(kuò)展,采用 微內(nèi)核 + 插件 的設(shè)計(jì)原則,擴(kuò)展點(diǎn)更強(qiáng)
依賴(lài)包:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
注意:雖然是將 Dubbo 集成到了 Spring Cloud,增加了一些 注解 和 yaml 配置項(xiàng),開(kāi)發(fā)更方便,但大部分調(diào)用玩法還是遵守 Dubbo 框架那一套。
幾個(gè)重要的配置項(xiàng):
- dubbo.scan.base-packages # dubbo 服務(wù)掃描基準(zhǔn)包,上報(bào)注冊(cè)服務(wù)
- dubbo.protocol.name: dubbo # 支持的協(xié)議
- dubbo.protocol.port: -1 # dubbo 協(xié)議端口( -1 表示自增端口,從 20880 開(kāi)始)
- dubbo.registry.address # 注冊(cè)中心地址
六、Spring Cloud Gateway(網(wǎng)關(guān))
分布式時(shí)代,一個(gè)復(fù)雜的系統(tǒng)被拆分為若干個(gè)微服務(wù)系統(tǒng),每個(gè)系統(tǒng)都配置獨(dú)立的域名肯定不合適。為了解決這個(gè)問(wèn)題,網(wǎng)關(guān)便誕生了。
網(wǎng)關(guān)充當(dāng)反向代理的角色,作為流量的第一入口,承載了很多基礎(chǔ)的、公共的模塊功能,如:流控、鑒權(quán)、監(jiān)控、路由轉(zhuǎn)發(fā)等。
Spring Cloud 生態(tài)早期的網(wǎng)關(guān)是 Netflix 公司的Zuul,后來(lái)Zuul社區(qū)停止了維護(hù)。官方后來(lái)推出了 Spring Cloud Gateway,其底層是基于 WebFlux 框架,而WebFlux框架的底層采用高性能通訊框架 Netty,性能是 Zuul 的 1.6 倍。
核心組件:
1、路由。
內(nèi)部主要是負(fù)責(zé)轉(zhuǎn)發(fā)規(guī)則。
2、斷言(Predicate)
如果返回為true,當(dāng)前路由才有效,才會(huì)路由到具體的服務(wù)。官方提供了很多內(nèi)置路由斷言,如果滿(mǎn)足不了你的訴求,也可以自定義路由斷言工廠。
所有的路由斷言工廠都是繼承自 AbstractRoutePredicateFactory,自定義類(lèi)的命名也有固定規(guī)則,“配置名”+RoutePredicateFactory。這樣,在yaml配置時(shí),只需要寫(xiě)前面定義的配置名即可。
3、過(guò)濾器(Filter)
主要是請(qǐng)求、響應(yīng)之間增加一些自定義的邏輯。按作用范圍分為:全局和局部。全局是作用于所有的路由;而局部只是作用于某一個(gè)路由。
跟上面的斷言類(lèi)似,除了官方提供的過(guò)濾器,也支持自定義。
局部過(guò)濾器:繼承自 AbstractGatewayFilterFactory,自定義類(lèi)的命名也有固定規(guī)則,“配置名”+GatewayFilterFactory。這樣,在yaml配置時(shí),只需要寫(xiě)前面定義的配置名即可。
全局過(guò)濾器:實(shí)現(xiàn)GlobalFilter,Ordered 兩個(gè)接口,實(shí)現(xiàn)邏輯跟上面的局部過(guò)濾器類(lèi)似。這里就不展開(kāi)了。其中的 Ordered 接口主要是負(fù)責(zé)優(yōu)先級(jí),數(shù)值越小,優(yōu)先級(jí)越高。
依賴(lài)包:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
yaml 的配置示例:
spring:
cloud:
gateway:
routes: #路由,可配置多個(gè)
- id: user_route # 路由id 唯一即可,默認(rèn)是UUID
uri: lb://user-server-sample # 匹配成功后提供的服務(wù)的地址
order: 1 # 路由優(yōu)先級(jí),數(shù)值越小優(yōu)先級(jí)越高,默認(rèn)0
predicates:
- Path=/user/** # 斷言,路徑匹配進(jìn)行路由
# - User=0, 1000 # 自定義路由斷言工廠 只允許查詢(xún)id為0 - 1000之間的用戶(hù)
# - Method=POST # 表示需要POST方式請(qǐng)求
# - Query=id, \d+ # 參數(shù)名id,正則表達(dá)式為\d+(一個(gè)或多個(gè)數(shù)字)
filters:
- AddRequestHeader=X-Request-token, 12345678 #為原始請(qǐng)求加上請(qǐng)求頭及值
當(dāng)然,服務(wù)提供方的地址可能經(jīng)常變化,為了動(dòng)態(tài)感知,我們引入 Nacos 注冊(cè)中心,用于服務(wù)的注冊(cè)、發(fā)現(xiàn),統(tǒng)一管理服務(wù)的IP地址。網(wǎng)關(guān)路由轉(zhuǎn)發(fā)時(shí),只需從 Nacos 動(dòng)態(tài)獲取即可。
七、Sentinel(熔斷、限流、降級(jí))
Sentinel 是阿里開(kāi)源的流控框架,提供了簡(jiǎn)單易用的控制臺(tái),比 Hystrix支持的范圍更廣。
集成簡(jiǎn)單,只需要少量配置,即可快速接入,支持如:gRPC、Dubbo、Spring Cloud 等
同類(lèi)競(jìng)品框架:
- Hystrix 框架已經(jīng)停止維護(hù);
- Resilience4j 一種輕量級(jí)容錯(cuò)庫(kù),專(zhuān)為 Java 8 和函數(shù)式編程而設(shè)計(jì)。通過(guò)裝飾器的方式,以使用斷路器,速率限制器,重試或隔板來(lái)增強(qiáng)任何功能接口,lambda 表達(dá)式或方法引用。
流控規(guī)則:
頁(yè)面元素介紹:
資源名:唯一即可
針對(duì)來(lái)源:對(duì)調(diào)用者限流,填寫(xiě)應(yīng)用名稱(chēng)(Spring.application.name的值),只針對(duì)某個(gè)服務(wù)限流
閾值類(lèi)型
- QPS:每秒接收的請(qǐng)求數(shù)
- 線(xiàn)程數(shù):能使用的業(yè)務(wù)線(xiàn)程數(shù)
流控模式
- 直接:達(dá)到條件后,直接執(zhí)行某個(gè)流控效果
- 關(guān)聯(lián):如果訪(fǎng)問(wèn)關(guān)聯(lián)接口B達(dá)到了閾值,則讓接口A返回失敗
- 鏈路:記錄從入口資源的流量,達(dá)到條件也只限流入口資源
流控效果
- 快速失?。褐苯臃祷厥〗Y(jié)果
- Warm Up:預(yù)熱,開(kāi)始有一個(gè)緩沖期,初始值 = 閾值/ codeFactor(默認(rèn) 3),然后慢慢達(dá)到設(shè)置的閾值
- 排隊(duì)等待:讓請(qǐng)求以均勻的速度通過(guò),如果請(qǐng)求超過(guò)閾值就等待,如果等待超時(shí)則返回失敗
降級(jí)規(guī)則:
- RT
- 異常數(shù)
- 異常比例
系統(tǒng)規(guī)則:
流控規(guī)則和降級(jí)規(guī)則是針對(duì)某個(gè)資源來(lái)說(shuō)的,而系統(tǒng)規(guī)則是針對(duì)整個(gè)應(yīng)用的,粒度更大,當(dāng)前所有的接口服務(wù)都會(huì)應(yīng)用這個(gè)系統(tǒng)規(guī)則。
授權(quán)規(guī)則:
根據(jù)調(diào)用方判斷調(diào)用的接口資源是否被允許,如:黑名單、白名單機(jī)制
熱點(diǎn)規(guī)則:
將粒度進(jìn)一步細(xì)化,可以針對(duì)方法的參數(shù)做規(guī)則控制,為每個(gè)參數(shù)設(shè)置單獨(dú)的閾值,也可以多個(gè)參數(shù)組合。從而實(shí)現(xiàn)單個(gè)方法的熱點(diǎn)流量,按業(yè)務(wù)需求進(jìn)一步控制。
@SentinelResource注解
@SentinelResource 注解可以根據(jù)實(shí)際情況定制化功能,跟 Hystrix 的 @HystrixCommand 注解功能類(lèi)似。達(dá)到閾值后,系統(tǒng)的默認(rèn)提示是一段英文,很不友好,所以我們要自定義兜底方法。
// 資源名稱(chēng)為handle1
@RequestMapping("/handle1")
@SentinelResource(value = "handle1", blockHandler = "blockHandlerTestHandler")
public String handle1(String params) {
// 業(yè)務(wù)邏輯處理
return "success";
}
// 接口方法 handle1 的 兜底方法
public String blockHandlerTestHandler(String params, BlockException blockException) {
return "兜底返回";
}
注意:@SentinelResource注解中,除了blockHandler字段外,還有fallback字段
- blockHandler:主觀層面,如果被限流,則調(diào)用該方法,進(jìn)行兜底處理
- fallback:對(duì)業(yè)務(wù)的異常兜底,比如,執(zhí)行過(guò)程中拋了各種Exception,則調(diào)用該方法,進(jìn)行兜底處理
通過(guò)上面兩層兜底,可以讓Sentinel 框架更加人性化,體驗(yàn)更好。
集群流控:
單機(jī)限流很容易做,但是互聯(lián)網(wǎng)很多應(yīng)用都是集群部署,畢竟其下游還掛載著 mysql、或者其他微服務(wù),為了防止對(duì)下游的大流量沖擊,采用集群流控。防止單機(jī)的流量不均勻, 理想下 QPS = 單機(jī)閾值 * 節(jié)點(diǎn)數(shù)
八、Seata(分布式事務(wù))
事務(wù)的原子性和持久性可以確保在一個(gè)事務(wù)內(nèi),更新多條數(shù)據(jù),要么都成功,要么都失敗。在一個(gè)系統(tǒng)內(nèi)部,我們可以使用數(shù)據(jù)庫(kù)事務(wù)來(lái)保證數(shù)據(jù)一致性。那如果一筆交易,涉及到跨多個(gè)系統(tǒng)、多個(gè)數(shù)據(jù)庫(kù)的時(shí)候,用單一的數(shù)據(jù)庫(kù)事務(wù)就沒(méi)辦法解決了,此時(shí)需要引入分布式事務(wù)
Seata 是一款開(kāi)源的分布式事務(wù)解決方案,致力于提供高性能和簡(jiǎn)單易用的分布式事務(wù)服務(wù)。Seata 將為用戶(hù)提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,默認(rèn) AT 模式 ,為用戶(hù)打造一站式的分布式解決方案。
優(yōu)點(diǎn):
- 對(duì)業(yè)務(wù)無(wú)侵入:即減少技術(shù)架構(gòu)上的微服務(wù)化所帶來(lái)的分布式事務(wù)問(wèn)題對(duì)業(yè)務(wù)的侵入
- 高性能:減少分布式事務(wù)解決方案所帶來(lái)的性能消耗
Seata有3個(gè)基本組成部分:
- 事務(wù)管理器(TM):定義全局事務(wù)的范圍:開(kāi)始全局事務(wù),提交或回滾全局事務(wù)。
- 事務(wù)協(xié)調(diào)器(TC):維護(hù)全局事務(wù)和分支事務(wù)的狀態(tài),驅(qū)動(dòng)全局提交或回滾。
- 資源管理器(RM):管理正在處理的分支事務(wù)的資源,與TC對(duì)話(huà)以注冊(cè)分支事務(wù)并報(bào)告分支事務(wù)的狀態(tài),并驅(qū)動(dòng)分支事務(wù)的提交或回滾。
運(yùn)行流程:
- TM 向 TC 申請(qǐng)開(kāi)啟一個(gè)全局事務(wù),全局事務(wù)創(chuàng)建成功并生成一個(gè)全局唯一的 XID
- XID 在微服務(wù)調(diào)用鏈路的上下文中傳播
- RM 向 TC 注冊(cè)分支事務(wù),TC 返回分支事務(wù)ID ,并將其納入 XID 對(duì)應(yīng)全局事務(wù)的管轄
- RM 執(zhí)行本地業(yè)務(wù)表操作,并記錄 undo_log 日志,提交本地事務(wù)
- 當(dāng)所有的 RM 都執(zhí)行完后,TM 向 TC 發(fā)起針對(duì) XID 的全局提交或回滾決議
- TC 調(diào)度 XID 下管轄的全部分支事務(wù)完成提交或回滾請(qǐng)求。如果提交,刪除 undo_log 日志就可以了。如果是回滾,根據(jù) undo_log 表記錄逆向回滾本地事務(wù),把數(shù)據(jù)還原,最后再刪除 undo_log 日志。
關(guān)于 Seata 之前寫(xiě)過(guò)很多文章,這里就不展開(kāi)了,感興趣可以看看
- 業(yè)務(wù)無(wú)侵入框架Seata, 解決分布式事務(wù)問(wèn)題
- 深度剖析 Seata TCC 模式【圖解 + 源碼分析】
- 七種分布式事務(wù)的解決方案,一次講給你聽(tīng)
九、Spring Cloud Stream (異步消息)
Spring Cloud Stream 是統(tǒng)一消息中間件編程模型的框架,屏蔽了底層消息中間件的差異。支持的MQ 框架有 RabbitMQ、Kafka、RocketMQ 等
常用注解:
- @Input:標(biāo)記為輸入信道,消費(fèi)消息
- @Output:標(biāo)記為輸出信道,生產(chǎn)消息
- @StreamListener:監(jiān)聽(tīng)某個(gè)隊(duì)列,接收消息,處理自身的業(yè)務(wù)邏輯
- @EnableBinding:綁定通道
依賴(lài)包:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
綁定通道:
@SpringBootApplication
@EnableBinding({CustomSource.class})
public class StreamProduceApplication {
public static void main(String[] args) {
SpringApplication.run(StreamProduceApplication.class, args);
}
}
定義輸出信道:
public interface CustomSource {
@Output("output1")
MessageChannel output1();
}
yaml 配置:
spring:
cloud:
stream:
rocketmq:
binder:
name-server: 127.0.0.1:9876 # rocketMq服務(wù)地址
bindings:
output1:
producer:
transactional: true # 事務(wù)
group: myTxProducerGroup # 事務(wù)分組
bindings:
output1:
destination: test-transaction-topic # 主題
content-type: application/json # 數(shù)據(jù)類(lèi)型
發(fā)送消息:
@Service
public class SendMessageService {
@Resource
private CustomSource customSource;
public String sendMessage() { //發(fā)送簡(jiǎn)單字符串消息的方法
String message = "字符串測(cè)試消息";
// 發(fā)送消息
customSource.output1().send(MessageBuilder.withPayload(message).build());
return "發(fā)送成功!";
}
}
十、SkyWalking(分布式鏈路追蹤)
SkyWalking 是 一款 APM(應(yīng)用性能監(jiān)控)系統(tǒng),專(zhuān)為微服務(wù)、云原生架構(gòu)、容器(Docker、k8s、Mesos)而設(shè)計(jì)。通過(guò)探針收集應(yīng)用的指標(biāo),進(jìn)行分布式鏈路追蹤,感知服務(wù)間的調(diào)用鏈路關(guān)系。
特性:
- 支持告警
- 采用探針技術(shù),代碼零侵入
- 輕量高效,不需要大數(shù)據(jù)平臺(tái)
- 多個(gè)語(yǔ)言自動(dòng)探針。包括 Java,.NET Core 和 Node.JS。
- 強(qiáng)大的可視化后臺(tái)
- 上部分 Agent :負(fù)責(zé)從應(yīng)用中,收集鏈路信息,發(fā)送給 SkyWalking OAP 服務(wù)器。目前支持 SkyWalking、Zikpin、Jaeger 等提供的 Tracing 數(shù)據(jù)信息。而我們目前采用的是,SkyWalking Agent 收集 SkyWalking Tracing 數(shù)據(jù),傳遞給服務(wù)器。
- 下部分 SkyWalking OAP :負(fù)責(zé)接收 Agent 發(fā)送的 Tracing 數(shù)據(jù)信息,然后進(jìn)行分析(Analysis Core) ,存儲(chǔ)到外部存儲(chǔ)器( Storage ),最終提供查詢(xún)( Query )功能。
- 右部分 Storage :Tracing 數(shù)據(jù)存儲(chǔ)。目前支持 ES、MySQL、Sharding Sphere、TiDB、H2 多種存儲(chǔ)器。而我們目前采用的是 ES ,主要考慮是 SkyWalking 開(kāi)發(fā)團(tuán)隊(duì)自己的生產(chǎn)環(huán)境采用 ES 為主。
左部分 SkyWalking UI :負(fù)責(zé)提供控臺(tái),查看鏈路等等。
SkyWalking 部署起來(lái)還是很簡(jiǎn)單的,apache官網(wǎng)直接下載并解壓即可。
??https://skywalking.apache.org/??
SkyWalking 快速入門(mén)手冊(cè):
??https://skywalking.apache.org/zh/2020-04-19-skywalking-quick-start/??
十一、XXL-JOB(分布式任務(wù)調(diào)度)
關(guān)于定時(shí)任務(wù),相信大家都不陌生。但是單節(jié)點(diǎn)的定時(shí)任務(wù)有很多不足:
- 不支持集群,如果同時(shí)部署多個(gè)節(jié)點(diǎn),會(huì)競(jìng)爭(zhēng)數(shù)據(jù),造成數(shù)據(jù)重復(fù)
- 如果是單節(jié)點(diǎn),宕機(jī)后,任務(wù)無(wú)法自動(dòng)感知、重啟
- 不支持任務(wù)失敗重試
- 不支持執(zhí)行時(shí)間的動(dòng)態(tài)調(diào)整
- 無(wú)報(bào)警機(jī)制
- 無(wú)任務(wù)數(shù)據(jù)統(tǒng)計(jì)功能
- 不支持?jǐn)?shù)據(jù)分片
無(wú)論是集群化,還是周邊的生態(tài)建設(shè),都不完備。而 XXL-JOB,可以完美解決這些問(wèn)題。
XXL-JOB 是一款分布式任務(wù)調(diào)度框架,依賴(lài)的組件少(僅依賴(lài) Java 和 MySQL),開(kāi)箱即用。并提供了可視化界面,統(tǒng)計(jì)任務(wù)數(shù)據(jù),動(dòng)態(tài)修改任務(wù)執(zhí)行時(shí)間,內(nèi)置郵件報(bào)警,支持任務(wù)分片和任務(wù)失敗重試。
核心模塊:
1、調(diào)度中心
本身不執(zhí)行業(yè)務(wù)邏輯,只負(fù)責(zé)向執(zhí)行器發(fā)送調(diào)度命令。
2、執(zhí)行器
接收調(diào)度中心的請(qǐng)求,并執(zhí)行業(yè)務(wù)邏輯。
依賴(lài)包:
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.2.0</version>
</dependency>
yaml 配置:
server:
port: 8082 #程序端口
xxl:
job:
admin:
addresses: http://127.0.0.1:8002/xxl-job-admin # 調(diào)度中心地址,多個(gè)用逗號(hào)分開(kāi)
accessToken: # 調(diào)度中心和執(zhí)行器通信的token,如果設(shè)置,兩邊要一樣
executor:
appname: xxl-job-executor-sample #執(zhí)行器名稱(chēng)
address: # 執(zhí)行器地址,默認(rèn)使用xxl.job.executor.address配置項(xiàng),如果為空,則使用xxl.job.executor.ip + xxl.job.executor.port
ip: # 執(zhí)行器IP
port: 9989 #執(zhí)行器端口,與調(diào)度中心通信的端口
logpath: D:/work/Spring-Cloud-Alibaba/sample/logs # 日志保存路徑
logretentiondays: 30 # 日志保留天數(shù)
XxlJobSpringExecutor 初始化:
@Bean
public XxlJobSpringExecutor xxlJobExecutor() { // XXL-JOB執(zhí)行器初始化
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
我們可以采用 BEAN 模式, 使用 @XxlJob 注解描述代碼。優(yōu)點(diǎn):適用于一些復(fù)雜的業(yè)務(wù)場(chǎng)景。
也可以采用 GLUE 模式,將 執(zhí)行代碼 托管到調(diào)度中心在線(xiàn)維護(hù)。優(yōu)點(diǎn):簡(jiǎn)單快捷,不需要單獨(dú)的業(yè)務(wù)工程。
如果要處理的數(shù)據(jù)量較大時(shí),我們可以采用分片處理機(jī)制,將任務(wù)均攤到每個(gè)節(jié)點(diǎn),從而減輕單個(gè)節(jié)點(diǎn)的壓力。
shardingVO.getIndex() # 當(dāng)前執(zhí)行器的分片序號(hào)(從0開(kāi)始)
shardingVO.getTotal() # 總分片數(shù),執(zhí)行器集群的數(shù)量
# dataSource 待處理的所有原始數(shù)據(jù)
for (Integer val : dataSource) { // 遍歷代理
if (val % shardingVO.getTotal() == shardingVO.getIndex()) { // 取余
//TODO 歸屬于當(dāng)前分片處理
}
}
XXL-JOB 快速入門(mén)手冊(cè):
??https://www.xuxueli.com/xxl-job/??
巨人肩膀:
《Spring Cloud Alibaba 微服務(wù)實(shí)戰(zhàn)》