Heim  >  Artikel  >  Backend-Entwicklung  >  So verwenden Sie Ausnahmen in der Microservice-Architektur richtig

So verwenden Sie Ausnahmen in der Microservice-Architektur richtig

醉折花枝作酒筹
醉折花枝作酒筹nach vorne
2021-06-17 17:24:231831Durchsuche

In diesem Artikel erfahren Sie, wie Ausnahmen in der Microservice-Architektur korrekt verwendet werden. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.

So verwenden Sie Ausnahmen in der Microservice-Architektur richtig

Die korrekte Verwendung von Ausnahmen gehört zu den drei wichtigsten in der Microservice-Architektur.

Die korrekte Verwendung von Ausnahmen gehört zu den drei wichtigsten in der Microservice-Architektur Ich habe keine Meinung.

Curdboy Lange nicht gesehen, ich wünsche euch allen ein frohes Drachenbootfest. Ich möchte kürzlich über Ausnahmen sprechen. Ich hoffe, dass diese Kombination für Ihren Geschäftscode hilfreich sein kann.

Im Folgenden werden nur die besten Sprachen der Welt und die ökologisch vollständigsten Sprachen besprochen.

Ähnlichkeiten und Unterschiede von Ausnahmen

Das Ausnahmedesign von PHP in PHP7 stimmt mit Java Exception erweitert Throwable überein, es gibt jedoch immer noch einige subtile Unterschiede in den historischen Gründen und Designkonzepten. Ausnahmen in PHP verfügen beispielsweise über Codeattribute, sodass mehrere Ausnahmen in derselben Ausnahme geclustert werden und dann entsprechend dem Code im Catch-Block unterschiedliche Geschäftslogikcodes geschrieben werden.

Java-Ausnahmen haben keinen Code und können nicht auf diese Weise entworfen werden. Unterschiedliche Ausnahmen können nur für unterschiedliche Situationen verwendet werden. Daher sind wir es gewohnt, Dienste durch Verpackungsklassen zu kapseln, wenn sie der Außenwelt ausgesetzt werden, anstatt uns direkt auf die transparente Übertragung von Ausnahmen zu verlassen.

Einheitliche Ausnahmebehandlung

Am meisten kritisiert wird am Java-Code die zahlreichen Try-Catches. Ich habe keine Einwände. Schnappen Sie sich einfach ein Stück Code

@Override
public DataResult<List<AdsDTO>> getAds(Integer liveId) {
    
    try {
        List<AdsDTO> adsDTO = new ArrayList<>();
        //...业务逻辑省略
        DataResult.success(adsDTO);
    } catch (Exception e) {
        log.error("getAds has Exception:{}", e.getMessage(), e);
        DataResult.failure(ResultCode.CODE_INTERNAL_ERROR, e.getMessage()); // 将异常信息返回给服务端调用方
    }
    
    return dataResult;
}

Oft schreibe ich einfach einen Try-Catch, ohne darüber nachzudenken, unabhängig davon, ob darin Nicht-Laufzeit-Ausnahmen enthalten sind. Eine bessere Möglichkeit besteht darin, aop zu verwenden, um alle Aufrufe von Servicemethoden abzufangen, Ausnahmen einheitlich zu übernehmen und zu behandeln.

@Around("recordLog()")
public Object record(ProceedingJoinPoint joinPoint) throws Throwable {
  //... 请求调用来源记录
  
  Object result;

  try {
    result = joinPoint.proceed(joinPoint.getArgs());
  } catch (Exception e) {
    //... 记录异常日志
    
    DataResult<Object> res = DataResult.failure(ResultCode.CODE_INTERNAL_ERROR, e.getMessage());
    result = res;
  }

    //... 返回值日志记录
  
  return result;
}

Es gibt ein kleines Problem, wenn die Ausnahmeinformationen von Dienst A direkt an Anrufer B zurückgegeben werden. Dem Anrufer kann man niemals vertrauen, selbst wenn er ein armer Bauer der dritten Generation ist. Da nicht sicher ist, wie der Aufrufer mit der Fehlermeldung umgeht, wird sie möglicherweise direkt als JSON an das Frontend zurückgegeben.

