1. 程式人生 > >微服務的設計原則

微服務的設計原則

呼叫鏈中的異常處理

假設微服務serviceA的介面interfaceA被微服務serviceB呼叫,如果interfaceA在呼叫過程中會丟擲異常,那麼是否該將該異常以狀態碼傳給serviceB呢?

對於RPC來說(如Feign),會自動將被呼叫的遠端介面的異常在呼叫方以異常丟擲;對於Rest Api來說,可以將異常包裝到response的out中。


我建議serviceB在呼叫interfaceA時,判斷interfaceA是否出現異常應該儘量不要依賴於判斷interfaceA返回的狀態碼。因為讀取狀態碼是要獲取response物件,而這樣會造成程式碼不必要的拖沓。
儘量不要這麼寫:

@GetMapping(path = "/interfaceA")
public String methodA(@RequestParam String input)throw SomeException{
    ...
    return res;
}

應該這麼寫:

@GetMapping(path = "/interfaceA")
public String methodA(@RequestParam String input){
    try{
        ...
    }catch(SomeException e){
        logger.error("error reason"
, e); return "error reason"; } return res; }

這樣,出現異常時候,可以在serviceA記錄異常原因,同時將異常原因返回給serviceB,這樣serviceB可以通過返回字串來判斷是否執行成功。
而對於返回物件的介面,則可以在出現異常時通過返回null來告訴serviceB調用出現異常。

另外:

- 介面能返回String儘量不要返回Boolean,應該讓serviceB儘可能知悉異常原因。(返回物件就沒辦法了)
- 如果interfaceA只有前端呼叫,interfaceA丟擲異常返回狀態碼也是可以的(不過誰能保證interfaceA以後不被其他微服務呼叫呢?)

介面路徑定義原則

介面路徑

應該儘量將傳遞的變數input放在RequestParam

@GetMapping(path = "/interfaceA")
public String methodA(@RequestParam String input){
    ...
    return res;
}

即使要放在path也應該這樣:

@GetMapping(path = "/interfaceA/{input}")
public String methodA(@PathVariable("input") String input){
    ...
    return res;
}

而不應該這樣放在path:

@GetMapping(path = "/{input}/interfaceA")

我們應該儘可能保證可以通過某種方式形成路徑命名子空間,從而隔離開各個介面,方便dispatcher分派request。第三種方式容易造成路徑命名子空間汙染。