본문 바로가기

1. Reliability(신뢰성)


아래는 소프트웨어가 올바르게 동작함을 의미하는 경우이다. `신뢰성`이란 무언가 잘못되더라도 지속적으로 올바르게 동작함을 의미한다.

  • 애플리케이션은 사용자가 기대한 기능을 수행한다
  • 시스템은 사용자가 번한 실수나 예상치 못한 소프트웨어 사용법을 허용할 수 있다.
  • 시스템 성능은 예상된 부하와 데이터 양에서 필수적인 사용 사례를 충분히 만족한다.
  • 시스템은 허가되지 않은 접근과 오남용을 방지한다.

1.1 Fault Tolerant(결함성)과 Resilient(탄력성)

잘못될 수 있는 일을 fault(결함)이라고 하고 fault(결함)을 예측하고 대처할 수 있는 시스템을 fault-tolerant또는 resilient을 지녔다고 말할 수 있다. 모든 종류의 fault(결함)을 견디는 시스템으 존재할 수 없다. 따라서 특정유형의 결함내성에 대해서만 이야기하는것이 적절하다.

1.2 결함과 장애

결함은 사양에서 벗어난 시스템의 한 구성요소로 정의하지만 장애는 사용자에게 필요한 서비스를 제공하지 못하고 시스템 전체가 멈춘 경우이다. 결함확률을 0으로 줄이는것은 불가능하다. 결함으로 인해 장애가 발생하지 않도록 구조를 설계하는것이 중요하다.

1.3 하드웨어 결함

시스템에서 하드웨어 장애율을 줄이기위한 첫 번째 대응은 각 하드웨어에 구성요소를 중복(redundancy)으로 추가하는 방법이 가장 일반적이다.

  • 하드디스크 RAID구성
  • 서버는 이중 전원 디바이스와 핫스왑 가능한 cpu
  • 데이터센터는 예비전원용 디젤 발전기를 갖춘다

하드웨어 문제르 장애가 발생하는것을 완전히 막을 수는 없지만 일정시간동안은 장비가 중단되지 않고 동작하도록 해준다.

1.4 소프트웨어 오류

  • cpu,메모리,디스크공간,네트워크 대역폭과 같은 공유자원을 과도하게 사용하는 일부 프로세스
  • 시스템의 속도가 느려져 반응이 없거나 잘못된 응답을 반환하는 서비스

이런 소프트웨어 오류는 특정 상황이 발생하기 전까지 오랫동안 나타나지 않는다. 빈틈없는 테스트,프로세스 격리, 죽은 프로세스의 재시작 허용, 프로덕션 환경에서의 시스템 모니터링등이 문제해결에 도움을 준다.

1.5 인적오류

대규모 서비스에서 발생하는 오류는 운영하는 과정에서 하드웨어 결함으로 발생하는 경우는 10~25프로라고 한다. 그렇다면 나머지는 대부분 인적오류인것이다.

  • 사람이 가장 많이 실수하는 장소에서 실수로 장애가 발생하지 않도록 샌드박스를 제공하라
  • 단위테스트부터 통합테스트까지 모든 수준에서 철저히 진행하라
  • 장애발생시 오류를 빠르게 복구할 수 있도록 롤백, 롤아웃 방법을 마련하라
  • 성능지표와 오류율 같은 상세하고 명확한 모니터링 대책을 마련하라


2.확장성


시스템의 사용자가 1만명에서 10만명 또는 100만명,1000만명으로 증가할 수 있다. `확장성`은 증가한 부하에 대처하는 시스템의 능력을 설명하는데 사용하는 용어이다. 확장성이라는 것은 "X는확장성이 없다" 라고 표현하는것이 의미가 없다. "시스템이 특정 방식으로 커지면 이에 대처하기 위한 선택은 무엇인가?"같은 질문을 고려해야한다는 의미이다.

확장성을 설명하려면 먼저 양적으로 부하와 성능을 설명하는 방법이 필요하다. 부하를 기술하는 방법과 성능을 기술하는 방법을 알아보자.

2.1 부하 기술하기


부하는 부하 매개변수라고 부르는 몇 개의 숫자로 나타낼 수 있다. 웹 서버의 초당 요청 수, 데이터베으스의 읽기 대 쓰기 비율, 동시 활성 사용자, 캐시 정중률 등이 있다.

