MSHA控制臺提供在切流前或者切流結束后添加自定義動作的功能,支持切流前或者切流結束后進行業(yè)務自定義接口的回調,即支持添加自定義回調接口的前置或者后置動作。本文介紹如何添加前置或者后置的自定義動作。
使用限制
一個多活實例下,最多允許配置5個自定義動作。
操作步驟
登錄多活容災MSHA控制臺。
在左側導航欄,單擊多活實例。
在多活實例頁面,單擊目標實例的實例名稱/ID進入多活實例詳情頁面。
在多活實例詳情頁面,單擊
。在自定義動作頁面,單擊添加,配置以下參數。
參數
描述
回調URL
回調接口的URL:
管控與此URL根IP具備網絡連通性,建議測試網絡連通性后再進行配置。
URL需要包含協議頭,例如:
http://xx.domain.com/yy
。
前置/后置
回調接口的自定義切流動作,包括:
前置動作:阻塞回調接口的動作。當滿足一定的阻塞條件時,允許回調該接口后再進行切流動作,需要配置阻塞條件。
后置動作:觸發(fā)回調接口的動作。當滿足一定的觸發(fā)條件時,允許等待切流動作結束后再回調該接口,需要配置觸發(fā)條件。
一個多活實例下,既可以配置前置動作,也可以配置后置動作。
阻塞配置/觸發(fā)條件
阻塞配置:若選擇的是前置自定義切流動作,需要選擇阻塞配置。
等待成功:HTTP接口返回2xx后才繼續(xù)執(zhí)行切流。
等待結束:HTTP接口只要返回結果就繼續(xù)執(zhí)行切流,不管結果成敗。
等待失敗:HTTP接口返回2xx以外結果后才繼續(xù)執(zhí)行切流。
忽略結果:異步調用HTTP接口后立即繼續(xù)執(zhí)行切流,忽略結果。
觸發(fā)條件:若選擇的是后置自定義切流步驟,需要選擇觸發(fā)條件。
切流成功:切流成功才調用此接口。
切流結束:切流結束就調用此接口(無論成功還是異常)。
切流失?。呵辛魇〔耪{用此接口,僅切流異常結束后觸發(fā)。
忽略結果:異步調用HTTP接口后立即繼續(xù)執(zhí)行切流,忽略切流結果。
HTTP請求方法
回調采用的HTTP/HTTPS請求方法。枚舉值為:GET、POST。
安全摘要鹽值
鹽,用于對回調請求生成安全摘要。
生效
是否執(zhí)行回調接口的自定義切流動作。包括:
是:執(zhí)行當前的自定義動作。
否:暫不執(zhí)行當前的自定義動作。
應用架構
當前實例中包含的應用架構。包括:
異地雙活
同城多活
異地應用雙活
單擊保存,在彈出的對話框中單擊確認。
其他操作:
刪除:單擊操作列的刪除,刪除該自定義動作。
修改:單擊操作列的修改,修改該自定義動作。
規(guī)范
使用自定義動作功能時,回調接口需要滿足以下規(guī)范。
回調接口需是HTTP/HTTPS協議。
回調接口需要免登,即不做登錄態(tài)校驗。
回調接口不能有CSRF Token校驗。
回調接口參數名需要遵循以下名稱規(guī)范。MSHA控制臺發(fā)起回調時,用戶需要勾選以下名稱的參數,包含了切流工單基本信息和安全校驗摘要。
參數
參數描述
mshaTenantId
多活實例ID。
id
切流工單ID。
name
切流工單名稱。
sourceUnitFlag
切流源單元標識,表示從sourceUnitFlag->向targetUnitFlag切流。
targetUnitFlag
切流目的單元,表示從sourceUnitFlag->向targetUnitFlag切流。
status
切流結束狀態(tài)。
正常結束狀態(tài)枚舉值為:
complete:正常結束。
canceled:人為取消終止。
異常結束狀態(tài)枚舉值為:
autoCanceled:異常后自動取消終止(回滾完成)。
cancelFailed:取消失敗。
closed:強制關閉(不繼續(xù)執(zhí)行也不回滾)。
fail:其他情況異常終止。
completeTime
切流結束時間。
changeTokenRange
當范圍類型切流時,切流變更的范圍區(qū)間。當非范圍類型切流時,值為空字符串("")。
格式:[$區(qū)間開始,$區(qū)間結束],其中 [] 括號表示數學上的閉區(qū)間(固定為閉區(qū)間,不會有開區(qū)間或半開區(qū)間的情況)。
Java語言賦值樣例:
String changeTokenRange="[1,9999]";
。changeTokenList
當精準類型切流時,切流變更的精準名單。當非精準類型切流時,值為空字符串("")。
格式:以英文半角逗號隔開的精準名單。
Java語言賦值樣例:
String changeTokenList="11,22,33";
。digest
安全摘要,用于驗證調用是否可信以及參數防篡改。
回調接口樣例
以下是Java語言版本,使用Spring MVC框架的編寫的回調接口樣例:
@RestController
@RequestMapping("/demo")
@Slf4j
public class DemoController {
@RequestMapping(path = "/switchEndCallback", method = {RequestMethod.POST, RequestMethod.GET})
public void switchEndCallback( @RequestParam String mshaTenantId,
@RequestParam String id,
@RequestParam String name,
@RequestParam String sourceUnitFlag,
@RequestParam String targetUnitFlag,
@RequestParam String status,
@RequestParam String completeTime,
@RequestParam String changeTokenRange,
@RequestParam String changeTokenList,
@RequestParam String digest) throws Exception {
//do something
}
}
校驗調用來源是否可信
MSHA控制臺接口回調時,會帶上digest安全摘要參數,用于驗證調用來源是否可信以及參數防篡改。校驗流程如下:
自定義一個digestSalt值,并將digestSalt配置到MSHA控制臺切流結束回調接口信息中。
切流結束后,接口調用者(MSHA控制臺)將發(fā)起接口回調,使用digestSalt和回調參數生成摘要digest,并在回調時帶上該digest參數。
接口提供者(業(yè)務應用/業(yè)務系統)接收到回調接口時,使用跟步驟2一樣的方式生成期望的摘要expectedDigest,跟回調參數中的摘要digest做比較。若完全相同表示驗證通過,調用來源是否可信且參數沒有被篡改。
說明僅當接口調用者和接口提供者都使用相同的鹽值和參數生成的摘要才會驗證通過。
使用示例如下:
@RestController
@RequestMapping("/demo")
@Slf4j
public class DemoController {
@RequestMapping(path = "/switchEndCallback", method = {RequestMethod.POST, RequestMethod.GET})
public Object switchEndCallback(@RequestParam String mshaTenantId,
@RequestParam String id,
@RequestParam String name,
@RequestParam String sourceUnitFlag,
@RequestParam String targetUnitFlag,
@RequestParam String status,
@RequestParam String completeTime,
@RequestParam String changeTokenRange,
@RequestParam String changeTokenList,
@RequestParam String digest) throws Exception {
//使用TreeMap保證后續(xù)拼接的StringBuilder是固定順序的。
TreeMap<String, String> sortedParamMap = new TreeMap<>();
sortedParamMap.put("mshaTenantId", mshaTenantId);
sortedParamMap.put("id", id);
sortedParamMap.put("name", name);
sortedParamMap.put("sourceUnitFlag", sourceUnitFlag);
sortedParamMap.put("targetUnitFlag", targetUnitFlag);
sortedParamMap.put("status", status);
sortedParamMap.put("completeTime", completeTime);
sortedParamMap.put("changeTokenRange", changeTokenRange);
sortedParamMap.put("changeTokenList", changeTokenList);
log.info("switchEndCallback params:" + sortedParamMap);
//鹽值,在請求參數生成安全摘要時使用,用于驗證調用來源是否可信。
String digestSalt = "kbBO1nD1BM_Ymr76XOoZkbJ72k4";
StringBuilder paramsStringBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : sortedParamMap.entrySet()) {
paramsStringBuilder.append(entry.getValue());
}
paramsStringBuilder.append(digestSalt);
//推薦使用commons-codec:commons-codec:jar:1.10(或以上版本)DigestUtils來生成md5哈希摘要。
String expectedDigest = org.apache.commons.codec.digest.DigestUtils.md5Hex(paramsStringBuilder.toString().getBytes("utf-8"));
//只有接口調用者和接口提供者,都使用相同鹽值、相同的參數生成的摘要才會驗證通過。
boolean digestCheckPassed = digest.equalsIgnoreCase(expectedDigest);
log.info("switchEndCallback digestCheckPassed:{}", digestCheckPassed);
return "switchEndCallback returned success";
}
}