RuntimeException

Ausnahmen in Java können in Laufzeitausnahmen und Nicht-Laufzeitausnahmen unterteilt werden, und es ist nicht erforderlich, die Methode „throw Exception“ zu markieren guava-Paket in der Methode In der Preconditions-Toolklasse ist die ausgelöste IllegalArgumentException auch eine Laufzeitausnahme.

@Override
public DataResult<List<AdsDTO>> getAds(Integer liveId) {
  Preconditions.checkArgument(null != liveId, "liveIds not be null");
  
  List<AdsDTO> adsDTOS = new ArrayList<>();
  //...业务逻辑省略
  return DataResult.success(adsDTOS);
}

Wir können diese Funktion auch verwenden, um unsere eigene Geschäftsausnahmeklasse so anzupassen, dass sie RuntimeException erbt.

XXServiceRuntimeException extends RuntimeException

In Situationen, die nicht der Geschäftslogik entsprechen, werfen wir direkt XXServiceRuntimeException

@Override
public DataResult<List<AdsDTO>> getAds(Integer liveId) {

  if (null == liveId) {
    throw new XXServiceRuntimeException("liveId can&#39;t be null");
  }
  
  List<AdsDTO> adsDTOS = new ArrayList<>();
  //...业务逻辑省略
  return DataResult.success(adsDTOS);
}

und führen dann eine einheitliche Verarbeitung in AOP durch und machen entsprechend Für den vorherigen Vergleich besteht ein grober Ansatz darin, andere Ausnahmen als XXServiceRuntimeException und IllegalArgumentException intern aufzuzeichnen und sie nicht mehr der Außenwelt zugänglich zu machen. Sie müssen jedoch daran denken, die verteilten Links über die requestId aneinanderzureihen und sie im DataResult zurückzugeben erleichtern die Fehlerbehebung.

@Around("recordLog()")
public Object record(ProceedingJoinPoint joinPoint) throws Throwable {
  //... 请求调用来源记录
  
  Object result;

  try {
    result = joinPoint.proceed(joinPoint.getArgs());
  } catch (Exception e) {
    //... 记录异常日志①
    log.error("{}#{}, exception:{}:", clazzSimpleName, methodName, e.getClass().getSimpleName(), e);
    
    DataResult<Object> res = DataResult.failure(ResultCode.CODE_INTERNAL_ERROR);
    if (e instanceof XXServiceRuntimeException || e instanceof IllegalArgumentException) {
       res.setMessage(e.getMessage());
    }
 
    result = res;
  }

  if (result instanceof DataResult) {
      ((DataResult) result).setRequestId(EagleEye.getTraceId()); // DMC 
  }

    //... 返回值日志记录
  
  return result;
}

Abnormale Überwachung

Was die geschlossene Schleife betrifft, kann nach Verwendung der benutzerdefinierten Ausnahmeklasse der Schwellenwert für die Überwachung und Alarmierung für abnormale Protokolle erheblich reduziert werden, und die Alarmierung ist genauer. Nehmen Sie die Überwachung von Alibaba Cloud SLS als Beispiel

* and ERROR not XXServiceRuntimeException not IllegalArgumentException|SELECT COUNT(*) AS count

Was hier überwacht wird, ist das Protokoll, das das Ausnahmeprotokoll aufzeichnet①

Ausnahmen in PHP

Die oben in Java erwähnten Probleme treten auch in PHP auf, wenn Sie nicht 3 Methoden zur Simulation von AOP verwenden , Sie können nicht glauben, dass PHP die weltweit führende Sprache ist

//1. call_user_func_array
//2. 反射
//3. 直接 new
try {
  $class = new $className();
  $result = $class->$methodName();
} catch (\Throwable $e) {
    //...略
}

