linkerd는 ServiceProfile이라는 CRD를 사용하여 경로별 Retry, Timeout 설정을 할 수 있다.
Retry
서비스가 클라이언트의 요청을 받아 처리하는데, 요청이 실패할 경우 다시 보내는 기능이다.
가끔 요청이 실패할 경우 다시 보내어 클라이언트 기준 요청 성공률을 높일 수 있다. 하지만 클라이언트가 과도하게 재시도를 수행하면 서비스는 이를 처리하지 못하고 과부하 상태 및 잠재적인 장애 증상을 일으킬 수 있음에 주의해야 한다.
Timeout
서비스의 요청 처리 시간이 일정 시간 이상 걸릴 경우 해당 요청을 종료하는 기능이다.
클라이언트와 서버와의 통신이 끊어져 있거나 지연되고 있는 상황에서 클라이언트가 무한정 기다리는 것을 방지할 수 있다. 하지만 처리 중인 요청을 종료하여 문제를 일으킬 수 있으니 애플리케이션의 특성에 맞게 적절히 조정해서 사용해야 한다.
실습을 통해 어떻게 동작 하는지 간단하게 테스트해 보자.
실습 전제 조건
- [Linkerd 설치]
- Kubernetes 1.16 이상
실습 환경
- AWS EKS 1.22
실습
1. 테스트를 위한 Client, Server 사전 구성
요청받을 nginx 서버를 배포한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
annotations:
linkerd.io/inject: enabled
spec:
containers:
- name: nginx
image: nginx:latest
nginx서버 설정을 위한 패키지를 다운로드한다.
$ kubectl expose service nginx --port=80
$ kubectl exec -it svc/nginx -c nginx -- /bin/bash
$ apt update
$ apt-get install build-essential libpcre3 libpcre3-dev zlib1g-dev libssl-dev vim wget
nginx서버에서 요청에 대한 응답 지연을 발생시키기 위한 구성으로 echo-nginx-module 모듈을 사용하기 위한 구성을 아래와 같이 한다.
$ wget http://nginx.org/download/nginx-1.23.4.tar.gz
$ tar zxvf nginx-1.23.4.tar.gz
$ cd nginx-1.23.4
## nginx 1.23 버전에 호환되는 echo-nginx-module 다운
$ wget https://github.com/openresty/echo-nginx-module/archive/v0.63.tar.gz
$ tar -xvzf v0.63.tar.gz
## 모듈 컴파일
$ ./configure --with-compat --add-dynamic-module=../echo-nginx-module-0.63
make modules
cp objs/ngx_http_echo_module.so /etc/nginx/modules
/test 경로로 요청 오면 502 error를 반환하고, /tmout 경로로 요청 오면 10초 후 echo 메세지를 반환하는 설정이다.
$ vi /etc/nginx/conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /test {
return 502;
}
location /tmout {
echo_sleep 10;
return 200 "Hello, world!";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
$ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ service nginx reload
같은 nginx 이미지를 사용하여 요청 보낼 nginx-client를 배포한다.
apiVersion: v1
kind: Service
metadata:
name: nginx-client
spec:
selector:
app: nginx-client
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-client
spec:
replicas: 1
selector:
matchLabels:
app: nginx-client
template:
metadata:
name: nginx-client
labels:
app: nginx-client
annotations:
linkerd.io/inject: enabled
spec:
containers:
- name: nginx-client
image: nginx
2. Retry 설정
ServiceProfile을 통해 nginx서버의 /test 경로에 대한 Retry 설정을 하고 nginx-client에서 요청을 보내 로그를 확인해 보자.
apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: nginx.default.svc.cluster.local
namespace: default
spec:
routes:
- condition:
method: HEAD
pathRegex: /test
isRetryable: true ## Retry 설정
name: HEAD /test
$ kubectl logs svc/nginx -c nginx -f
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
192.168.6.169 - - [19/Apr/2023:03:52:49 +0000] "GET /test HTTP/1.1" 502 497 "-" "curl/7.74.0" "-"
약 1번의 요청 Fail에 대한 Retry로 100번의 요청이 재시도된 것을 확인할 수 있다.
retry 값은 아래 설정을 통해 세세하게 설정할 수 있다.
spec:
retryBudget:
retryRatio: 0.2
minRetriesPerSecond: 10
ttl: 10s
- retryRatio : 재시도 요청에 대한 최대 비율 (0.2 = 20%)
- minRetriesPerSecond : retryRatio에서 허용하는 것 외에 초당 재시도 허용 수
- ttl : retryRatio를 계산하기 위해 요청이 고려되는 시간
3. Timeout 설정
ServiceProfile을 통해 nginx서버의 /tmout 경로에 대한 Retry 설정을 하고 nginx-client에서 요청을 보내자.
1초간 지연이 발생하면 Timeout 되는 설정이다.
apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: nginx.default.svc.cluster.local
namespace: default
spec:
routes:
- condition:
method: GET
pathRegex: /test
isRetryable: true
name: GET /test
## timeout path에 timeout 설정 추가
- condition:
method: GET
pathRegex: /tmout
name: GET /tmout
timeout: 1000ms
$ kubectl exec -it svc/nginx-client -c nginx-client -- /bin/bash
$ curl nginx/tmout -vvv
* Trying 10.100.119.208:80...
* Connected to nginx (10.100.119.208) port 80 (#0)
> GET /tmout HTTP/1.1
> Host: nginx
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 504 Gateway Timeout
< l5d-proxy-error: HTTP response timeout after 1s
< connection: close
< l5d-proxy-connection: close
< content-length: 0
< date: Wed, 19 Apr 2023 08:00:51 GMT
<
* Closing connection 0
1초가 지나면 504 Gateway Timeout가 발생하여 connection이 끊긴 것을 확인할 수 있다.
마치며
timeout과 retry는 서비스의 안정성과 가용성을 향상시키는 데 큰 역할을 한다. timeout 시간이 너무 짧으면 서버로부터 응답이 와도 클라이언트에서 에러가 발생할 수 있으며, retry 횟수나 간격이 너무 많거나 짧으면 서버의 부하를 더욱 악화시킬 수 있다. 따라서 이 기능들을 설정할 때는 애플리케이션의 특성에 맞춰 주의 깊게 고려하여 적용해야 한다.
'Service Mesh > Linkerd' 카테고리의 다른 글
Linkerd 서킷 브레이킹 (Circuit Breaking) (1) | 2023.04.19 |
---|---|
Linkerd 버전 업그레이드 (1) | 2023.04.19 |
Linkerd 권한 부여 정책 (0) | 2023.04.05 |
Linkerd mTLS 통신 검증 (0) | 2023.04.05 |
Linkerd 사이드카 주입 (0) | 2023.04.05 |
댓글