偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

阿里二面:外部接口大量超時 ,把整個系統(tǒng)拖垮,引發(fā)雪崩!如何解決?

開發(fā) 架構
本著復雜的事情簡單化的原則,我們將一個大的系統(tǒng)拆分成若干個子系統(tǒng),每個 子系統(tǒng) 職責單一,按 DDD 的設計理念,承載一個子域的業(yè)務建設。

大家好,我是Tom哥~

互聯(lián)網(wǎng)+ 時代,業(yè)務數(shù)字化已經(jīng)蔓延到你能想到的各個行業(yè)。各種業(yè)務功能、營銷玩法越來越多,系統(tǒng)也越來越復雜。

面對不斷復雜的業(yè)務系統(tǒng),腦子越來越不夠用了

于是 聰明的人們 提出了 微服務 的設計思想

本著 復雜的事情簡單化 的原則,我們將一個大的系統(tǒng)拆分成若干個子系統(tǒng),每個 子系統(tǒng) 職責單一,按 DDD 的設計理念,承載一個子域的業(yè)務建設。

于是,人們可以將精力聚焦,專心完成某一個業(yè)務點的深度建設。

多個微服務系統(tǒng)之間通過 RPC 框架(如:dubbo、spring cloud、gRPC 等)完成了串聯(lián),但隨著調用量越來越大,人們發(fā)現(xiàn)服務與服務之間的穩(wěn)定性變得越來越重要

舉個例子:

  • Service D 掛了,響應很慢
  • Service G 和 Service F ,都依賴 Service D,也會受到牽連,對外響應也會變慢
  • 影響層層向上傳遞,Service A 和 Service B 也會被拖垮
  • 最后,引發(fā)雪崩效應,系統(tǒng)的故障影響面會越來越大

為了解決這種問題,我們需要引入 熔斷 機制?!爱敂鄤t斷,不受其亂。當斷不斷,必受其難”

什么是熔斷?

熔斷,其實是對調用鏈路中某個資源出現(xiàn)不穩(wěn)定狀態(tài)時(如:調用超時或異常比例升高),對這個資源的調用進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯(lián)錯誤。

當資源被降級后,在接下來的降級時間窗口內(nèi),對該資源的調用都自動熔斷(默認是拋出 BlockException)

目前市面上的熔斷框架很多,如:Sentinel、Hystrix、Resilience4j 等,這些框架的設計理念都差不多。

本文重點講下 Sentinel 是如何在項目中使用的

Sentinel (分布式系統(tǒng)的流量防衛(wèi)兵) 是阿里開源的一套用于服務容錯的綜合性解決方案。它以流量為切入點, 從流量控制、熔斷降級、系統(tǒng)負載保護等多個維度來保護服務的穩(wěn)定性。

核心分為兩部分:

1、核心庫(Java 客戶端):能夠運行在所有 Java 環(huán)境,對 Dubbo 、Spring Cloud 等框架也有較好的支持。

2、控制臺(Dashboard):基于 Spring Boot 開發(fā),打包后可以直接運行。

Sentinel 熔斷種類:

  • RT 響應時間
  • 異常數(shù)
  • 異常比例

Sentinel 安裝

首先,官網(wǎng)下載 sentinel 控制臺安裝包

下載地址:https://github.com/alibaba/Sentinel/releases

下載 Jar 包后,打開終端,運行命令

java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar

登陸Sentinal控制臺:

默認用戶和密碼都是 sentinel ,登錄成功后的界面如下,先來個直觀感受

控制臺配置熔斷規(guī)則:

這里表示熔斷策略選擇 慢調用比例,響應時間超過200毫秒則標記為慢請求。如果在一個1000 ms的統(tǒng)計周期內(nèi)(可自行調整),慢請求比例超過30%且數(shù)量超過3個,則對后續(xù)請求進行熔斷,熔斷時長為10秒鐘,10秒以后恢復正常。

注解式接入

接入非常簡單,只需要提前在控制臺配置好資源規(guī)則,然后在代碼中添加 @SentinelResource注解即可。

// 資源名稱為handle1 
@RequestMapping("/handle1")
@SentinelResource(value = "handle1", blockHandler = "blockHandlerTestHandler")
public String handle1(String params) {
// 業(yè)務邏輯處理
return "success";
}

