1. Reliable, Scalable, and Maintainable Applications

최근의 많은 애플리케이션은 계산-집중적이 아닌 자료-집중적이다. 즉, 많은 애플리케이션은

  • 데이터를 저장해 그 애플리케이션이나 다른 애플리케이션이 나중에 찾을 수 있어야 하며 (데이터베이스)
  • 비싼 연산의 결과를 기억해 읽기를 가속해야 하며 (캐시)
  • 사용자가 키워드로 데이터를 찾거나 여러 방법으로 필터링할 수 있어야 하며 (탐색 인덱스)
  • 다른 프로세스에 대해 메시지를 보내 비동기적으로 다룰 수 있어야 하며 (스트림 프로세싱)
  • 많은 양의 누적 데이터를 고속으로 처리할 수 있어야 한다. (배치 프로세싱)

이 때 많은 엔지니어들은 이게 당연한 거라고 생각할지 모르나 실제로는 그렇지 않다. 데이터베이스 시스템, 캐싱, 서치 인덱스 등에는 여러 방법이 있으며 이들의 장단점을 적절히 분석해 적절히 활용하는 것이 중요하다.

Thinking About Data Systems

모든 경우에 적용 가능한 단일 데이터베이스 시스템은 없다. 서비스를 제공하기 위해 여러 도구를 결합한다면, 서비스의 인터페이스(API)는 대개 이 세부 구현을 클라이언트로부터 숨긴다. 그러나 세부 구현을 하는 입장이 되면 여러 질문이 필요하다: 캐시는 올바르게 무효화되어야 하며, 데이터의 정합성은 어떻게 보장하는가? 시스템 일부의 성능이 저하되더라도 어떻게 일관적으로 좋은 성능을 내는가? 부하 증가는 어떻게 다루는가? 서비스에 대한 좋은 API는 어떻게 될 것인가? 데이터 시스템의 설계에 영향을 미치는 많은 인자기 있다. 여기서는 가장 큰 3개의 인자를 다룬다.

  • 신뢰도. 시스템이 어려움에 처하더라도 올바르게 작동해야 한다.
  • 확장성. 시스템이 커지더라도 그에 대처할 수 있어야 한다.
  • 유지 가능성. 많은 사람이 유지보수할 때도 생산적으로 일할 수 있어야 한다.

Reliability

신뢰도는 다음 등을 포함한다.

  • 애플리케이션이 사용자가 기대한 동작을 한다.
  • 사용자의 실수나 소프트웨어를 기대와 다르게 사용하는 방법에 대처할 수 있다.
  • 요구하는 사용례에 대한 성능이 충분하게 나온다.
  • 권한이 없는 접근이나 남용을 막는다.

이는 시스템의 컴포넌트 중 하나가 오작동하는 폴트에 대해서도 대처할 수 있어야 한다. 이는 시스템 전체가 실패하는 실패와는 다르다. 폴트의 확률을 0으로 줄일 순 없으므로 이에 대처할 수 있어야 한다. 에러 처리를 늘리기 위해 폴트를 의도적으로 일으킬 수도 있다. 보안의 경우에는 문제 방지가 문제 해결보다 더 나을 수도 있다.

Hardware Faults

하드 디스크 크래시 등 하드웨어 폴트는 빈번히 일어날 수 있다. 이에 대한 첫 번째 대처법은 각 하드웨어에 대한 중복을 두는 것이다. 하지만 시간이 지나면서 이것도 불충분해졌기 때문에, 소프트웨어 폴트 대처 기법들이 등장하기 시작했다. 이는 단일 기계 실패를 전체 시스템 다운 없이 처리할 수 있다는 장점이 있다.

Software Errors

다른 폴트는 시스템의 에러가 있다. 이런 에러는 예측하기 힘들며, 특정 입력이 있을 때 애플리케이션 서버를 전부 크래시해버리는 버그라든가, 공유 자원을 쓰는 프로세스의 크래시, 시스템이 의존하는 서비스의 속도 감소, 무응답, 잘못된 출력 발생, 폭포수형 실패 등이 있다. 이에 대한 빠른 해결법은 없으며, 신중한 설계, 철저한 테스팅 등의 방법밖에 없다.

Human Errors