트위터를 예로 부하를 기술하는 방법을 알아보자. 트윗시스템에서 단순히 초당 12,000건의 쓰기처리문제보다는 fan-out에서 확장성에 문자가 생긴다.

  • 트윗 작성
    • 사용자는 팔로워에게 새로운 메시지를 게시할 수 있다. (평균 초당 4.6k요청, 피크일때는 12k요청)
  • 홈 타임라인
    • 사용자는 팔로우한 사람이 작성한 트윗을 볼 수 있다 (초당 300k요청)




개별사용자는 많은 사람을 팔로우하고 많은 사람이 개별사용자를 팔로우한다. 관계형 데이터베이스로 간단하게 설계해보면 아래와 같은 형태로 구현이 가능하다.

사용자가 자신의 홈 타임라인 화면에 접속하면 팔로우하는 모든 사람을 찾고, 여기서 찾은 사람들의 모든 트윗을 찾아서 시간순으로 정렬해서 화면단에 응답하는 설계이다. 피드를 조회할때마다 매번 join으로 연산하므로 비용이 비싸고 팔로워가 많아지고 글이 많아지면 많아질수록 읽기성능은 급속도로 느려질것이다.


다른 방법은 개별 사용자의 홈 타임라인을 테이블에 캐시해두는 방식이다. 즉, 사용자가 트윗을 작성하면 해당 사용자를 팔로우하는 사람을 모두 찾고 팔로워 각자의 홈타임라인 테이블에 새로운 트윗을 삽입하는 방식이다. 사용자가 홈타임라인을 조회할때는 미리 계산된 타임라인을 조회하기때문에 훨씬 빠르고 저렴한 비용으로 조회가 가능하다.

대신 첫번째 방법보다는 쓰기시점에 더 많은 일을 해야하지만, 읽기시에 수백배 적은 연산으로 피드화면을 전달할 수 있다. 만약, 팔로워 수가 3천만명이 넘는 특별한 사용자가 글을 올리게되면 3천만명의 타임라인 캐싱에 쓰기를 해야한다는것을 의미한다. 이 방법에서는 사용자가 작성한 트윗을 팔로워에게 적시에 전송하는것이 해결해야하는 문제이다.


트위터에서는 1번방법의 장점과 2번방법의 장점을 결합해서 일반적인 사용자의 경우 2번방식으로 피드화면을 조회할 수 있고 특수한 사용자의 경우에는 피드를 읽는시점에 별도로 조회를해서 두 결과를 합친것을 피드화면에 그려주는 방식을 채택했다.


트위터 사례에서 `사용자당 팔로워의 분포`가 부하를 결정하기 때문에 `핵심 부하 매개변수`가 된다. 애플리케이션마다 특성은 매우 다르지만 추론할때 비슷한 원리를 적용할 수 있다.

2.2 성능 기술하기

시스템의 부하를 기술하면 후바가 증가할때 어떤일이 일어나는지 조사해야한다. 하둡과 같은 일괄 처리 시스템은 throughput(처리량)에 관심을 가지고 온라인 시스템에서는 response time(응답시간)에 관심을 가진다.

2.3 부하 대응 접근 방식


특정 애플리케이션에 적합한 확장성을 갖춘 아키텍처는 주요 동작이 무엇이고 잘 하지 않는 동작이 무엇인지에 대한 가정을 바탕으로 구축한다. 이 가정이 잘못되면 확장에 대한 엔지니어링 노력은 헛수고가 되고 최악의 경우 역효과를 낳는다.


3. 유지보수성


소프트웨어 비용의 대부분은 초기개발이 아니라 지속해서 이어지는 유지보수에 들어간다. 유지보수에는 버그수정,시스템 운영 유지, 장애조사, 새로운 플랫폼 적응, 기술채무 상환, 새로운 기능 추가등이 있다.

  • 운용성
    • 운영팀이 시스템을 원할하게 운영할 수 있도록 쉽게 만들어라
  • 단순성
    • 시스템에서 복잡도를 최대한 제거해 새로운 엔지니어가 쉽게 이해할 수 있게 만들어라
  • 발전성
    • 엔지니어가 이후에 시스템을 쉽게 변경할 수 있게 하라.

확장성을 달성하기 위한 쉬운 해결책은 없기때문에 운용성,단순성,발전성을 염두해두고 시스템을 생각하려 노력하자.


정리

  • 신뢰성은 결함이 발생해도 시스템이 올바르게 동작하게 만든다는 의미
  • 확장성은 부하가 증가해도 좋은 성능을 유지하기 위한 전략
  • 유지보수성은 시스템을 작업하는 작업자와 운영자의 삶을 개선하는 데 있다.

댓글