Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- github
- javascript
- html
- 데이터통신
- cache
- Static
- HTTP
- socket
- network
- Elk
- reactive
- VCS
- mongodb
- mybatis
- AWS
- Lombok
- ajax
- effective
- Heap
- git
- r
- spring
- nodejs
- reactor
- Linux
- libuv
- Java
- 네트워크
- NoSQL
- redis
Archives
- Today
- Total
빨간색코딩
[데이터 중심 애플리케이션 설계] 1장. 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 어플리케이션 본문
- 참조문서
- https://github.com/ept/ddia-references
- 데이터 중심 애플리케이션 설계(마틴 클레프만, 위키북스)
초심자의 눈으로 이해한 내용을 정리해보았다. 책에 있는 내용을 기반으로 썼지만, 책에 없는 내용도 조금씩 적어보았다. 책은 꼭 사서 보시길 바랍니다..
1. 데이터 시스템
- 어플리케이션은 계산 중심(compute-intensive)보다 데이터 중심(data-intensive)이 많다.
- 계산에 쓰이는 CPU보다는 데이터 양, 데이터 복잡도 등이 더 문제다.
- 데이터 중심 어플리케이션이 공통으로 필요로 할수 있는 기능들 : 데이터 시스템
- 데이터베이스 : 영속성 스토리지
- 캐시 : 읽기 속도 향상, 값비싼 수행 결과 기억
- 검색 색인 : 사용자가 키워드로 데이터를 검색하거나 다양한 방법으로 필터링할 수 있게 제공
- 스트림 처리 : 비동기 처리를 위해 다른 프로세스로 메세지 보내기
- 일괄(batch) 처리 : 대량의 누적된 데이터를 주기 분석
- 데이터 시스템의 범주들
- 데이터베이스, 메세지큐, 캐시 등
- 최근에는 이 경계들이 허물어지고있다. ex) redis를 MQ로도 쓸 수 있음. kafka 도 지속성을 지원함
- 단일 시스템으로는 어플리케이션 니즈를 충족시킬 수 없음. 복합 데이터 시스템으로 흘러감
- 개발자는 애플리케이션 개발자뿐 아니라 데이터 시스템 설계자이기도 하다.
- 개발자의 고민들
- 데이터를 정확하고 완전하게 유지하려면 어떻게 해야할까?
- 시스템의 일부 성능이 저하되더라도 클라이언트에 일관되게 좋은 성능을 어떻게 제공할 수 있을까?
- 부하 증가를 다루기 위해 어떻게 규모를 확장할까?
- 서비스를 위해 좋은 API 는 어떤 건가?
2. 소프트웨어 엔지니어링의 목표
- 신뢰성(Reliability) : sw결함, 휴먼에러, 재난같은 상황에서도 시스템은 올바르게 동작
- 확장성(Scalability) : 트래픽이 증가해도 대응가능
- 유지보수성(Maintainability) : 모든 개발,운영자가 생산적으로 작업할 수 있어야 함
3. 신뢰성
- 결함(fault)을 예측하고 대처할 수 있는 시스템을 내결함성(fault-tolerant) 또는 탄력성(resilient) 있다고 함
- 결함 : 사양에 벗어난 시스템의 구성 요소
- 장애 : 유저에게 서비스를 제공하지 못하고 시스템이 멈춤
- 결함으로 인해 장애가 발생하지 않도록 내결함성 구조로 설계해야함
- 결함을 0으로 줄일 수는 없다.
- 카오스 몽키(Chaos Monkey) : 고의적으로 결함을 유도하고 내결함성 시스템을 지속적으로 훈련하고 테스트
- https://github.com/netflix/chaosmonkey
- cf) 내결함성을 쉽게 테스트할 수 있는 spring 지원 구현체 : https://codecentric.github.io/chaos-monkey-spring-boot
3-1. 하드웨어 결함
- 시스템 장애의 대부분의 원인 : 디스크, 램 고장. 대규모 정전, 담당자가 장비를 잘못 다룸
- 대응 방안 : 하드웨어 구성에 중복(redundancy)을 추가
- 디스크 : RAID
- 서버 : 이중 전원 디바이스, hot-swap CPU
- IDC : 예비용 전원 발전기
- 애초부터 내결함성과 탄력성을 잘 고려해서 설계해라
- ex) aws 의 가상장비들은 언제나 죽는걸 가정하고 설게했다.
- 이렇게 고려된 시스템은 재부팅도 쉽다.
3-2. 소프트웨어 결함
- systematic error 는 더 예상하기 어렵고 오류를 더욱 많이 유발한다.
- ex) 리눅스 커널 윤초 버그로 레딧, 링크드인 등이 전부 장애남
- https://engineering.vcnc.co.kr/2016/12/struggling-with-the-leap-second/
- 특정 상황에 의해 발생하기 전까지 나타나지 않을수도 있다.
- 명확한 해결책은 없다. 빈틈없는 테스트, 프로세스 격리, 모니터링, 알람체계를 잘 갖춰라
3-3. 인적 오류(human error)
- 대응방안
- 잘 설계된 추상화 API, 인터페이스를 사용하라. 옳은 일은 쉽게하고 잘못된 일을 막을 수 있다.
- 실수가 잦게 발생하는 곳은 실제 데이터로 안전하게 실험해볼 수 있는 sandbox 를 제공하라 (ex. stage환경)
- 단위테스트, 통합테스트, 수동테스트를 철저히 해라. 특히 코너케이스에 유의
- 장애를 빠르게 복구 할 수 있게 도구를 만들어라
- 모니터링이 중요하다. 지표를 분석해라
4. 확장성
4-1. 부하 매개변수
- 부하 성장 질문
- 시스템이 특정 방식으로 커지면 어떤 선택지들이 있는가?
- 추가 부하를 다루기 위해 계산 자원을 어떻게 투입할까?
- 부하 매개변수 : 이걸 정의해야 부하 성장 질문을 논의할수 있다. 기준이 생기기 때문이다.
- 각 시스템 설계에 따라 달라진다.
- ex) rps, qps, active user, cache hit ratio 등
- 예시) 트위터 타임라인 아키텍처
- 버전1 : 트윗을 쓰면 테이블에 전역적으로 insert. 각 유저는 타임라인 접근 시점에 join
- SELECT tweets.*, users.* FROM tweets JOIN users ON tweets.sender_id = users.id JOIN follows ON follows.followee_id = users.id WHERE follows.follower_id = current_user
- 쉽고 빠른 쓰기 + 쉽지만 느린 읽기
- 버전2 : 각 유저별 트윗 우편함에 insert. 각 유저는 타임라인 접근 시, 자신의 트윗 우편함만 읽으면 됨
- 어려운 쓰기 + 쉽고 빠른 읽기
- 한계 : 인플루언서가 수천만 팔로워를 갖고있다면 쓰기가 너무 비대해지고 어려워짐
- 버전3 : 인플루언서는 2방식에서 제외. 1방식으로 전환
- 트위터의 부하 매개변수 : 팬아웃 -> 사용자당 팔로워의 분포, 빈도
- 버전1 : 트윗을 쓰면 테이블에 전역적으로 insert. 각 유저는 타임라인 접근 시점에 join
4-2. 성능 기술하기
- 하둡같은 일괄 처리 시스템은 처리량에 관심이 있지만, 서비스들은 응답시간에 관심이 있다.
- 응답시간은 요청마다 매번 다르다. 따라서, 분포로 생각해야한다.
- 대부분의 요청은 빠르지만, 가끔 오래걸리는 특이점(outlier)이 있다.
- 컨텍스트 스위칭, 네트워크 패킷손실 - TCP재전송, GC, page fault 등 다양한 이유가 있겠다.
- 응답시간 분석에 백분위를 사용하고, 중앙값(p50)을 지표로 삼아라
- 특이점 = p95, p99, p999
- p9999부터는 최적화 비용이 너무 많이들어서 이점이 없다.
- 특이점도 무시할 순 없다. 보통 데이터가 많기 때문에, 발생할 수 있는데, 중요한 고객이기 때문이다.
- SLO(서비스 수준목표. Service Level Objective)와 SLA(서비스 수준 협약서. Service Level Agreement) 가 이럴때 자주 등장함
- ex) 환불의 기준
- 큐 대기 지연은 응답시간의 상당 부분을 차지한다.
- 선두 차단(head-of-line blocking) : 서버는 병렬로 소수 작업만 처리할 수 있기때문에, 첫 요청을 처리하는데 느려진다면 후속 요청이 모두 영향받는다.
- 시스템에 인위적으로 부하를 생성하는 경우, 클라이언트는 응답시간과 독립적으로 요청을 계속 보내야한다. 응답을 기다리고 다음 요청을 보내면 평가가 의미없다.
- cf) nGrinder 같은 전문 부하테스트기 대신 개발자가 부하 시뮬레이터를 만들 경우 고려해야한다.
- 꼬리 지연 증폭(tail latency amplification) : 여러 API를 호출했을 때, 적은 API만 느려도 전체가 느린게 된다.
4-3. 대응 방안
- 용량확장=수직확장=scaling up 과 규모확장=수평확장=scaling out 사이에서 실용적인 조합을 찾아야한다.
- 스케일아웃이 항상 좋지는 않다. 적절히 스케일업된 장비들로 구성된게 더 좋을 때도 있다.
- 탄력적(elastic) : 부하 증가를 감지하면 자동으로 자원 추가
- 이것도 항상 좋지는 않다. 수동 확장이 더 간단하고 예상치 못한 운영이슈가 적다.
- 분산환경이 필요해질때 까진 스케일업하는게 보통이지만, 요새는 분산시스템과 추상화가 워낙 좋아져서, 처음부터 고려해볼만도 하다.
5. 유지보수성
- 많은 사람들은 레거시 시스템을 유지보수하는 것을 좋아하지 않는다.
- 처음부터 레거시를 만들지 않게 끔 설계해야한다.
- 유지보수성 원칙
- 운용성 : 운영팀이 원활하게 운영할 수 있도록 쉽게 만들어라
- 단순성 : 복잡도를 최대한 제거해 새로운 팀원도 잘 이해할 수 있게 만들어라
- 발전성 : 이후 변경에 열려있어야 한다. 요구사항 변경같은 새로운 사용사례를 쉽게 적용할 수 있어야한다.
- 유연성, 수정가능성, 적응성
5-1. 운용성
- 운영 중 일부 측면은 자동화할 수 있고, 자동화해야한다.
- 하지만 자동화를 처음 설정하고 제대로 동작하는 지 확인하는 것도 여전히 사람이 해야한다.
- 좋은 운영성 : 반복되는 태스크들을 쉽게 수행할 수 있도록 하는 것
- 런타임 동작과 시스템 내부에 대한 가시성 제공
- 좋은 문서
- 이해하기 쉬운 운영모델 : X를 하면 Y가 발생
- 어드민 등으로 기본값을 재정의할 수 있는 권한 부여
- 자기 회복이 가능할 뿐아니라 관리자가 상태를 수동으로 제어할 수 있어야 함
5-2. 단순성
- 시스템이 복잡해지면 모든 사람의 진행을 느리게하고, 유지보수 비용이 증가한다.
- 복잡성의 사례들
- 상태 공간의 금증
- 모듈 간 강결합성
- 일관성 없는 네이밍
- 임시방편 코드들
- 우발적 복잡도(accidental complexity)를 제거하기 위한 최상의 도구는 '추상화' 다
- 좋은 추상화는 깔끔하고 직관적인 외관 아래로 세부 구현을 숨길 수 있다.
- 재사용성이 좋아진다.
- ex) 기계어, cpu레지스터, 시스템콜들을 추상화한 것이 고수준 프로그래밍언어다.
5-3. 발전성
- 시스템 요구사항은 계속 바뀐다.
- 애자일(agile) 작업 패턴은 변화에 적응하기 위한 프로세스이다.
- TDD, 리팩토링 등
- 작고 로컬규모에 초점을 맞춰라
'database' 카테고리의 다른 글
[데이터 중심 애플리케이션 설계] 2장. 데이터 모델과 질의 언어 (1) | 2022.05.01 |
---|---|
Redis maxmemory (policy, samples, replica-ignore) (0) | 2022.04.24 |
Kafka 기본 개념 (토픽, 파티션, 성능, 고가용성, 프로듀서, 컨슈머) (1) | 2021.07.11 |
Redis 기본 개념 (기초, Collection 타입, Expire, Persistence) (2) | 2020.06.25 |
Commons DBCP2 (dbcp 정의, 커넥션 속성, Evictor, 트랜잭션, Statements Pool, 예제) (1) | 2018.04.11 |
Comments