사람으로 인해 발생하는 오류도 있다. 이를 줄이려면 어떻게 할까? 인터페이스를 옳은 동작을 하도록 유도하고 틀린 동작을 지양하도록 한다. 사람이 실수를 많이 일으키는 영역과 그것이 실패를 일으키는 지점을 분리한다. 모든 층을 신중하게 테스트한다. 사람 에러에 대한 빠르고 쉬운 복구를 허용한다. 성능 지표와 오차율에 대한 상세하고 깔끔한 모니터링을 한다. 좋은 관리법을 구현하고 학습한다.

How Important Is Reliability?

모든 애플리케이션에 있어 신뢰도는 매우 중요하다.

Scalability

오늘 동작하는 시스템이라도 미래에 동작한다는 보장은 없다. 부하에 따라 성능 저하가 생길 수 있기 때문이다. 이에 대처하는 척도를 확장성이라 한다.

Describing Load

부하는 부하 매개변수라 이르는 몇 가지의 숫자로 정의될 수 있다. Twitter로 치면 트윗 수, 홈 타임라인 등이 그렇다. 상황에 따라서 병목 변수는 크게 달라질 수 있다.

Describing Performance

부하가 증가했을 때 어떤 일이 발생하는질을 알아야 한다.

  • 부하 매개변수를 증가시키고 시스템 자원을 유지했을 때 성능이 어떻게 변화하는가?
  • 부하를 증가시켰을 때 성능을 유지시키려면 자원을 얼마나 늘려야 하는가?

Hadoop같은 배치 프로세싱 시스템에 대해서는 초당 처리할 수 있는 레코드 수인 처리량을 중요시한다. 온라인 시스템에서는 서비스의 응답 시간 등이 중요하다. 이 때 응답 시간은 평균 응답 시간과 분포로 잰다. 이 때 가장 높은 응답 시간에 대해 퍼센타일을 매기거나 중위값을 보는 것도 좋다. 반응 시간에 대한 높은 퍼센타일은 사용자 경험에 악영향을 미치므로 이를 줄이는 것은 중요하다. 이 경우에는 큐 딜레이가 많은 영향을 미치기도 한다. 이로 인해, 반응 시간은 클라이언트 쪽에서 측정하는 것이 좋다.

Approaches for Coping with Load

부하 매개변수가 증가했을 때 어떻게 성능을 유지시킬 수 있을까? 확장은 두 가지로 나눈다. 스케일링 업(수직 스케일링, 더 강한 기계로의 이동), 그리고 스케일링 아웃(부하를 복수의 작은 기계로 분산). 집중적인 부하량은 스케일링 아웃을 막을 수는 없다. 현실에서 좋은 아키텍쳐는 두 접근법을 혼합한다. 어떤 시스템은 부하가 증가했을 때 자동적으로 계산 자원을 추가하는 엘라스틱 시스템이기도 하다. 이는 부하가 예측 불가능할 때 유용하다. 상태 없는 서비스를 분산하는 것은 쉽지만 상태 있는 데이터 시스템을 분산하는 것은 어려우므로, 데이터베이스는 꼭 필요해지기 전까지는 단일 노드에 두는 것이 합리적이었다. 분산 시스템에 대한 도구와 추상화 수단이 발전하면서, 어떤 애플리케이션들에 대해서는 이 상식이 바뀌기도 하였다. 대형 스케일에서 동작하는 시스템 구조는 대개 그 애플리케이션에 특화되어 있다. 모든 구조에 일괄적으로 적용 가능한 확장 가능한 아키텍쳐는 존재하지 않는다. 문제가 읽기의 볼륨, 쓰기의 볼륨, 저장할 데이터의 볼륨, 데이터의 복잡도, 반응 시간 조건, 접근 패턴 등 다양할 수 있기 때문이다. 그렇지만 확장 가능한 아키텍쳐는 대개 범용 구성 요소로부터 만들어진다.

Maintainability

소프트웨어 비용의 대다수는 유지보수에서 온다. 이를 쉽게 하기 위해서는 다음 방법들을 지켜야 한다:

  • 사용성 : 팀이 시스템을 부드럽게 사용할 수 있도록 해야 한다.
  • 단순성 : 시스템에서 복잡성을 최대한 제거하여 새 엔지니어들이 시스템을 이해하기 쉽게 해야 한다.
  • 진화성 : 엔지니어들이 새 요구 사항 등에서 변화를 적용하기 쉬워야 한다.