// 接口方法 handle1 的 兜底方法
public String blockHandlerTestHandler(String params, BlockException blockException) {
return "兜底返回";
}

達到閾值后,系統(tǒng)的默認提示是一段英文,很不友好,我們可以自定義兜底方法。在@SentinelResource注解中進一步配置 blockHandler、fallback 屬性字段

  • blockHandler:主觀層面,如果被限流或熔斷,則調用該方法,進行兜底處理
  • fallback:對業(yè)務的異常兜底,比如,執(zhí)行過程中拋了各種Exception,則調用該方法,進行兜底處理

通過上面兩層兜底,可以讓Sentinel 框架更加人性化,體驗更好。

注意:注解式開發(fā),需要添加在方法上,作用域范圍相對固定。下面的項目實戰(zhàn)中,我們也可以采用 顯示 形式,可以靈活圈定代碼塊范圍。

項目實戰(zhàn)

我們這邊有個項目,考慮到客戶的部署成本,想做一個輕量級方案,需求如下:

  • 既想引入框架的熔斷功能,又不想部署控制臺
  • 攔截點相對收攏,類似與dubbo消費端遠程訪問一樣,在代理類的遠程通訊位置做攔截處理

概要方案--流程圖:

1、我們通過 Proxy.newProxyInstance 為所有的接口創(chuàng)建了代理子類

2、所有對代理子類的方法調用全部收攏到 InvocationHandler

3、我們講類名和方法名做一個拼接,然后去 熔斷規(guī)則表查詢,看是否配置了規(guī)則

4、如果沒有,那么走常規(guī)則遠程調用邏輯

5、如果有,將遠程調用邏輯納入 Sentinel 的監(jiān)控管轄

6、如果觸發(fā)了 熔斷機制,則直接拋出 BlockException ,上層業(yè)務攔截異常,做特殊處理,比如:修飾下給用戶更合適的文案提示。

熔斷狀態(tài)機:

核心的代碼邏輯,繼續(xù)往下看

首先,引入 Sentinel 的依賴包:

<!-- 限流、熔斷框架 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.3</version>
</dependency>

熔斷規(guī)則表設計:

CREATE TABLE `degrade_rule` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`resource_name` varchar(256) NOT NULL COMMENT '資源名稱',
`count` double NOT NULL COMMENT '慢調用時長,單位 毫秒',
`slow_ratio_threshold` double NOT NULL COMMENT '慢調用比例閾值',
`min_request_amount` int NOT NULL COMMENT '熔斷觸發(fā)的最小請求數(shù)',
`stat_interval` int NOT NULL COMMENT '統(tǒng)計時長,單位 毫秒',
`time_window` int NOT NULL COMMENT '熔斷時長,單位為 s',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uk_resource_name` (`resource_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COMMENT='熔斷規(guī)則表';

由于放棄了部署控制臺,我們只能自己管理熔斷規(guī)則的各個屬性值??梢园雌髽I(yè)內(nèi)部管理后臺風格,開發(fā)頁面管理這些規(guī)則。

當然,早期可以采用更簡單粗暴方式,在數(shù)據(jù)庫表手動初始化數(shù)據(jù)。如果要調整規(guī)則,走 SQL 訂正。

為了盡可能實時感知規(guī)則表數(shù)據(jù)變更,開發(fā)了定時任務,每 10 秒運行一次。