Ähnlich wie bei der oben genannten Architekturlogik müssen Sie keinen Pseudocode mehr schreiben und bleiben im Grunde derselbe. Es ist auch möglich, Ihre eigene Geschäftsausnahmeklasse so anzupassen, dass sie RuntimeException erbt, und dann eine externe Ausgabeverarbeitung durchzuführen.

Aber es gibt einige historische Probleme in PHP. Als es ursprünglich entworfen wurde, wurden viele Laufzeitausnahmen als Hinweis- und Warnfehler ausgegeben, aber in der Fehlerausgabe fehlte ein Aufrufstapel, was der Fehlerbehebung nicht förderlich war Die spezifischen Parameter und der Aufrufstapel sind nicht sichtbar. Wenn Sie set_error_handler + ErrorException verwenden, ist dies sehr klar.

function foo(){
  return boo("xxx");
}

function boo($a){
  return explode($a);
}

foo();

Die letzten gedruckten Informationen sind

Warning: explode() expects at least 2 parameters, 1 given in /Users/mengkang/Downloads/ab.php on line 8

Wenn Sie die obige Funktion

set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 10001, $severity, $file, $line);
});

function foo(){
  return boo("xxx");
}

function boo($a){
  return explode($a);
}

try{
  foo();
}catch(Exception $e){
  echo $e->getTraceAsString();
}

ändern, kann sie nicht erfasst werden, da es sich um PHP handelt. Schwerwiegender Fehler: Uncaught TypeError, PHP7 hat hinzugefügt

class Error implementiert Throwable, dann in PHP Es wird einen Stack im Systemfehlerprotokoll geben, dieser kann jedoch nicht in Reihe mit dem gesamten Geschäftssystem verbunden werden. Hier müssen wir über das Design des Protokolls sprechen. Wir hoffen, alle Protokolle über eine Trace-ID wie Java zu verbinden Nginx-Protokolle werden in PHP-Info-Level-Protokollen und nicht abgefangenen TypeErrors protokolliert. Übernehmen Sie daher die Standardausgabe in das Systemfehlerprotokoll und zeichnen Sie sie an einer einheitlichen Stelle im Catch-Codeblock auf. Dann ändern Sie es hier einfach in

Fatal error: Uncaught ErrorException: explode() expects at least 2 parameters, 1 given in /Users/mengkang/Downloads/ab.php:12
Stack trace:
#0 [internal function]: {closure}(2, &#39;explode() expec...&#39;, &#39;/Users/mengkang...&#39;, 12, Array)
#1 /Users/mengkang/Downloads/ab.php(12): explode(&#39;xxx&#39;)
#2 /Users/mengkang/Downloads/ab.php(8): boo(&#39;xxx&#39;)
#3 /Users/mengkang/Downloads/ab.php(15): foo()
#4 {main}
  thrown in /Users/mengkang/Downloads/ab.php on line 12

catch Throwable, um Fehler und Ausnahmen zu akzeptieren.

Aber set_error_handler kann einige Fehler nicht verarbeiten, z. B. E_PARSE-Fehler. Sie können register_shutdown_function verwenden, um damit umzugehen.

值得注意的是register_shutdown_function的用意是在脚本正常退出或显示调用exit时,执行注册的函数。
是脚本运行(run-time not parse-time)出错退出时,才能使用。如果在调用register_shutdown_function的同一文件的里面有语法错误,是无法注册的,但是我们项目一般都是分多个文件的,这样就其他文件里有语法错误,也能捕获了
register_shutdown_function(function(){
    $e = error_get_last();
    if ($e){
        throw new \ErrorException($e["message"], 10002, E_ERROR, $e["file"], $e["line"]);
    }
});

如果你想直接使用这些代码(PHP的)直接到项目可能会有很多坑,因为我们习惯了系统中有很多  notice 了,可以将 notice 的错误转成异常之后主动记录,但是不对外抛出异常即可。

推荐学习:php视频教程

Das obige ist der detaillierte Inhalt vonSo verwenden Sie Ausnahmen in der Microservice-Architektur richtig. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen