Exception 과 Result
분포 식 시스템 개발 에서 우 리 는 다양한 상태 코드, 오류 정 보 를 최 외층 의 호출 자 에 게 전달 해 야 한다. 이 호출 자 는 보통
http/api
인터페이스, 오류 정보
,
등 이다.가장 바깥쪽 인터페이스 에 노출 된 데 이 터 는 보통
{code, msg, data}
과 같은 json
형식 이라는 점 에서 논란 이 되 지 않 는 다.그러나 분포 식 시스템 의 노드 간 RPC 호출, 노드 내부 방법 호출 에서 보통
ServiceException
또는 Result
방식 으로 잘못된 정 보 를 전달 하 는데 이 두 가지 방식 은 어떤 차이 가 있 고 어느 것 이 좋 고 어느 것 이 나 쁜 가?본 고 는
과
이 문 제 를 연구 하 는 데 중심 을 두 었 다.Result
소개이것 은 비교적 흔히 볼 수 있 는 잘못된 정보 전달 방식 으로 일부 공장 은 심지어 이 를 기술 규범 으로 설정 하여 각 팀 에 게 이런 방식 을 사용 하도록 강요한다.일반적인 Result 템 플 릿 은 다음 과 같 습 니 다.
@Data
public class Result {
private int code; // String
private String msg;
private T data;
}
시스템 개발 에서 의 응용 은 보통 다음 과 같다.
Result userModelResult = userService.query(userId);
if (!userModelResult.isSuccess() || userModelResult.getData != null) {
return Result.fail(userModelResult); //
}
UserModel userModel = userModelResult.getData();
if (userModel.getStatus() != UserStatusEnum.NORMAL) {
return Result.fail("user unavaliable"); //
}
// ... UserModel
비교적 복잡 한 분포 식 마이크로 서비스 환경 에서 유사 한 코드 가 매우 많 고 서비스 에 의존 하 는 모든 호출 은 유사 한 오류 논리 와 수반 된다.
이러한 패턴 은 유사
Golang
언어 에서 의 오류 코드 처리 와 유사 하 다. 이것 은 Golang 이 비교적 비난 을 받 는 부분 이다. 즉, 모든 단계 에서 잘못된 판단 을 해 야 한 다 는 것 이다.더 가혹 한 현실 은
Result
패키지 가 있 음 에 도 불구 하고 백 엔 드 시스템 Exception
이 전달 되 는 것 이다.제 가 접 한 실제 응용 프로그램 에서 이러한 돌파 Result
봉 인 된 이상 한 스 포 일 러 는 사례 가 아 닙 니 다. 제 가 맡 은 시스템 은 더 백 엔 드 의 국내 최 강 거래 시스템 을 호출 할 때 가장 내부 거래 센터 TC 의 업무 이상 을 받 은 적 이 있 습 니 다. 문 제 를 조사 할 때 추적 하 는 팀 만 5 개가 아 닙 니 다.ServiceException
소개말 그대로 정상 논리 와 이상 논 리 를 분리 하 는 방식 이다.
시스템 개발 에서 대부분의 오 류 는 서 비 스 를 직접 중단 하고 오 류 를 사용자 에 게 직접 피드백 해 야 한다. 그 렇 기 때문에 우 리 는
을 사용 할 때 유사 한 Result
코드 를 자주 써 야 한다.그리고 if(result.isFail()){return…}
을 사용 하면 우 리 는 비슷 한 코드 의 대부분 을 생략 할 수 있다.보통
ServiceException
은 이렇게 정의 할 수 있다.@Getter
public class ServiceException extends RuntimeException {
private final int code;
private final String msg;
public ApiException() {
this(-1, null);
}
public ApiException(Code code) {
this(code, null);
}
public ApiException(Code code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
}
시스템 내부 구성 요 소 는
ServiceException
,
,
,
등 이상 상황 을 만 났 을 때 직접
논 리 를 중단 한 다음 에 가장 바깥쪽 ServiceException
또는 Filter
에서 이상 을 포착 하여 그 중의 Aspect
와 code
을 추출 하여 사용자 에 게 되 돌려 준다.실제 사용 하 는 코드 논 리 는 다음 과 같 습 니 다.
UserModel userModel = userService.query(userId); // userID 、
// ... userModel
이런 방식 은 현저히 우아 하고 간소화 되 어 개발 효율 의 향상 과 후기 유지 에 도움 이 된다.
그러나 이상 중단 을 사용 하면 성능 에 영향 을 미 칠 수 있다 는 소문 이 돌 고 있 으 며, 간단 한 성능 테스트 를 통 해 이상 중단 성능 을 내 놓 는 데 걸 리 는 시간 이 Result 로 돌아 가 는 것 보다 수백 배 나 빠르다 는 소문 도 있다.
성능 테스트
성능 문제 에 대해 저도 간단 한 테스트 를 했 습 니 다. 구체 적 인 테스트 코드 는 다음 과 같 습 니 다.
https://github.com/sisyphsu/b...
여기 서
msg
를 사용 하여 성능 테스트 를 실시 합 니 다. JMH
라 고 하면 정말 부 럽 습 니 다 benchmark
언어 자체 golang
라 이브 러 리 가 부 럽 습 니 다. 정말 편리 합 니 다.내부 의 업무 논 리 를 테스트 하 는 것 은 매우 간단 하 다. 단지 한 번
test
을 호출 하고 시간 표를 되 돌려 준다.성능 테스트 에 서 는 각각
System.currentTimeMillis()
반환 값 과 던 지기 long
를 사용 하여 이상 한 성능 테스트 를 던 지고 서로 다른 깊이 의 호출 스 택 테스트 를 추가 합 니 다. 이것 은 Result
이상 을 던 질 때 현재 Exception
의 스 택 을 분석 해 야 하기 때 문 입 니 다. 호출 스 택 이 깊 을 수록 성능 손실 이 크기 때 문 입 니 다.구체 적 인 창고 깊이 추출 값 은 1, 10, 100:Test.test avgt 5 0.027 ± 0.001 us/op
Test.testException avgt 5 1.060 ± 0.045 us/op
Test.testDeep10Exception avgt 5 1.826 ± 0.122 us/op
Test.testDeep100Exception avgt 5 9.802 ± 0.411 us/op
얼핏 보면 이상 스 택 깊이 가 100 인 성능 손실 은 일반 방법 에서 사용 하 는 360 배 이 고 어떤 사람들 은 이런 이유 로 자바 의 이상 중단 성능 손실 이 심각 하 다 는 결론 을 내 렸 다.
성능 의 영향 을 분석 하 다
그러나 주의해 야 할 시간 단 위 는 마이크로 초 일 뿐 밀리초 의 1000 분 의 1, 초의 백만 분 의 1 이다.
만약 에 특정한 마이크로 서비스 단일 CPU 의 스루풋 이 1000 QPS 이 고 그 중 10% 가 불법 요청 이 라 고 가정 하면 이상 하 게 중 단 된 성능 손실 도 만 분 의 1 에 불과 하고 서비스 소모 에 대한 영향 도 0.001 밀리초 에 불과 하 다.
성능 테스트 에서
Java
는 시스템 시간 만 얻 을 뿐 대략 Thread
소모 된다.그 렇 기 때문에 이상 하 게 중 단 된 성능 손실 이 공포 의 '수백 배' 에 이 르 렀 다. 그러나 업무 소모 시간 이
에서 25ns
, 25ns
로 바 뀌 면?성능 병목 재 론
우 리 는 시스템 성능 을 분석 할 때 반드시 그의 수량 급 과 성능 병목 을 파악 하고 성능 최적화 의 곤경 에 빠 진 것 을 기억 해 야 한다.
예 를 들 어 일반적인 서비스 에서 색인 을 이용 한 DB 작업 은 1 ~ 10 밀리초 사이 이 고 분포 식 Cache 를 방문 하 는 데 걸 리 는 시간 은 3 ~ 30 밀리초 사이 이 며 마이크로 서비스 RPC 의 네트워크 성능 손실 은 3 ~ 10 밀리초 사이 이 며 클 라 이언 트 와 서버 간 의 네트워크 소모 시간 은 5 ~ 300 밀리초 사이 이다.이런 상황 에서 0.001 밀리초 의 성능 을 최적화 하 는 위험 은 참깨 를 주 워 수박 을 잃 어 버 리 는 것 과 다름없다.
저 는 TCP 와 유사 한 바 텀 네트워크 프로 토 콜 을 쓴 적 이 있 습 니 다. 그런 고주파 장면 에서 알고리즘 최적화 가 0.1 초 동안 의 성능 최적화 를 가 져 온 것 은 매 초 스루풋 이 몇 할, 심지어 몇 배의 향상 을 의미 하지만 분포 식 호출 의 저주파 장면 에서 이런 성능 은 쓸모 가 없습니다.
또 다른 예 로 몇 년 전에 저 와 동료 들 이 DB 데이터 시트 디자인 을 토론 할 때 주문 상태 에서 어떤 길 이 를 사용 하 는 지
25us
때문에 다 투 는 얼굴 이 빨 개 지고 목이 굵 었 습 니 다. 지금 생각해 보면 주문 상태 에서 최 적 화 된 1 개의 바이트 도 오 랜 세월 동안 1MB 의 디스크 공간 을 절약 하지 못 했 을 뿐 무슨 소 용이 있 습 니까?RPC 의 이상 중단
Dubbo, HSF 와 같은 원 격 호출 프레임 워 크 를 사용 할 때 이상 중단 을 사용 하여 잘못된 정 보 를 전달 하 는 데 주의해 야 할 것 은 이상 유형 이 통용 되 는, 즉 각 마이크로 서비스 가 인용 하 는 기본 유형 으로 설계 되 어야 한 다 는 것 이다.
모 공장 의 기술 규범 에서 다음 과 같이 말 했다.
1) 이상 반환 방식 을 사용 하여 호출 자가 캡 처 하지 않 으 면 실행 중 오류 가 발생 합 니 다.
2) 스 택 정 보 를 추가 하지 않 고 new 사용자 정의 이상 일 뿐 이해 하 는 error message 를 추가 하면 호출 단 에서 문 제 를 해결 하 는 데 도움 이 되 지 않 습 니 다.스 택 정 보 를 추가 하면 자주 호출 오류 가 발생 하 는 상황 에서 데이터 직렬 화 와 전송 성능 손실 도 문제 다.
나 는 이런 기술 규범 에 대해 상당히 그렇게 생각 하지 않 는 다.
우선 업무 이상 은 원래 호출 자가 최 외층 에 전달 해 야 한다. 예 를 들 어
25ms
, int
,
등 이상 은 중간의 호출 자가 포착 해도 소 용이 없다.그 다음은 허튼소리
이다. 이런 저주파 데이터 의 직렬 화 와 내부 망 전송 은 어떤 성능 손실 이 있 을 까?스 택 정 보 를 호출 자 에 게 전달 하 는 것 도 고장 검사 에 도움 이 됩 니 다. 저 는 TC 의 이상 스 택 정 보 를 받 은 적 이 있 습 니 다. 스 택 에 있 는 package 에 따라 3, 4 층 을 돌아 서 바 텀 오류 가 발생 한 곳 을 찾 았 습 니 다. 많은 시간 을 절약 했다 고 할 수 있 습 니 다.결론.
분포 식 마이크로 서비스 에서 이상 중단 을 사용 하면 업무 코드 를 대폭 간소화 할 수 있 고 성능 에 미 치 는 영향 도 미미 하 다.
보조
,
등 주석 으로 분포 식 개발 을 바람 처럼 빠 르 고 편리 하 게 할 수 있다.복잡 한 서비스 네트워크 에서 업무 이상 도 개발 자 들 이 정확 한 포 지 셔 닝 오 류 를 쉽게 찾 을 수 있 고 사람들 이 체인 을 따라 고장 점 을 추적 하 는 난처 한 상황 을 피 할 수 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
nginx 학습 - 입문 부터 정통 까지Nginx 는 고성능 HTTP 와 역방향 프 록 시 서버 nginx 는 정적 파일 을 잘 처리 하고 메모리 소모 가 적 습 니 다 클 라 이언 트 는 프 록 시 서버 와 목표 서버 가 모두 누구 인지 파악 합 니 다...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.