Key-Value-Store를 구현하는 과정에서 docker-compose를 사용했는데 기대하던 실험 결과가 나오지 않았습니다.
그래서 제가 만난 이슈와 해결방법에 대해 공유하려합니다.
간단한 Key Value Store 프로젝트 소개
1) User는 Proxy 서버로 데이터 저장을 요청합니다.
2) Proxy 서버는 해시링을 통해 적절한 Store 서버에 저장을 합니다.
3) Store 서버는 1초에 1번씩 redis에 헬스 카운트를 올리고, Service Discovery는 5초에 한번씩 Store서버가 죽었는지 확인합니다.
4) 죽은 Store 서버가 있다면 Service Discovery 서버는 Proxy 서버로 '해시링에서 죽은 스토어 서버를 제거' 하라는 요청을 보냅니다.
-> "cap, pacelc 이론을 통해 스토어 서버가 장애시 PA로 가용성을 보장하고, 일반 상황시 EL로 일관성을 희생하여 더 적은 지연 시간을 가져간다" 라는 실험주제입니다.
제가 원하는 실험방법은 초당 n*100 번의 Request를 보내는데 도중 Store 서버 1개를 중단시키고 장애가 복구되는 과정을 모니터링 하는것입니다.
아래 그림은 제가 구현한 서버의 구성도입니다.
Situation
Store A를 제거했을 때 전체 요청 중 약 '1/3이 실패 응답', '2/3가 성공 응답'으로 오길 기대했습니다.
하지만 Store A를 제거했을 때 Proxy 서버로부터 응답 속도가 지연되면서 요청수 자체가 줄어들었습니다.
Task
가장먼저 에러로그를 확인했습니다.
java.net.SocketTimeoutException: Read timed out
java.net.ConnectException: Connection timed out
java.net.SocketException: Connection reset
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:323) ~[na:na]
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350) ~[na:na]
Store A를 제거했을 때 매번 다른 에러가 떴습니다.
Connection이 잘 안돼서 pending이 걸리는것같은데... 라는 생각이 들었고,
Store 서버를 종료했는데도 불구하고 죽은 Store A서버에 요청을 보내고 응답을 기다리는게 이해가 안됐습니다.
그리고 가끔씩 원하는 방향대로 성공했는데 이 때 뜨는 에러는 아래와 같은 UnknownHostException이였습니다.
java.net.UnknownHostException: store-service-1
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567) ~[na:na]
at java.base/java.net.Socket.connect(Socket.java:633) ~[na:na]
Action
저는 위의 에러 로그로부터 힌트를 얻었습니다.
UnknownHostException이 떴을때는 실험이 잘 됐기 때문에, Store A 서버를 죽였을때는 dns서버가 Store A 서버를 제대로 인식하지 못해야 한다고 생각했습니다.
그래서 docker의 dns캐시에 대해 알아보게됐습니다.
docker는 dns가 내부적으로 사용되고 있고, dns를 통해 service name과 ip를 맵핑시켜서 통신합니다.
***
컨테이너 통신
- Docker Compose에서는 서비스 이름을 사용하여 다른 컨테이너에 접근할 수 있습니다.
- 이는 내부적으로 Docker의 DNS 서버가 관리하며, 서비스 이름을 해당 컨테이너의 IP 주소로 변환합니다.
***
처음엔 Docker Process를 끄면서 동시에 DNS서버를 강제 리프레쉬 하는 방향을 생각했지만 공식문서를 찾아봐도 관련옵션이 없어서 다른 방법을 생각했습니다
제가 생각한 방법은 Connection Timeout을 핸들링 하는 방법입니다.
같은 Docker network에서 connection timeout을 낮추는 방법을 선택했습니다.
극단적으로 1ms는 너무 낮은값이지만 같은 도커 네트워크 환경이고, 실험을 위해 사용하는 방법이기 때문에 괜찮다고 판단했습니다.
Result
Store A 서버를 죽였을 때
장애시 PA를 통해 전체 요청중 1/3이 실패, 2/3이 성공 응답이 오는것을 확인할 수 있었습니다.
'개발 > 설계' 카테고리의 다른 글
Restful API 설계 (0) | 2023.01.08 |
---|