반응형
슬라이드 링크 : https://www.slideshare.net/cybaek/201403?from_action=save
안정적인 서비스 운영 (설계에서 모니터링까지)
설계(Architect)
스케일링이란? - 어떠한 정책에 따라서 서비스에 대한 시스템을 늘리고 줄여주는 서비스
- Scale Up : 하드웨어 성능을 높이는 방법. 예) cpu, ram, storage 업그레이드
- Scale Out : 하나의 서버 보다는 여러대의 서버를 이용하여 일을 나눠서 처리하도록 하여 성능을 높이는 방법
서버 한대에서 시작
- 쉽게 시작할 수 있지만 원만한 운영 어려움
- 이유는 하나의 서버안에 다 들어가 있으므로 이 서버가 죽으면 서비스가 멈춤
- 그리고 디비의 경우 자원이 계속해서 필요하므로(저장) 하드웨어 스케일업을 계속 시켜줘야함
- 따라서 웹 서버가 주기적으로 멈춰야함
두대의 서버(웹서버 1대, 디비 서버 1대)
- SPOF(Simple Point Of Failure : 단일장애점)
- 웹서버가 죽던, 디비서버가 죽던 둘중 하나만 죽으면 모두 정상적인 동작이 안됨.
- 이유는 웹 서버는 디비서버에 의존하고있고, 클라이언트는 웹서버만 바라보고 있으므로 웹서버가 죽던 디비서버가 죽던 클라이언트는 정상적으로 서비스를 이용할 수 없는 것임.
세대의 서버(웹서버 2대, 디비 서버 1대)
- 웹서버가 2대 이상이 되면, 트래픽 분산을 위해 로드밸런서를 앞단에 둔다.
- 로드밸런서를 앞단에 두는 이유는 클라이언트의 진입점을 하나로 두기 위함도 있다.
- 웹서버를 다중화하여 안전성을 꾀했지만 여전히 DB가 죽으면 서비스안됨. SPOF 이슈가 아직 남아 있음
네대의 서버(웹서버 2대, 디비서버 2대)
- DB 쓰기는 Master에, 읽기는 두대 모두에서
- 읽기 처리는 두배로 증가
- 써야할 양도 두배로 증가(Master - Slave간의 데이터 싱크)
- DB서버를 다중화하여 SPOF 이슈는 해결했지만 DB 관리 포인트가 늘음
- 어떻게 DB를 잘 관리할 것이냐가 관건
셀 아키텍쳐(웹서버 2대, 디비서버 2대)
- http://highscalability.com/blog/2012/5/9/cell-architectures.html
- 데이터를 특정 속성 중심으로 물리적 분할
- 웹서버, 디비서버를 물리적으로 분할
- 대규모 확장에는 병렬화가 필요하고 병렬화에는 구성 요소가 서로 분리되어야 한다는 아이디어를 기반으로함
- 약간 MSA(Micro Service Architecture)와 비슷한 느낌임
- 장점
- 사용자 기반이 커짐에 따라 모든 크기로 저장할 수 있는 병렬화 단위를 제공함
- 더 많은 용량이 필요함에 따라 셀이 증분 방식으로 추가됨(셀 단위 스케일링)
- 하나의 셀 아키텍쳐가 장애가 났을 시 다른 셀에 영향을 미치치 않음(장애를 특정 셀로 고립 가능)
- 단점
- 많은 장비가 필요(비용 증가)
- 제공하는 기능에 따라 셀간 데이터를 조합해야할 수도 있음
로드밸런서(Load Balancer)
- 로드밸런싱 : 부하 분산을 위해서 가상 IP를 통해 여러 서버에 접속하도록 분배하는 기능을 말함
- 성능 향상, 무중단 서비스 구축(안정성), Scale Up 보다는 비교적 저렴
- 로드밸런서는 하드웨어가 될 수도있고, 소프트웨어가 될 수도 있다.
- 로드밸런서에도 부하가 많이 물리면 병목현상(Bottle Neck)이 생길 수 있으므로 이중화 하는 것이 좋다.(아니면 DSR 세팅으로 부하 감소를 꾀하거나..)
- 로드밸런서
- 로드밸런싱 : 부하 분산을 위해서 가상 IP를 통해 여러 서버에 접속하도록 분배하는 기능을 말함
- 성능 향상, 무중단 서비스 구축(안정성), Scale Up 보다는 비교적 저렴
- 로드밸런서는 하드웨어가 될 수도있고, 소프트웨어가 될 수도 있다.
- 로드밸런서 동작 알고리즘
- Round Robin
- 순차 방식
- 요청을 순서대로 각 서버에 균등하게 분배하는 방식
- 서버 커넥션 수나 응답시간에 상관 없이 모든 서버를 동일하게 처리
- 다른 알고리즘에 비해서 가장 빠름
- DNS RR
- Least Connection
- 최소 접속 방식
- 서버에 연결되어 있는 커넥션 개수만 갖고 단순 비교하여 가장 적은 곳에 연결
- Weighted Least Connections
- 가중치 최소 접속 방식
- 서버에 부여된 Weight값을 기반으로 커넥션 수의 개수와 함께 고려하여 연결
- Fastest Response Time
- 응답시간방식
- 가장 빨리 응답하는 서버에 이용자 요구를 연결하는 방법
- 응답시간은 각 서버가 패킷 형태의 요구를 송수신하는데 걸리는 시간을 측정한 것이다
- Adaptive
- 최소대기방식
- Open 또는 Pending중인 커넥션을 적게 가지고 있는 서버로 네트워크 커넥션 방향을 지정한다
- Pending 커넥션은 Full TCP Handshake를 완성하지 않은 것으로, 이것은 초당 클라이언트 Thread의 수가 증가할 때 더욱 잘 수행된다
- Hash
- 특정 클라이언트는 특정 서버로만 할당시키는 방법
- 경로가 보장되며 접속자수가 많을수록 분산 및 효율이 뛰어나다
- 다만 접속자수가 적을수록 공평하게 분산이 안될수도 있다
- 보통 단순하게 한가지 알고리즘만 선택하지 않고 Least Connection 알고리즘 선택 후 동등한 수의 Connection일 경우 Round Robin을 선택하는 방식으로 결합하여 사용한다.
- 로드밸런서 동작방식(Mode 별)
- DSR(Direct Server Return) 방식
- 서버에서 결과를 바로 클라이언트에게 리턴
- 이러한 모드가 나온 배경은, 인바운드 트래픽 대비 아웃바운드의 트래픽이 높아 나오게됨
- 기존은 Client -> L4 -> Server -> L4 -> Client 이렇게 됨. L4에 인바운드, 아웃바운드 트래픽이 모두 물려 부하가 크고 리소스 소모가 큼
- 이러한 문제를 해결하기 위해 나온 DSR은 이렇게 동작함: Client -> L4 -> Server -> Client
- 아웃바운드 트래픽을 L4에 전달하지 않고 직접 클라이언트에게 전달함
- 사용자가 real server에 접근할 때 출발지와 목적지의 IP 주소를 변조하지 않고, L4에서 관리하는 real server의 MAC 주소 테이블을 확인해서 MAC주소만 변조한다.
- 클라이언트의 Request를 서버로 전달함에 있어 어떤 헤더를 이용하는지에 따라 L2/L3 DSR로 구분하게 된다.
- L2DSR : MAC 주소 변경을 통해 클라이언트의 Request가 전달
- L3DSR : IP Header를 변조하여 서버에 Request를 전달
- Bridge/Transparent Mode
- 사용자가 서비스를 요청하면 L4로 전달된 목적지 IP 주소를 REAL SERVER IP 주소로 변조하고 MAC 주소를 변조해서 목적지를 찾아가는 방식
- 요청 전달 시 변조 :
- 사용자 -> L4 -> NAT(IP/MAC 주소 변조) -> real server
- 사용자가 L4를 호출하면 중간에 NAT(Network Address Translation)가 목적지 IP 주소를 real server IP 주소로 변조하고 MAC 주소도 변조한다
- 응답 전달 시 변조 :
- Real server -> NAT -> L4 -> 사용자
- real server에서 L4를 거치면서 출발지(source) IP 주소를 L4 가상 IP 주소로 변조한다
- 동일 네트워크 대역이므로 MAC 주소는 변조하지 않는다
- Router Mode
- Bridge/Transparent Mode와 유사하지만 출발지(source) MAC 주소도 변조된다
- One Arm Mode
- 사용자가 real server에 접근할 때 목적지 IP는 L4 스위치 IP를 바라본다.
- L4에 도달하면 L4가 클라이언트에게 받은 목적지 IP 주소를 L4 IP 주소에서 real server IP와 real server MAC 주소로 변조한다
- 되돌아가는 IP는 L4의 IP pool의 IP 주소로 변조한다.
- NAT(Network Address Translation)
- private IP를 public IP로 바꾸는데 사용하는 통신망의 주소변조기
- 대표적인 로드밸런서
- L4 (Transport Layer) :
- OSI 7계층 중 4 Layer를 라우팅 하는 스위치
- Transport Layer(IP + Port) Load Balancing
- TCP, UDP 프로토콜
- Port 기반 스위칭 지원
- VIP(Virtual IP)를 이용하여 여러대를 한대로 묶어 부하 분산
- 주로 Round Robin 방식 사용
- L7 (Application Layer) :
- Application Layer(Client Request) Load Balancing
- HTTP, FTP, SMTP, 프로토콜
- 오픈소스 로드밸런서 HAProxy
- 기존의 하드웨어 스위치를 대체하는 소프트웨어 로드밸런서로, 네트워크 스위치에서 제공하는 L4, L7 기능 및 로드밸런서 기능을 제공한다.
- Proxy
- Forward Proxy :
- 클라이언트 앞단에 존재하며 프록시 서버가 클라이언트 대신 서버에 요청하고 전달받은 결과를 클라이언트에게 전달하는 역할 수행
- Backend Server에게 Client를 숨길 때 사용
- Client <=> Forward Proxy → Backend Server
- Reverce Proxy :
- 실제 서버 요청에 대해서 서버 앞 단에 존재하면서, 서버로 들어오는 요청을 대신 받아서 서버에 전달하고 요청한 곳에 그 결과를 다시 전달하는 역할 수행
- Client에게 Backend를 숨길 때 사용
- Client → Reverse Proxy Server <=> Backend Server
- Forward Proxy :
- HAProxy 기본 동작 방식
- HAProxy는 기본적으로 reverse proxy형태로 동작한다
- 1. 최초 접근 시 서버에 요청 전달
- 2. 응답 시 쿠키(cookie)에 서버 정보 추가 후 반환
- 3. 재요청 시 proxy에서 쿠키 정보 확인 -> 최초 요청 서버로 전달
- 다시 접근 시 쿠키 추가 없이 전달 -> 클라이언트에 쿠키 정보가 계속 존재함(쿠키 재사용)
- 참고 : https://d2.naver.com/helloworld/284659
- HAProxy는 기본적으로 reverse proxy형태로 동작한다
- HAProxy를 운용하는 다양한 방법이 있으나, 상세한 내용은 링크를 참고할 것
데이터베이스(Database)
- 데이터베이스 : 고가용성 보장 필요
- 고가용성이란? (High Avaliability) : 서버와 네트워크, 프로그램 등의 시스템이 상당히 오랜기간동안 지속적으로 정상운영이 가능한 성질을 말함. 가용성이 높다는 뜻으로서, 절대 고장나지 않음을 의미한다. 가용성 99.99%
- DB는 중요하기 때문에 고가용성을 보장하는 것이 가장 중요하다.
- 고가용성을 보장하는 디비 구성
- 액티브-스텐바이
- 하나의 DB 서버는 Active로 두고, 다른 하나의 DB 서버는 대기상태인 StandBy로 둔다.
- 만약 Active가 장애가 나면, StandBy와 절체되어서 고가용성을 보장한다.
- StandBy의 종류
- Hot StandBy : StandBy측은 가동 후 즉시 이용가능한 구성. 이게 전환시간이 가장 짧지만 비용이 비싸다.
- Warm StandBy : StandBy측은 가동 후 이용가능하게 하기 위해서 나름대로의 준비가 필요한 구성
- Cold StandBy : StandBy측을 정지시켜 두는 구성. 절체 시 가동.
- 액티브-스텐바이
-
- 액티브-액티브
- 두개의 DB 서버를 모두 Active로 두는 것이다.
- 장점은 두개 중 하나가 죽어도 고가용성을 보장한다.
- 단점은 두개의 DB 서버의 데이터 정합성을 유지해야하기 때문에 속도가 느리다.
- 마스터-슬레이브(Read Replication)
- 하나의 DB 서버를 Master로 두고 n개의 DB 서버를 복제본(Replication)으로 둔다
- Insert, update, delete는 Master에서 수행하고 select는 Replication에서 수행하여 부하를 분산한다.
- 데이터가 많아지면 많아질수록 Slave가 Master를 복제하는 시간이 늘어난다. (데이터 싱크)
- 데이터 싱크 문제로 인해 정말 Select한게 맞는지 재차 확인하는 로직 필요.
- 클러스터링 : DB의 다중화
- 샤딩(Sharding)
- 파티셔닝의 한 종류, 수평으로 데이터를 쪼개는 방식이다
- Mysql의 경우 5.1 미만의 버젼에서는 지원하지 않음
- 파티셔닝(Partitioning)
- 성능, 고가용성, 유지보수성을 목적으로 논리적인 데이터를 다수의 엔티티로 분할하는 행위
- 큰 테이블이나 인덱스를 관리하기 쉬운 파티션이라는 작은 단위로 물리적으로 분할하는것을 의미함.
- 장점
- 물리적인 파티셔닝으로 인해 전체 데이터의 훼손 가능성이 줄어들고 데이터 가용성이 향상됨
- 큰 테이블들을 제거하여 관리를 쉽게 해줌
- 성능이 향상됨
- 단점
- 테이블간의 Join에 대한 비용 발생
- 테이블과 인덱스를 별도로 파티셔닝할 수 없음. 테이블과 인덱스를 같이 파티셔닝해야함
- 종류
- 수평 단편화(Horizontal Partitioning, Sharding)
- 기존에 하나로 구성될 스키마를 다수의 복제본으로 구성하고 각각의 샤드에 어떤 데이터가 저장될지를 샤드키를 기준으로 분리한다.
- 예를 들면, 나는 고객의 데이터베이스에서 CustomerId 컬럼을 샤드키로 사용하여 샤딩하기로 하였다. 0 ~ 10000 번 고객의 정보는 하나의 샤드에 저장하고 10001 ~ 20000 번 고객의 정보는 다른 샤드에 저장하기로 하였다. DBA는 데이터 엑세스 패턴과 저장 공간 이슈(로드의 적절한 분산 , 데이터의 균등한 저장)를 고려하여 적절한 샤드키를 결정하게 된다.
- 수직 단편화(Vertical Partitioning)
- 하나의 엔티티에 저장된 데이터들을 다수의 엔티티들로 분리하는 것을 말한다.
- 관계형 DB에서 3정규화와 비슷한 개념으로 접근하면 이해하기 쉽다.
- 하지만 수직 파티셔닝은 이미 정규화된 데이터를 더 잘게 분리하는 과정이다.
- 수평 단편화(Horizontal Partitioning, Sharding)
- 액티브-액티브
사용자인증(Authentication & Authorization)
- Authentication(인증) : 사용자 인증. 클라이언트가 자신이 주장하는 사용자와 같은 사용자인지를 확인
- Authorization(인가) : 권한 인증. 클라이언트가 하고자 하는 작업이 해당 클라이언트에게 허가된 작업인지를 확인
- 세션 : 일정 시간동안 사용자로부터 들어오는 일련의 Request를 하나의 상태로 보고 그 상태를 일정하게 유지시키는 기술
- 보통 사용자 인증(Log in)에 사용
- 이 세션 데이터를 서버 어플리케이션을 통해 물리적으로 어떠한 저장 공간에 저장한다.
- 따라서 보안성은 굉장히 우수하지만, 세션에 대한 서버의 저장공간을 필요로 한다는 단점이 있다.
- 서버의 메모리에 세션정보를 저장함으로 인하여 병목현상이 생길 수 있다.
- 웹서버가 2대 이상이면 세션정보에 대해서 모든 웹서버들이 동기화 해야한다. 따라서 구현이 복잡하고 또 성능적으로 속도가 저하된다.
- 이런 복잡함과 성능적인 저하 문제를 해결하기 위해 DB나 Redis, memCached같은 메모리 DB를 사용하여 세션 관리 role을 분리하는 구현 방식이 탄생함
- 하지만 이마저도 동기화에 대한 부분만 해소되었을 뿐 요청이 많아지면 많아질수록 필요한 메모리도 늘어나고(비용증가) 이에 따라 병목현상이 발생(성능저하)한다는 이슈가 남아있음
- 이런 부분까지 해결하기 위해 사용자 인증 후 인증에 대한 정보 저장을 Client에 넘기는 구현방식이 탄생함.
- OAuth2.0 혹은 Json Web Token을 사용한 사용자 인증이 이것임.
- OAuth2.0
- 사용자 인증 후 Access Token과 Refresh Token을 전달받아 사용
- 권한에 대한 부분을 Access Token을 사용하여 api의 기능을 이용하고, Access Token의 lifetime이 만료되면 Refresh Token을 가지고 새로운 Access Token을 발급받는다.
- JWT(Json Web Token)
- 사용자 인증 후 Json 형태로 된 Json Web Token을 전달받아 사용
- 권한에 대한 부분을 JWT을 사용하여 api의 기능을 이용하고, JWT의 lifetime이 만료되면 다시 사용자 인증을 한다.
배포(Deploy)
- 배포가 번거로운 일이 되면 안됨
- 빠른 롤백이 가능해야함 → 빠른 배포보다 중요!
- 배포 전에 롤백 시 필요한 작업 미리 준비 → 엔터 한번으로 롤백이 되도록!
- 모든 장비의 설정 내용이 같은가?
- Terraform
- Cloudformation(AWS)
- Docker
속도 개선
- 어디가 느린지 파악하는 것이 우선
- 캐쉬적용 → 정적인 파일
- 시간적 지역성
- 한번 읽은 데이터를 곧 다시 읽을 수 있다
- LRU(Least Recently Used)
- 사용한지 가장 오래된 element를 자동으로 캐시에서 제거해나가며 데이터를 캐싱할 수 있도록 해주는 자료구조
- 공간적 지역성
- 읽은 곳 근처의 데이터를 접근하는 경우가 있다
- prefetch
- 연산에 필요한 data들을 미리 가져오는 것을 의미
- CPU가 연산을 하는 동안 prefetcher가 다음 연산에 필요할 데이터를 유추해서 미리 CPU에서 가장 가까운 cache에 넣어놓음
- prefetch
- 읽은 곳 근처의 데이터를 접근하는 경우가 있다
- 시간적 지역성
- 정책 변경
- 예) 조회수가 꼭 정확해야하나?
- 스토리지
- RAID
- RAID(Redundant Array of Inexpensive Disks)의 약자
- 여러 개의 디스크를 배열하여 속도의 증대, 안정성의 증대, 효율성, 가용성의 증대를 하는데 쓰이는 기술
- 정책으로 스토리지 속도를 최적화
- RAID
- 웹, WAS
- 각 URI별 응답속도 관리
- 클라이언트와 가장 가까운 리젼으로부터 Response 받도록
- 정적인 파일을 내려받는 경우(예, 이미지, 동영상 등) 파일 사이즈를 줄여 최적화 했는지
- 클라이언트 렌더링 방식이 Lazy Loading이 적용되어있는지
- 백엔드에는 Slow Query가 없는지
- 각 URI별 응답속도 관리
- 가장빠른 해결책 : 증설
운영(Operational)
- 서비스 오픈은 끝이 아니라 시작
- 신규 서버 설치
- 장비를 받아 10분 내에 설치할 수 있도록
- 코드로 인프라관리(Infrastructure As a Code)
- Terraform
- Ansible Playbook
- AWS Cloudformation
- 하지만 온프레미스 환경은..?
- 방법 1 : Shell Script 작성해놓고 실행하면 다 세팅되도록 구성 → Shell 노가다 필요
- 방법 2 : 가상머신으로 기본 환경세팅이 되어있는 이미지파일을 만들어 사용
- 방법 3 : Docker를 쓰자
- 자동 복구
- 장애 시 루틴하게 하는 작업
- 예, 프로세스 재구동 등을 특정 조건일 때 자동으로 수행하도록
- 배치작업
- 필요한 기본 인프라
- 실패시 알림 → Slack
- 과거 작업 이력 조회 → Jira
- 여러 서버 묶어서 실행 → Infrastructure As a Code
- feat. Jenkins
- 필요한 기본 인프라
- 로그처리
- 수집 + 처리 + 모니터링
- 흔히 이야기하는 ELK, EFK 스텍
- 로그로테이션
- 한정적인 서버 자원 안에서 계속해서 쌓여가는 로그를 주기적으로 저장하고, 삭제하여야함
- 보관
- 로그를 얼마나 오랫동안 보관할 것인가는 정책의 문제
- 조회
- 얼마나 많은 범위의 데이터를 얼마나 빠르게 처리할 것인가
- 잘 구축하면 CS처리를 비개발자에게 이관 가능
- Kibana
- ReDash
- 보안
- 개인정보 저장X 혹은 격리 및 암호화
- 백업
- AWS AMI
- 어떻게 복구하는가
- 주기적인 인스턴스 백업 → 복구 시 백업했던 AMI 사용하여 복구
- 품질 관리
- 각 서버 구간별 처리 속도 관리
- 네트워크 모니터링 툴 : PINPOINT
- https://github.com/naver/pinpoint
- 데이터베이스
- Slow Query를 만들지 않는다 → Slow Query 자동 검출 시스템 만들면 좋음 → AWS RDS는 기능을 지원함
- 동적 쿼리 지양 → ORM 사용 권장
- 각 서버 구간별 처리 속도 관리
- 서비스 HealthCheck
- HTTP 에러 페이지 설정
- 사용자들은 무의식적으로 새로고침을 반복 → 트래픽!!
- 에러 페이지는 별도로 정적인 화면을 내려주도록 설정해야함
- 불필요한 로그는 남기지 말자 → 로그를 찍는 것도 일
모니터링(Mornitoring)
- 경고와 장애 수준으로 분리
- 장애 이전에 알림이 오도록 해야함
- 평상시 사용률 20%를 유지하고 있다면, 90%가 아니라 50% 수준에서 경고 알람을 받아야함
- 주기적으로 수치 점검
- 시스템의 기능과 사용자 수는 계속 변함
- 따라서 경고, 장애, 최저 값 세 수치는 주기적으로 리뷰해야함
- 테스트 활용하여 기능 체크
- 사용자 인터페이스 레벨의 테스트 모듈을 주기적으로 돌려 서비스 상태 체크
- 개발 문화 TDD를 지향하자
- 사용자 인터페이스 레벨의 테스트 모듈을 주기적으로 돌려 서비스 상태 체크
- 외부 API를 이용할 경우
- 외부 서비스에 의존하고있으므로 주기적인 API 체크가 필요
- 내가 직접 관리하는 서비스가 아니라고 방치해서는 안됨
장애 대응
- 전파 : 메일링 리스트를 이용하여 유관자에게 전파
- 롤백이 가능하면 롤백이 우선
- 중요기능 우선 대응
- 장애 발생 후 꼭 회고를 하도록
- 모니터링 항목으로 등록
- 장애 원인을 자동으로 알 수 있다면 스크립트화 시킨다
반응형
'개발관련' 카테고리의 다른 글
Argo CD Notification (1) | 2020.01.20 |
---|---|
VirtualBox 화면 해상도 조절 방법 참고 (0) | 2019.10.30 |
JVM Heap에 대한 좋은 글 링크(feat. Elastic search) (0) | 2019.09.08 |
[Java] 서버 인스턴스 사양에 맞도록 JVM Heap Area 튜닝 하는 방법 (0) | 2019.08.12 |
[Java] jvm gc와 heap 메모리 체크 방법 (0) | 2019.08.12 |