@Scheduled(cron = "0/10 * * * * ? ")
public void loadDegradeRule() {
List<DegradeRuleDO> degradeRuleDOList = degradeRuleDao.queryAllRule();
if (CollectionUtils.isEmpty(degradeRuleDOList)) {
return;
}
String newMd5Hex = DigestUtils.md5Hex(JSON.toJSONString(degradeRuleDOList));
if (StringUtils.isBlank(newMd5Hex) || StringUtils.equals(lastMd5Hex, newMd5Hex)) {
return;
}
List<DegradeRule> rules = null;
List<String> resourceNameList = new ArrayList<>();
rules = degradeRuleDOList.stream().map(degradeRuleDO -> {
//資源名,即規(guī)則的作用對象
DegradeRule rule = new DegradeRule(degradeRuleDO.getResourceName())
// 熔斷策略,支持慢調用比例/異常比例/異常數(shù)策略
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
//慢調用比例模式下為慢調用臨界 RT(超出該值計為慢調用);異常比例/異常數(shù)模式下為對應的閾值
.setCount(degradeRuleDO.getCount())
// 熔斷時長,單位為 s
.setTimeWindow(degradeRuleDO.getTimeWindow())
// 慢調用比例閾值
.setSlowRatioThreshold(degradeRuleDO.getSlowRatioThreshold())
//熔斷觸發(fā)的最小請求數(shù),請求數(shù)小于該值時即使異常比率超出閾值也不會熔斷
.setMinRequestAmount(degradeRuleDO.getMinRequestAmount())
//統(tǒng)計時長(單位為 ms)
.setStatIntervalMs(degradeRuleDO.getStatInterval());
resourceNameList.add(degradeRuleDO.getResourceName());
return rule;
}).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(rules)) {
DegradeRuleManager.loadRules(rules);
ConsumerProxyFactory.resourceNameList = resourceNameList;
lastMd5Hex = newMd5Hex;
}
log.error("[DegradeRuleConfig] 熔斷規(guī)則加載: " + rules);
}

考慮到規(guī)則變更頻率不會很高,沒有必要每次都DegradeRuleManager.loadRules重新加載規(guī)則。這里設計了個小竅門

DigestUtils.md5Hex(JSON.toJSONString(degradeRuleDOList));

對查詢的規(guī)則內(nèi)容 JSON 序列化,然后計算其md5摘要,如果跟上一次的結果一致,說明這期間沒有變更,直接 return ,不做處理。

定義子類,實現(xiàn)了 InvocationHandler 接口。通過 Proxy.newProxyInstance 為目標接口創(chuàng)建一個代理子類。

這樣,每次調用接口方法,實際都是在調用 invoke 方法

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> clazz = proxy.getClass().getInterfaces()[0];
String urlCode = clazz.getName() + "#" + method.getName();
if (resourceNameList.contains(urlCode)) {
// 增加熔斷處理
Entry entry = null;
try {
entry = SphU.entry(urlCode);
// 遠程網(wǎng)絡調用,獲取結果
responseString = HttpClientUtil.postJsonRequest(url, header, body);
} catch (BlockException blockException) {
// 觸發(fā)熔斷
log.error("degrade trigger ! remote url :{} ", urlCode);
throw new DegradeBlockExcetion(urlCode);
} finally {
if (entry != null) {
entry.exit();
}
}
} else {
// 常規(guī)處理,不走熔斷判斷邏輯
// 省略
}
}

實驗數(shù)據(jù):

責任編輯:姜華 來源: 微觀技術
相關推薦

2025-05-29 03:25:00

2021-07-12 09:09:54

Go 連接池緩存

2013-03-11 10:17:13

路由協(xié)議路由器設置網(wǎng)絡連接設置

2020-09-14 06:57:30

緩存穿透雪崩

2021-04-25 09:58:48

mmapJava面試

2021-03-17 15:54:32

IO零拷貝方式

2011-08-10 16:58:35

windowsXP黑屏

2024-09-30 08:43:33

HttpgolangTimeout

2025-05-28 02:25:00

高并發(fā)緩存穿透雪崩

2018-12-13 12:43:07

Redis緩存穿透

2021-04-26 09:40:46

QPS數(shù)據(jù)庫Redis

2015-07-14 10:54:50

PHP數(shù)據(jù)循環(huán)內(nèi)存耗盡

2023-07-20 09:13:02

Jedis服務器

2024-10-24 16:51:08

2021-12-28 14:53:47

Java編程語言

2010-04-06 18:26:03

CentOS系統(tǒng)

2010-04-23 14:20:15

Aix操作系統(tǒng)

2021-12-26 18:24:51

MySQL InnoDB引擎

2024-03-28 08:32:10

美團關閉訂單輪訓

2012-09-05 11:09:15

SELinux操作系統(tǒng)
點贊
收藏

51CTO技術棧公眾號