? 왜 타임아웃 제어가 필요한가요?
많은 계단식 실패 시나리오에서 흔히 발생하는 문제는 서버가 이미 클라이언트의 기한을 초과한 요청을 처리하기 위해 많은 리소스를 소비하고 있다는 것입니다. 그 결과 서버는 귀중한 작업을 수행하지 않고 많은 리소스를 소비하게 됩니다. 응답 시간이 초과되었습니다. 요청이 의미가 없습니다. 타임아웃 제어는 서비스 안정성을 보장하는 중요한 방어선이라고 할 수 있습니다. 그 본질은 빠른 실패를 방지하는 것입니다. 좋은 타임아웃 제어 전략은 지연 시간이 높은 요청을 최대한 빨리 처리하고 리소스를 최대한 빨리 해제할 수 있습니다. 요청이 누적됩니다.
서비스 간 시간 초과 전달
요청에 일련의 RPC 호출과 같이 여러 단계가 있는 경우 서비스는 낭비되는 작업을 피하기 위해 각 단계가 시작되기 전에 마감일을 확인해야 합니다. 요청을 처리하는 데 충분한 시간이 남아 있습니다. 일반적인 구현 오류는 각 RPC 서비스에 고정된 시간 초과를 설정하는 것입니다. 시간 초과는 서비스 호출의 최상위 수준에서 설정할 수 있으며 전체 RPC는 초기 요청에 의해 트리거됩니다. 트리는 동일한 절대 기한을 설정합니다. 예를 들어 서비스 요청의 최상위 수준에서 시간 초과를 3초로 설정하면 서비스 A가 서비스 B를 요청합니다. 서비스 B는 실행하는 데 1초가 걸리고 서비스 B는 서비스 C를 요청합니다. 이 때 시간 초과 기간은 서비스 C로 유지됩니다. 서비스 C가 서비스 D를 요청하면 서비스 D는 실행하는 데 500ms가 소요됩니다. 이상적으로는 전체 호출 체인에서 동일한 시간 초과 전달 메커니즘이 사용됩니다.
시간 초과 전달 메커니즘을 사용하지 않으면 다음 상황이 발생합니다.
서비스 A가 서비스 B에 요청을 보내고 설정된 시간 초과는 3초입니다.
서비스 B가 요청을 처리하는 데 2초가 걸리며, 계속 서비스 C 요청
- 타임아웃 전달을 사용하는 경우 서비스 C의 타임아웃 시간은 1초여야 하는데 여기서는 타임아웃 전달을 사용하지 않으므로 구성에 타임아웃 시간이 3초로 하드 코딩되어 있습니다
- 서비스 C의 지속적인 실행 실제로 2초가 걸립니다. 이때 최상위 계층에서 설정한 제한 시간이 만료되었으며 다음 요청은 의미가 없습니다
- 계속해서 서비스 D를 요청하세요
- 서비스 B가 시간 제한 전달 메커니즘을 채택하면 요청이 이루어져야 합니다. 클라이언트가 오류를 보고했을 수 있으므로 서비스 C에서는 즉시 중단됩니다. 타임아웃 전달을 설정할 때 일반적으로 네트워크 전송 시간과 클라이언트가 응답을 받은 후 처리 시간을 고려하기 위해 전달 기한을 약간(예: 100밀리초) 단축합니다.
-
프로세스 내 타임아웃 전송
서비스 간 타임아웃 전송은 물론, 프로세스 내 타임아웃 전송도 필요합니다. 예를 들어 Mysql, Redis, 서비스 B는 하나의 프로세스에서 순차적으로 호출되어 전체 요청이 발생합니다. 시간은 3초로 설정되며, MySQL은 1초가 소요되고 Redis를 다시 요청합니다. Redis 실행은 500ms가 소요된 다음 서비스 B를 요청합니다. 각 미들웨어 또는 서비스는 구성에서 고정 값을 설정하므로 시간 초과는 1.5초입니다. 타임아웃 시간은 남은 시간과 설정된 시간의 최소값을 취해야 합니다.
컨텍스트는 시간 초과 전달을 구현합니다
컨텍스트의 원리는 매우 간단하지만 그 기능은 매우 강력합니다. Go의 표준 라이브러리도 컨텍스트 지원을 구현했으며, 다양한 오픈 소스 프레임워크도 컨텍스트 지원을 구현했습니다. , 컨텍스트가 표준이 되었으며 시간 초과 전달도 컨텍스트에 의존합니다. 타임아웃 제어 전송을 위해 보통 서비스 상단에 초기 컨텍스트를 설정합니다. 예를 들어 타임아웃을 3초로 설정합니다
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)defer cancel()
위 그림에서 Redis를 요청하는 것처럼 컨텍스트가 전송되면 남은 시간을 다음과 같은 방법으로 Redis에서 설정한 타임아웃을 비교하고 더 작은 시간을 선택하세요
dl, ok := ctx.Deadline()
timeout := time.Now().Add(time.Second * 3)if ok := dl.Before(timeout); ok {
timeout = dl}
서비스 간 타임아웃 전송은 주로 RPC 호출 시 타임아웃 전송을 의미하므로 gRPC 자체에서 지원하는 추가 처리는 필요하지 않습니다. 타임아웃 전송 원리 위와 유사하게 다음 코드와 같이 메타데이터를 통해 전달되며 결국 grpc-timeout 값으로 변환됩니다.
if v := r.Header.Get("grpc-timeout"); v != "" {
to, err := decodeTimeout(v)
if err != nil {
return nil, status.Errorf(codes.Internal, "malformed time-out: %v", err)
}
st.timeoutSet = true
st.timeout = to}
타임아웃 전달은 서비스 안정성을 보장하는 중요한 방어선입니다. 원칙과 구현은 매우 간단합니다. 타임아웃 전달이 프레임워크에 구현되어 있습니까? 그렇지 않은 경우 신속하게 조치를 취하십시오.
go-zero의 시간 초과 전달
go-zero는 구성 파일의 Timeout
을 통해 api 게이트웨이
및 rpc
서비스를 구성할 수 있습니다. 시간 초과가 발생하며 서비스 간에 자동으로 전달됩니다. Timeout
配置 api gateway
和 rpc
服务的超时,并且会在服务间自动传递。
之前的 一文搞懂如何实现 Go 超时控制 里面有讲解超时控制如何使用。
参考
《SRE:Google运维解密》
项目地址
github.com/zeromicro/go-zero
欢迎使用 go-zero
이전 기사에서는 Go 시간 초과 제어 구현 방법
을 이해하고 시간 초과 제어를 사용하는 방법을 설명했습니다.
"SRE: Google 운영 및 유지 관리 암호 해독"🎜🎜프로젝트 주소🎜🎜github.com/zeromicro/go-zero🎜🎜
go-zero 사용을 환영합니다.
그리고 🎜star/fork🎜도 우리를 지지해 주세요! 🎜🎜추천: "🎜🎜golang 튜토리얼🎜🎜"🎜
위 내용은 마이크로서비스의 시간 초과 전달을 이해하는 기사 1개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!