Operability: Making Life Easy for Operations

좋은 조작 팀들은 다음에 대한 책임이 있다:

  • 시스템의 상태를 진단해 상태가 조지 않으면 빨리 복구하는 것
  • 시스템 실패나 성능 저하 등 문제의 원인을 찾는 것
  • 보안 패치 등을 적용해 소프트웨어나 플랫폼을 업데이트시키는 것
  • 다른 시스템이 어떻게 상호작용하는지를 주시해서 문제 있는 변경이 피해를 끼치기 전에 이를 회피하는 것
  • 미래 문제를 예측해 발생하기 전에 푸는 것
  • 배포, 설정 관리 등에 대한 좋은 습관과 도구를 설립하는 것
  • 애플리케이션을 한 플랫폼에서 다른 플랫폼으로 옮기는 복잡한 유지보수 작업을 수행하는 것
  • 설정이 변경되어도 시스템의 보안성을 유지하는 것
  • 동작들을 예측 가능하게 하는 프로세스를 정의하고 프로덕션 환경을 안정적으로 유지하는 것
  • 개개인이 떠나거나 도착해도 시스템의 관리 지식을 유지시키는 것

데이터 시스템은 다음 작업으로 작업 효율성을 높일 수 있다.

  • 좋은 모니터링으로 시스템의 내부와 런타임 행동을 볼 수 있게 하는 것
  • 자동화, 표준 도구와의 통합에 대한 좋은 지원을 하는 것
  • 기계 각각에 대한 의존성을 피하는 것
  • 좋은 문서화와 이해하기 쉬운 동작 모델을 제공하는 것
  • 좋은 기본 동작을 제공하되 관리자들에게 필요할 때 기본값을 오버라이딩할 수 있게 해 주는 것
  • 적절한 경우 자가복구를 수행하되, 관리자들에게 필요할 때 직접적인 시스템 제어를 허용하는 것
  • 예측이 어려운 동작을 최소화하고 예측 가능한 행동을 수립하는 것

Simplicity: Managing Complexity

프로젝트를 단순화하라. 복잡도는 유지보수를 어렵게 만들며 비용과 스케쥴은 더 많이 든다. 시스템을 단순화한다는 것은 기능을 더 줄인다는 것이 아니다. 돌발적인 복잡도를 줄인다는 것이다. 이는 추상화를 통해 바람직하게 이루어질 수 있다.

Evolvability: Making Change Easy

시스템의 요구 사항은 시간에 따라 바뀔 수 있다. 테스트 기반 개발과 리팩토링, 시스템의 단순화가 핵심이다.

Summary

애플리케이션은 유용하기 위해서는 많은 요구 조건을 필요로 한다. 이에는 기능적 요구 사항, 비기능적 요구 사항 등이 있다. 여기서는 신뢰도, 확장성, 유지보수성을 다루었다. 신뢰도는 폴트가 발생해도 시스템이 올바르게 동작하도록 하는 것이다. 폴트는 하드웨어, 소프트웨어, 인간으로부터 날 수 있다. 폴트 대처법은 특정한 폴트를 최종 사용자에게서 숨길 수 있다. 확장 가능성은 부하가 증가해도 성능을 좋게 유지시키는 것이다. 확장성을 논하기 위해서는 부하와 성능을 정량적으로 묘사할 수 있어야 한다. 확장가능한 시스템에서는 부하가 커져도 시스템이 신뢰성 있을 수 있도록 프로세싱 용량을 더할 수 있다. 유지보수성은 많은 관점이 있지만, 대개는 시스템과 일하는 엔지니어링과 동작 팀의 효율을 높이는 것이다. 좋은 추상화는 복잡도를 줄이고 시스템을 더 수정하기 쉽게 하고 새 사용자 케이스에 대한 확장을 쉽게 한다. 좋은 작동성은 시스템의 신뢰도에 대한 좋은 시각화를 제공하고 이를 관리할 수 있는 효과적인 방법을 제공한다. 애플리케이션을 신뢰성 있게, 확장성 있게, 유지보수성 있게 하는 쉬운 방법은 없지만, 범용적으로 등장하는 특정한 패턴과 테크닉은 있다.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중