마이크로서비스 아키텍처
마이크로 서비스 아키텍처란?
독립적으로 배포 가능한 작은 서비스들이 모여 하나의 큰 시스템을 이루는 ‘느슨하게 연결된’ 집합체
핵심 개념은 정보은닉이다. 내부 구현의 복잡함을 숨기고 사영자에게서는 최소한의 인터페이스만 제공하므로서 독립적인 기능 릴리즈가 용이하게 된다.
SOA와 비슷하다 하지만 SOA는 서비스의 재사용을 목적이 크지만 MSA는 독립적인 하나의 서비스로서 분리하는것이 목표이다. SOA는 서비스들이 서로 통신하는 체계가 복잡해져서 중앙 bus라는 시스템이 존재하게된다. MSA는 서비스의 경계나 인터페이스가 단순하며 그래야만 한다.
독립적 배포성
도메인주도 설계와 잘 어울리고 비지니스 기능의 응집력을 우선시하여 분리해야한다.
자기 상태 소유
서비스들이 데이터베이스를 공유하지 않게하고 서비스 도메인모델에 작합한 부분에 데이터만 사용하더록 독립시켜야 한다.
크기
서비스를 가장 쉽게 이해할수 있는 크기로 제한해야한다.
너무 많은 서비스도 복잡성을 초래할 수 있으므로 점진적 전환 전략이 현실적이다.
유연성
마이크로서비스 아키텍처를 적용하면 유연성이 높아진다.
가치있는 업무 단위를 팀으로 구분해서 독립적으로 배포가능하고 타팀과의 핸드오프 가능성을 최대한 줄여서 효율성을 확보한다.
모놀리스 아키텍처
모놀리스는 MSA에 상반되는 개념이다. 시스템의 한 부분이 배포되려면 모든 부분이 함께 배포되어야 하면 모놀리스식 설계라고 할수 있다.
모놀리스가 결코 나쁜건 아니고 소규모 시스템에서는 적합하다.
초반부터 MSA일 필요는 없지만 나중에 시스텝이 커져서 MSA로 확장할때, 데이터베이스를 분해하기 어렵다는 단점이 있다.
모놀리스 단계라도 모듈별로 데이터베이스를 나눠서 시작하면 나중에 도움이 된다.
분산형 모놀리스
SOA 기능성의 정의를 충족하지만, 약속을 이해하기 힘든 경우를 말한다.
시스템이 분산은 되어 있지만 비지니스 기능의 응집력이 약하고 은닉성이 없다.
모놀리식의 장점
간단한 시스템의 경우 배포가 활씬 간단하며 E2E 테스트도 훨씬 수월하다.
모놀리스는 그 자체로 강력하며 레거시와 동일어가 아니다. 하지만 사람들은 그렇게 착각한다.
주의할점
MSA를 채택할 때 처음부터 많은 기술을 고려하는건 안티패턴이다. 하지만 로그집계와 분산추적은 처음부터 잘 고려할 필요가 있다.
클라우드 업체에서 제공하는 간단한 로깅 시스템도 충분히 좋다.
예거, 라이트스텝, 허니코움 같은은 서비스가 있다.
컨테이너와 쿠버네티스의 개념을 적용하면 효과적으로 MSA를 운영할 수 있다.
이는 상당히 복잡하고 리소스가 들어가므로 클라우드 제공 업체에 시스템을 이용해 관리하는게 최선의 선택이다.
스트리밍
마이크로 서비스간에 데이터를 공유하는 방법이 있어야한다. 대용량 데이터를 쉽게 스트리밍 할수 있는 도구를 선택해야하는데.
대표적인 서비스로는 아파치 카프카가 있다.
공용 클라우드 서비스 AWS나 구글 GCP 등을 사용하면 많은 서버 운영의 복잡한 부분을 클라우드 시스템에 맡길 수 있다.
이기종 아키텍처
Ruby + 문서기반디비 <-> golang + 그래프기반 디비 <-> java + blob 디비 와 같이 msa간 이기종 아키텍처를 서로 연결할수 있게 된다.
모놀리식은 기술을 변경하기가 힘들다. 한 부분을 변경하면 전체의 다른 부분에 영향을 주기 때문이다.
MSA는 작은 서비스 하나에만 기술을 적용해볼수 있기 때문에 전략 및 안정성이 더욱 효과적이다.
견고성
MSA는 서비스 하나에 문제가 생겨도 다른 부분이 격리되어 있기 때문에 견고하다.
확장성
서비스의 확장이 필요한 부분만 확장할 수 있어서 MSA가 유리하다.
다양한 기술을 더 쉽게 확장할 수 있다.
배포 용이성
모놀리식은 코드가 한줄만 수정되도 전체 서비스를 다 배포해야 되기 때문에 위험하다.
기능마다 코드베이스거 작기 때문에 확장 수정에 용이함.
MSA단점
- 너무 많은 기술을 과다하게 사용함으로 인한 혼란
- 더 많은 서비스가 필요하기 때문에 비용절감을 중요하게 생각하면 MSA가 그리 좋지는 않다.
- 모놀리스에 단일체계 관게형 데이터베이스에 비해 분산수집 및 리포팅이 어려워짐
- 보안에 더 많이 신경써야한다.
- 네트워크 지연시간에 영향을 더 많이 받는다.
msa가 비적합한 곳
소규모 팀이나 도메인 모델이 자주 변하는 스타트업 같은 시작하는 단계에서는 오히려 안좋다.
전문가가 직접 운영하는 조직이 아니라 SI로 납품하는 서비스라면 모놀리스가 적합하다.
msa거 적합한 곳
많은 개발자가 동일 시스템에서 서로 방햐받지 않고 적업하기 위한것.
Saas처럼 연중 무후 24시간 동작해야 하는 서비스는 배포관리 등 여러모로 msa가 적절함.
클라우드 시스템을 최대한 활용할 수 있으면 msa가 적합하다.
시스템을 발전시키면서 많은 유연성이 재공된다.
마이크로서비스 모델링방법
정보은닉
모듈의 정보은닉은 모듈들을 병렬로 개발할수 있고 이해하기 쉽다.
Msa는 모듈식 아키텍처의 한 형태다.
응집
관련된 코드는 응집되어 있어야 배포와 수정 확장 관리가 편하다. MSA는 기능들이 강한 응집력을 갖게 해준다.
결합
하나의 마이크로 서비는 당연히 강한 응집력을 갖는게 좋지만 다른 MSA와는 느슨하게 얀결되어 있어야 독립배포 할 수 있다.
응집과 결합의 균형점을 찾으려면 모델이 어느정도 안정되어야 한다. 모델이 자꾸 바뀌면 초기 설계가 자꾸 바뀌게 되므로 서비스간의 관계나 경계도 계속 바뀌게 되기 때문이다.
결합유형 (도메인결합)
하나의 도메인 서비스가 다른 도메인 서비스의 기능을 사용해야 하는 경우를 말한다.
이 유형에서 특정 마이크로서비스는 너무 많은 다른 서비스와 연결되어야 해서 불가피하게 특별히 결합이 많고 복잡해질수 있으며 이건 문제가 될 수 있다.
서비스의 은닉성과 꼭필요한 갓만 공유하고 연결하려는 노력이 필요하다.
특정 서비스를 순서대로 연결해야 성립하는 경우와 같은 시간적 결합은 특히 어렵고 복잡하다.
통과결합
한 서비스가 다른 서비스의 데이터가 필요하다는 이유로 데이터를 여러 서비스에 통과시켜야 하는 경우 은닉성에 위배되기 때문에 문제가 된다.
공통결합
둘 이상의 서비스가 공통의 데이터를 필요로 할때 발생한다.
공유데이터베이스를 여러 서비스가 공용으로 사용할때.
데이터의 구조가 변경되면 여러 서비스에 영향을 주게 된다.
상태기계를 사용하면 해당 문제에 도움이 된다.
특정 상태로 변경되기 위한 전제조건을 확실히 정해서 체크하는게 상태기계다.
하나의 서비스가 이런 상태기계를 전담하게 하면 경함없이 유용하게 사용할 수 있다.
내용 경합
상위서비스가 하위서비스의 내부까지 관여해, 하위 서비스의 상태를 변경하는 것이다.
내용결합은 정보은닉의 개념이 사라지게 되므로 명확한 계약이 아니라 안묵적 계약이 생기게 되므로 관리가 힘들어진다.
도메인 경계
DDD의 도메인 경계를 사용하여 서비스의 경계를 찾는다.
보편언어
도메인 전문가와 커뮤니케이션을 명쾌하기 위한 유비쿼터스언어를 말함
에그리거트
도매인주도 설계에 생명주기를 함께하는 객체집합
하나의 서비스에 관련된 에그리거트가 존재하면 관계형데이터베이스를 이용할수도 있지만, 여러 서버에 걸쳐 에그리거트가 관리되어야 한다면 관계를 모델링할 방법이 필요함.
MSA에서는 서비스간에 아이디를 임시로 저장하여 고유하게 사용할 경우 URL을 이용하는 것도 좋은 방법이다.
REST API를 사용하지 않을 경우 별도의 uri스킴 룰을 정의하여 사용하는것도 좋다.
경계 컨텍스트
여러 에그리거트를 포함하는 서비스의 경계를 말한다.
하나의 경계 컨텍스트는 하나의 서버의 경계로 표현할 수 있고 그렇게 하는게 당연해 보이지만, 항상 그런건 아니다. 초기의 경우에는 여러 경계 컨텍스트가 하나로 묶여 간단한 서비스가 될수 있다. 반면 너무 큰 1개의 경계컨텍스트의 규모가 너무 큰 경우 하나의 경계컨텍스트가 여러 서비스로 쪼개지는 경우도 있다.
거북이 아래 거북이
여러개의 마이크로서비스를 하나의 대분회된 마이크로서비스로 감싸 사용자에게 내부 서비스를 은닉하게 할수도 있다.
이벤트 스토밍
“시스템에서 발생하는 ‘이벤트’를 중심으로 전체 흐름을 시각적으로 풀어내는 방법”
DDD에서 개념을 뽑아낼때 증요한 이벤트를 주요 개념으로 뽑아내면 모델링이 좀더 분명해 지는걸 말한다.
객체지향 증심의 DDD로 풀어보자면 프로세스를 객체화 해서 뽑아내는 개념이다.
DDD는 마이크로서비스아키텍처를 구축할때 매우 편리하다.
도메인경계에 대한 대안
경계를 나누는데 DDD가 유용하긴 하지만 그게 전부는 아니며, 다른 방법론도 많다.
변동성에 의한 분해
자주 함께 바뀌는 것들끼리 묶어서 경계를 나누면 자주 안바뀌는 부분에 안정성을 유지하면서 변경할수 있다는 개념이다.
좋은방법은 아니다.
데이터에 의한 분해
데이터의 종류에 의해 분해한다. 예를 들면 보안에 민감한 부분과 민감하지 않은 부분을 분리하는 것.
기술에 의한 준해
어떤 도메인 구간이 특정 기술을 사용하면 여러모로 편리하고 이점이 많다면, 기술을 경계로 분해할수도 있다. 하지만 이상적이지 않은 경우가 많다.
조직에 의하누분해
조직의 기반이 분리되어 있다면 조직에 의한 분리가 필요할수도 있다.
혼합방식
위에 설명한 여러가지 경계 방법을 혼합해야 하는 경우도 많다.
모놀리스 분해
마이크로서비스로 부터 프로젝트를 시작하려고 하는건 좋은 생각이 아니다. 기존 모노리스가 관리가 힘들어질때 조금씩 마이그레이션 하여 분리하는게 이상적이다.
모노리스와 마이크로서비스가 공존하는건 엉망인 상태가 아니라 이상적인 상태다.
조급한 븐해의 위험성
모놀리스 프로젝트의 도메인을 제대로 이해하지 못한채 서비스를 분해하려는 시도는 매우 위험한 시도다.
무앗을 먼자 나눌까?
- 추출했을때의 이점은 무앗인가?
- 추출하는 작업이 용이한가?
이 두가지를 잘 고려하는게 좋다.
먼저 가장 쉽게 분해할 수 있는 것부터 시작하라.
만약 성공하면 점점 추진력을 얻어서 분리해 나간다. 하지만 가장 쉬운것도 실패한다면… 정말 분해하는게 올바른 서비스인지 다시 생각해봐야 한다.
좀 더 도메인을 더 잘 이해한 후 문제를 시도하는게 좋을지도 모른다.
계층분해
Ui관련 코드를 분해하는게 가장 이득이 많다.
코드우선분리
그 다음은 우선 코드 우선 분리가 가장 정석이다.
데이터가 추츨 가능한지 함께 미리 고려하는것이 바람직하다.
데이터우선
흔하지는 않지만 데이터를 분해하고 시작하는 경우도 종종 있다. 코드 우선분해보다 당장에 이점은 없지만, 설계상에 이점이 있다.
유용한 분해패턴
- 교살자 패턴
- 병렬실행 - 원래기능과 분리하는 기능을 병렬로 실행하여 비교해본다.
- 기능 토글 - 원래 서비스와 쉽게 토글될수 있게 만든다.
데이터무결성
마이크로서비스로 분해되면 기존 디비의 트렌젝션 기능은 쓸수 없고 분산 트렌젝션이나 이에 준하는 다른 도구를 사용해야 하는데 또다른 복잡성이 초래되므로 주의해야한다.
플라이웨이디비나 리퀴베이스 같은 도구들이 있다.
리포팅 데이터베이스
마이크로서비스가 다른 마이크로서비스이터를 위해 리포팅 데이터베이스를 제공 하는 방법이 있으며 스키마가 변경되더라도 다른 서비스와의 기존 호완성을 위해 계속 관리해주어야하는 지속적인 수고가 필요하다.
마이크로서비스 통신방식
프로세스 내부에서 프로세스 사이로
기존 모놀리스에서는 내부 함수호출로 네트워크 비용이나 메모리 비용없이 자동으로 최적화가 일어난다. 하지만 여러개의 서비스로 나뉘면 메모리 복사나 네트워크 비용이 발생할 수 있으므로 개발자가 이런 사실을 정확힐 알고 있어야 한다.
인터페이스변경
하위호완성을 깨뜨리는 인터페이스를 변경할때는 서비스를 단계적으로 배포할 계획이 먼저 수립되어야한다.
에러처리
마이크로서비스간의 오류는 충동실패, 타이밍실패, 임의실패, 누락실패 등이 있다.
이런 실패는 보통 시간이 해결해주는 경우가 많지만 어떤 경우에는 사람이 개입해야 한다.
어떤 종류의 에러인지는 400 ,501, 503 등의 일반적으로 약속된 에러코드 규약이 도움이 된다.
HTTP 응답체계와 별개로 풍부한 응답체계가 있으면 더 견고한 시스템을 구축할 수 있다.
마이크로서비스 통신방식
- 동기식 블로킹
일반적이고 예측이 쉽지만 시간적 결합이 있다. 호출체인이길어지면 문제가 생길수있다 호출 체임이 길어지면 문제가 생길 수 있다.
- 비동기 요청 및 응답
메세지 브로커를 이용하여 비동기로 병렬 처리한다.
async await 을 이용하면 특정 경우 편리하게 이용가능하다.
공용데이터를 파일로 떨구고 공유하는 방식도 비동기 논블로킹의 일종이라고 할수 있다.
- 이벤트기반
이벤트 발행 구독 패턴으로 동작한다.
레벳엠큐 와 같은 도구를 사용한다.
단점은 이벤트가 잠잠 많아져서 복잡해지고 부하가 생길 가능성이 있다는것이다. 해결방법은 한번에 이벤트에 많은 정보를 담아 불필요한 이벤트를 줄이는 것이다.
하지만 너무 많은 데이터는 용량때문에 문제가 될수도 있고 이벤트에 특정한 정보를 포함히기 시작하면 계약의 일부가 되어버리기 때문에 주의해야한다.
요즘은 요청응답 보다는 어벤트 기반으로 바뀌는 추세다.
자신의 서버시에 걸맞는 통신방식을 선택해야 한다.
신중하게 선택하기
비동기식이나 동기식 이벤트 기반을 자신에 서비스에 맞는 방법으로 신중히 선택해야 한다. 각각의 패턴에는 단점과 장점이 있으며 다 각기 문제점을 갖고 있다. 다만 해결책이나 문제 패턴의 익숙함만 틀릴 뿐이다.
마이로서비스의 통신구현
하위호완성
하위호완성을 고려하여 통신방법 기술선택을 고려해야한다.
인터페이스를 명시적으로 하라
스키마가 있어야 하며 명시적 스키마를 지녀야지 서비서가 어떤 기능을 제공하는지 명확해진다.
api를 기술 중립적으로 유지하라.
통합 기술 스택을 강요하는건 바람직하지 않다. 변화에 항상 열려있는게 바람직하다.
서비스를 단순하게 만들어라
마이크로서비스 때문에 너무 복잡해진다면, 마이크로서비스는 필요없을수도 있다.
사용자들이 서비스를 쉽게 사용하는걸 항상 증요하게 생각해야한다.
원격프로시저 호출
마이크로서비스 환경에서 RPC는 매우 매력적인 선택이다. 원격 서비스를 함수 호출로 처리할수 있어서 매우 간편하다.
네트워크 통신은 비용이 크므로 간단한 대신 큰 비용을 간과하거나 방심할 수 있음에 유의해야 한다.
레거시 시스템에 기술제약이 있을 수 있으므로 그런 경우 rest 를 고려하는게 좋다.
rest
Rest는 가장 보편적으로 사용하는 통신 규약이다. http 방식의 rest가 가장 편하고 효울적이다.
Rest api는 여전히 효과적이고 안정적이지만, grpc와 같은 다른 대안들에 비교해 덜 효과적일 수 있다.
어플리케이션 상태엔진으로서의 하이퍼미디어
하이퍼미디어란 텍스트 이미지 비디오 같은 리소스가 컨텐츠로 표현되는 개념이다.
하이퍼미디어란 콘텐츠의 UI가 변하더라도 컨텐츠의 속성을 암묵적으로 알수 있게하는 의미 규약이다.
현재로서는 하이퍼미디어의 개념과 마이크로서비스의 구축방식이 잘 맞아떨어지지 않는다.
GraphQL
단점으로 서버측에 너무 과한 부하를 준다 .sql은 문제를 추작하기 쉽지만, graphql은 무책임해 보인다.
캐싱을 하기에도 너무 복잡하고 어렵다.
GraphQL 만으로는 아직 충분하지 않고 하이브리드 정략으로 필요한 경우에만 graphql을 쓰는것이 올바라 보인다.
GraphQL이 마이크로서비스의 은닉성을 회손하는것 처럼 쓰이는 경우도 있으므로 주의해야 한다.
GraphQL은 외부에 서비스되는 api를 다 친숙하게 접근할수 있도록 할때 적합하다.
메세지 브로커
카프카나 레빗엠큐같은 도구를 사용하는걸 의미함.
토픽이나 큐의 개념을 이용해서 메세지를 전달.
마이크로서비스에서 이런 메세지브로커의 전달보장 약속은 매우 유용하고 편리하다.
하지만 이런 전달 보장 기능 조차도 제약사항이 있으므로 설명 문서를 잘 읽어봐야 한다.
제약사항도 존재하는데… 예를 들어 카프카의 경우 같은 파티션 내에서만 전달 순서를 보장한다.
특히 메세지 소비자가 같은 메세지를 중복으로 전달 받을수도 있는데… 이런 부분은 메세지 브로커의 특성이므로 브로커 자체만으로 완벽하게 제어하기 힘들다. 클라이언트에서 메세지 고유 아이디 처리를 통해 해결하는 방식 같은걸 고려해야 후ㅏㄹ수도 있다.
대표적인 메세지 브로커는 레빗엠큐 엑티브엠큐 카프카 등이 있고 클라우드 서비스 제공업체가 지원하는 기능도 있다.
카프카
특히 카프카가 가장 인기있는데, 대용량 메세지 처리를 위해 설계되었으며, 다른 브로커에 없는 메세지 영속성 기능이 있어서 예전 메세지를 다시 처리하거나 이용할 수 있다.
또한 카프카는 스트림 처리를 기본으로 제공한다.
Ksql을 사용하면 하나 이상의 토픽을 즉석에서 함께 처리하는 데이터베이스의 뷰와 유사한 기능을 제공할 수 있다
직렬화 포멧
텍스트 포멧으로는 XML JSON이 널리 쓰이면 JSON이 간결성으로 인해 더 많이 쓰인다.
페이로드 크기나 효율성이 중요한 경우, 바이나리 포멧이 쓰이기도 한다. 대표작으로 SBE 같은 포멧이 있다.
스키마
마이크로 서비스의 통신에는 스키마는 산택적이지만… 스키마를 선택하는 편이 여러모로 유리하다.
스키마가 어긋나는건 구조적 계약위반이다.
의미적 계약위반은 함수의 실제 구현 내용이 틀려지는게 의미적 계약 위반이라고 한다.
스키마를 사용하는건 정적타입언어의 컴파일러를 사용하는 것과 비슷한 개념이다.
동적타입의 언어도 나름대로의 장점이 있지만 스키마와 통신의면만 비교하면 스키마가 있는쪽이 절대적으로 좋다.
하지만 데이터제공과 소비를 한팀에서 다루는 상황에서는 스키마가 없는 쪽이 더 좋을수도 있다.
마이크로서비스간의 변경처리
중단변경은 피하는게 좋다.
- 확장변경
기존것은 지우지 않고 변경은 확장변경만 하는걸 말한다.
- 관대한 독자
다른 마이크로서비스와 통신할때, 관신없는 속성에 대해서는 변경에대해 무시할수 있게 만드는 패턴을 관대한독자 패턴이라고 한다.
자신에겐 엄격하게하고 남에게서 받아들일때는 너그럽게 하라.
마이크로서비스 엔드포인트에는 스키마가 정의도어 있는 편이 좋다. 비교적 새로운 베세지 이벤트 기반에서도 스키마를 정의하는 흐름이 점점 발전되고 있다.
우발적 변경을 일찍 발견하기
스키마를 사용하면 변경을 빨리 파악할 수 있다.
많은 스키마 변경 비교 도구가 있다.
스키마 비교 도구는 구조적 변경을 위해 존재하지만, 의미적 변경을 방어하기 위해서는 테스트 코드를 촘촘히 하려는 노력이 필요하다.
락스탑 배포
하위호완되지 않는 버전으로 배포할 경우 사용자에게도 변경할 시간을 주는 패턴이다.
- 다른 버전의 여러 서비스를 제공하기
- 새로운 버전에 기존 버전의 인터페이스를 지원하도록 애뮬레이션 지원
마이크로서비스 세계에서 dry 코드 재사용 위함
Dry는 좋은 격언이지만 마이크로서비스에서는 애매한 경우도 있다.
서로다른 마이크로서비스간에 공유코드를 상요하면 불필요한 사용자 변경이 생겨날 수 있다. 잠재적 결합이 생기는 것이다.
라이브러리를 여러서비스에서 사용할 경우 라이브러리의 다른 여러 버전이, 각각 다른 서비스간에 다른 버전이 사용될수 있음을 유의해야 한다.
클라이언트 라이브러리 패턴을 쓸 경우 도메인 로직이나 서버와의 결합이 없어야 한다.
서로 다른 서비스가 독립적으로 클라이언트 라이브러리를 업데이트 해도 상관없는지 신중히 고려해야 한다.
서비스 디스커버리
현재 사용되고 있는 MSA들을 파악하고 모니터링 하는걸 마이크로서비스 디스커버리라고 부른다.
1. 도메인네임 시스템
예를 들어. accounts.service.com 과 같은 서브도메인을 활용하여 마이크로 서비스를 나누는 걸 말한다.
여러 DNA를 생성하고 파기하는 과정이 번거롭다는 단점이 있다.
DNS는 여러 분산된 서버에 캐싱될 수 있으며 ttl이라는 시간 동안 유지된다.
로드밸런서 전략을 사용하면 인스턴스 서버를 넣거나 빼기 쉽다.
2. 동적서비스 레지스트리
- 주키퍼
주키퍼를 MSA 디스커버리로 사용할 수 있다고 하는데 추천하지는 않는다고 한다.
서비스 아이피들을 주키퍼에 등록해 주며 주키퍼에서 health 체크등을 해주고 서비스에서 제외하거나 추가해준다.
- 콘슐
주키퍼와 비슷하지만 http rest 를 사용하므로 다양한 스택과의 통합이 가능하다.
콘슐 + envoy(사이드카) 메시 구조로 많이 사용.
- ETCD와 쿠버네티스
쿠버네티스는 잘 알려진 컨테이너 오케스트레이션인데, 쿠버네티스는 콘슐과 비슷한 기능을 가진 ETCD 라는걸 사용해 디스커버리를 지원한다.
컨테이너와 클라우드 환경에서 유리함.
서비스메시와 api 게이트웨이
메시는 내부애서의 통신을 책임지고 게이트웨이는 내ㅜ외부를 연결해주는 역할이다. 메시는 내부에서 통신을 책임지며, 게이트웨이는 내 외부를 연결해주는 역할을 한다.
api 게이트위이
API 게이트웨이의 역할은 외부의 요청을 내부의 MSA서비스에 연결해주는것이다.
리버스프록시로 동작한다. API키, 로깅 속도 제한같은 기능을 추가로 설정할수 있다.
쿠버네티스 클러스터끼리의 통신 외에 용도로 게이트웨이 api를 사용하는것은 과잉 조치이다.
API 게이트웨이의 중간개입은 복잡도를 높이므로 안좋은 경우가 더 많다.
MSA간 중간호출자로 API게이트를 사용하는건 네트워크 호출 지연에 따른 오버헤드 문제가 있어서 비효율적임, 이런 경우 서비스 메시가 더 적합함
서비스 메시
마이크로서비스간 통신에 관련된 모든기능이 전담된다.
서로다른 기술을 사용하는 마이크로서비스간 표준 동작을 구현하는데 매우 유용하다.
하위호완성이 보장되지 않는 배포시 재빌드와 재배포를 하지 않고 유연하게 체인지 가능하다.
서비스메시는 남북방향의 네트워크 통신을 피하고 동서방향의 네트워크를 최대한 이용하도록 도와주고 네트워크 디스커버리를 담당하는 로컬프록시(envoy)를 통해 이를 해결한다.
각각의 서비스는 각각의 통신을 담당하는 메시 프록시 엔보이를 갖게 된다.
작은 규모의 마이크로서비스들은 서비스메시가 오히려 복잡성만 더할 뿐 이득이 없을수도 있고, 서비스 메시는 아직 성숙된 기술이 아니기도 하다.
하지만 대규모 미이크로서비스에서의 서비스매시는 효과적인걸로 입증되었다.
쿠버환경에서는 자동으로 처리해주는게 많으므로 더 효과적이다. 마이크로서비스는 10개 이상의 서비스간 호출이 복잡할때 유용하다.
서비스메시는 주로 http프로토콜을 처리하는 경우 유용하며 메세지 브로커만을 이용할 경우 이런 메시 사용이 애매해질 수 있다.
휴면레지스트리와 같은 개념을 이용하면 엔드포인트에 대한 정보를 관리할수 있다.(사내 위키 같은걸 말한다)
워크플로우
마이크로서비스간의 협업이나 트랜젝션 처리는 어떻게 할까?
데이터베이스 트랜젝션
트랜젝션이란 단일 단위로 취급하고 싶은 하나 이상의 작업이다.
ACID 트랜젝션
일반적인 데이터베이스 트랜젝션을 말할때는 acid 트랜젝션을 의미한다.
- 원자성
- 일관성
- 격리성
- 내구성
믈론 모든 데이터베이스가 acid 트랜젝션을 지원하지는 않는다.
분산 트랜젝션
2개 이상의 분리되어있는 데이터베이스상에 마이크로서비스에서 작업의 원자성이 필요한 경우 2단계 트렌젠션(2PC)를 사용할 수 있다.
각각의 프로세스는 워커를 가지고 있고, 조장자에게 워커가 vertify요청을 보내 모드 혐의가 될 경우 변경을 실행한다.
분산 트렌젝션에는 참여자가 많을수록 지원범위가 크고 길수록 문제가 발생하므로 신중히 생각하고 적용해야 한다.
웬만하면 그냥 안하는게 좋다(실질적으로 너무 복잡해지고 비용도 크다).
사가패턴
요점은 오래 걸리는 트랜젝션을 서비스 단위의 트랜젝션으로 나눠서 처리하는 것이다.
서비스 단위로 트랜젠션을 분리하고 실패시 이미 처리된 서비스는 reset하지 않고 revert 시키는 것이다.
역방향 복구는 revert를 해주면 되고, 정방향복구는 실패를 다시 시도하는것이다.
워크플로우를 리버트하기 쉽게 재정렬 해놓으면 트랜젝션 처리를 쉽게 할수 있다.
오케스트레이션형 사가
중앙 조정자가 실행순서를 정의하고 보상조치를 트리거하는 방식.
중앙 조정자가 비지니스 로직을 너무 많이 흡수하는 단점이 있다. 이를 완화하는 방법은 각각의 처리마다 서로다른 서비스가 중앙 오케스트레이터 역할을 하게 하는 것이다.
코레오그래피 사가
중앙집중식 명령과 고나리로 프로세스가 관리되지 않고 각각의 렵력 서비스로 책임을 분한하는 것이다.
각각의 서비스는 이벤트를 단지 구독하고 있고, 이벤트가 일어나면, 필요한 서비스에서 적절한 처리를 알아서 한다. 이벤트 기반 처리가 연관된 서비스 전반에 걸쳐 이루어진다.
단점은 어떤일이 일어나고 있는지 파악하기 힘들다는 것이다. 상관관계아이디를 발행하여 이 아이디를 포함한 로그를 쌓는 방식으로 이 부분을 보완할 수 있다.
혼합방식
꼭 두 가지중 하나만 선택해야 하는건 아니다. 혼합해서 사용해도 된다.
하나의 팀에서 여러 서비스를 관리할 경우 오케스트레이션 방식이 적합하며, 여러팀으로 이루어진 경우 코래오그래피형이 적합하다. 필자의 경우 진행사항을 추적하는 추가 복잡성보다, 느슨한 결합의 이점이 더 크기 때문에 감수할만 한다.
사가와 븐산트랜잭션
분산트랜잭션은 위험하기때문에 사가를 사용하는 편을 추천한다.
빌드
마이크로서비스에 지속적 통합과 지속적 제공에 대해 다룬다.
모든 코드의 버전을 제어해 투명성을 강화하고 빌드를 쉽게 복제할수 있게한다.
브랜치 모델
트렁크기반 개발이란 개발자들이 각각의 브랜치에서 작업하는게 아니라. 하나의 브랜치에서 자주 통합하면서 함께 작업하는걸 말한다.
오픈소스개발방식은 깃플로우는 오픈소스에 적합하지만 일반적인 개발방식에는 트렁크기반 방식이 적합하다.
코드 커밋을 더 빨리 자주할수록 좋다.
빌드 파이프라인과 지속적 제공
더 빠른 배포와 더 운영환경과 유사한 환경에서 테스트 되도록 최대한 노력해야한다.
산출물 생성
효울을 위해서 산츨물 생성을 위한 빌드는 딱 한번만 실행되어야 한다.
검증할 산출물이 실제 배포될 산출물과 같아야 한다.
환경마다 빌드 산출물이 틀려서는 안된다. 하나의 빌드를 여러 산출물에서 활용할 수 있어야 한다.
거대한 리퍼지토리 하나와 거대한 빌드
쉽지만 어느서비스가 변경되었는지 정확히 알기가 어렵다. 하나가 잘못되면 전체 빌드가 깨진다. 한마디로 결합이 너무 높다. 이런 경우는 분면 모노레포의 한 형태지만 모든것을 함께 배포하는 방식으로 되돌아가기 쉽다.
멀티리포( 서비스 하나당 하나의 리포)
한번에 연관된 여러 서비스를 작업해야 할때 단점이 될수 있다.
하나의 서비스가 다른 리포의 코드를 참고해야 할 경우 라이브러리로 패키징하여 제공하는 방법을 써야한다.
여러 레포지토리가 하나의 코드를 공유하는 상황에서는, 공유 코드의 수정과 배포가 서비스에 어떤 영향을 미치는지 더 주의 깊게 다뤄야 한다. 이 과정에서 서비스의 경계에 대해 더 깊이 이해하게 되므로, 장점이 있다.
모노레포
서비스간 코드를 재활용하기 쉽다. 하지만 빌드시 조금 복잡해진다.
프로젝트간에 보다 세분화된 코드의 재활용이 장점이다.
모노레포는 팀의 규모가 커질수록 디렉터리별 소유권 개념을 강력하게 조정할 수 있다. 깃헙에서도 2016년 부터 이 기능을 제공한다.
마소에서 사용하는 깃용 vfs는 거대한 모노레포의 특정 디렉토리만 다운로드해서 사용할수 있다.
대기업에서 한다니까 그냥 따라하기 보다는 팀자다 자신에 맞는 방법을 찾는게 좋다.
배포
다수 인스턴스
각각의 서비스 인스턴스는 허나가 아닌 여러개일 가능성이 많다. 때로는 견고성을 이유로 하나의 서비스에 대한 인스턴스들이 여러 데이터센터에 분산되어야 할 수 있다.
데이터베이스
마이크로서비스간 데이터베이스는 공유되지 않는게 좋다.
하지만 동일한 서비스의 여러 인스턴스는 단일 데이스를 공유할수 있다.
데이터베이스는 읽기복제본 노드를 여러개 만들어 부하를 분산할수 있다.
각각의 서비스는 자신의 서비스만의 인프라스트럭처를 구성하는게 안정작이다. 하지만 온프로미스에서는 그렇게 하기 힘들다.
데이터베이스도 마찬가지로 빌드 결과물이 환경 정보와 분리되는게 좋다.
배포되는 환경에 인스턴스가 몇개 필요할지가 대표적인 환경설정의 일부이며 매개변수화 하여 쉽게 설정할수 있게 하는게 좋다.
마이크로서비스 배포의 원칙
- 격리실행
각각의 서비스는 격리된 자신만에 자원을 사용해야 하며 다른 서비스와 자원을 공유해서는 안된다.
- 자동화집중
배포는 자동화되어야 한다 당연하다. 서비스가 커질수록 배포에 신경쓸께 많아진다.
- 코드형 인프라스트럭처
배포를 위한 정보를 소스코드에 저장하라. 배포자동화에 용이해진다.
- 무중단배포
다른서비스에 영향이 없도록 다운타임 없이 배포 가능해야 한다.
- 기대상태관리
플랫폼의 힘을 빌리면 장애나 트래픽 증가시 새로운 인스턴스를 쉽게 추가 가능해야 한다.
배포방법
물리머신배포, 가상머신배포, 컨테이너배포, paas, faas
어떤 배포가 적합할까?
유행에 따라 기술 결정을 내리지 말고 지금 방법이 효과가 있다면 계속하라.
고장나지 않았다면 고치지 마라.
자신이 통제하지 않아도 잘 동작한다면 그냥 맡겨라(플랫폼을 이용해라)
그래도 현재 규모에서 운영이 어렵고 확장이 용이한 형태를 고려해야 한다면 쿠버네티스를 고려하라.
쿠버네티스
도커는 도커스웜과 같은 기술을 선보였지만 여전히 쿠버네티스와 경쟁할수 없었다.
쿠버네티스 없이 컨테이너 인스턴스 시작 및 네트워킹 관리를 위한 스크립트를 작성하는건 정말 지루하고 힘든일이다.
쿠버네티스 클러스터는 컨트롤 플레인과 머신들의 집합인 노드가 있다.
보통 하나의 파드에는 하나의 컨테이너가 있지만 여러 칸테이너가 서로 생명주기를 같이해야 하는경우는 하나의 파드에 묶어서 생성되고 소멸된다. 쿠버노드는 파드 단위로 인스턴스를 제어한다.
클러스터 내에서 서비스는 안정적인 엔드포인트 라우팅 역할을 한다. 파드는 상황에따라 종료될 수 있지만 서비스는 계속 유지된다.
리플리카셋
리플리카셋은 파드들을 제어하고 디플로이먼트를 통해 리플리카셋을 제어한다.
간략히 말하면 디플로이먼트와 리플레카셋을 통해 실행중인 포드에 변경사항을 적용할 수 있다는 것이다.
실행 중인 파드를 직접 수정하는 것이 아니라 디플로이먼트 설정을 바꾸면 쿠버네티스가 알아서 새 파드를 만들고 기존 파드를 교체해준다는 뜻입니다.
멀티테넨시와 페더레이션
자원에 서로다른 조직에 적절한 제어가 필요하다. 이런 지원은 쿠버 자체에는 없으므로 적잘한 다른 도구를 사용해야한다.
예를 들면 레드헷의 오픈시프트 같은 플랫폼이다.
다른 방법으로는 페데레이션 모델을 고려하는 것이다. 페데레이션모델은 여러개의 클러스터를 관리하는 툴을 두는 것이다.
페데레이션 사용은 클러스터 자체를 업그레이드 할때도 이용할 수 있어서 편리하다.
-
멀티테넌시(Multi-tenancy)
- 하나의 쿠버네티스 클러스터를 여러 조직, 팀, 사용자 그룹이 나눠 쓰는 방식
-
페더레이션(Federation)
- 여러 개의 쿠버네티스 클러스터를 하나의 관리 체계로 묶어서 운영하는 방식
헬름 오포레이터 CRD
쿠버네티스 자체는 플렛폼이 아니며 다른 도구들을 혼합하여 자체 플랫폼을 구상할수 있게하는 도구다.
쿠버네티스의 패키지매니저라고 불르는 핼름 이나 오퍼레이터 같은 도구를 이용해 어프리케이션 버전이나 수명주기관리를 할수 있으며 CRD API를 통해 쿠버네티스에 새로운 동작을 연결할수 있다. 사용 방법에 대한 일반적인 패턴은 없고 매우 혼란스러운 생태계이다.
Helm은 운영에 필요한 쿠버네티스 리소스 묶음을 패키지로 제공해서 설치와 업그레이드를 편하게 해주는 개념이고, Operator는 복잡한 애플리케이션 운영 작업을 쿠버네티스 방식으로 자동화해주는 개념이다.
Knative 는 쿠버네티스를 사용하여 개발자들에게 faas를 워크플로우를제공하는 오픈소스다.
여기에 Istio라는 서비스메시를 연결할수 있다.
미래의 쿠버네티스
지금은 매우 혼란스럽지만 사실 쿠버는 현재 개발자 친화적이지 않고 단기적인 형태로 보인다.
앞으로는 좀 더 추상화 계층 뒤로 숨겨진 형태로 쿠버네티스가 쓰일 것처럼 보인다.
미래가 될수록 개발자가 소프트웨어가 하부 머신에 매핑되는걸 세세하게 걱정하지 않아되 되는걸 의미한다.
쿠버네티스를 직접운영하는건 매우 어려운 일이므로 대기업들은 대부분 전문업체에 아웃소싱 한다.
일반 개발자들은 건단하게 쿠버가 어떻게 동작하는지 로컬에서 돌려보는걸로 충분하다 하지만 플랫폼을 관리할 사람들은 더 깊이 파고들 필요가 있다.
카타코다에는 이런 사람들을 위한 훌륭한 자섭서가 제공되고 있다.
점진적 제공
소프트웨어를 자주 배포하는 조직이 실패율을 낮춘다는게 증명되었다.
직접배포보다는 점진적 배포가 안전하다.
배포와 릴리즈의 분리
블루그린 배포가 이에 속한다 특정 버전을 모든서버에 바로 릴리즈 하지 않고 점진적으로 릴리즈 하는걸 말함.
카탈리나 릴리즈는 제한된 고객에게만 먼저 새 기능을 제공한다는 의미다.
테스트
이 책에서 말하는 서비스 테스트는 서비스 단위위 통합테스트를 말한다.
통합테스트는 보통 스텁이나 목을 사용한다.
스톱은 약속된 반환값을 돌려주고 목은 몇번 실행되었는지 등을 기록한다.
스텁 서비스를 이용하면 편할수 있다.
엔드투엔드 테스트
득보다 실이 많은 테스트다.
좀더 소비자 계약 중심의 통합테스트가 e2e 테스트를 대체할수 있으며. 대표적으로는 팩트와 같은 서비스가 있다.
운영중테스트
카탈리나테스트 스모크테스트 헬스체크 기능토글 등이 전무 운영중 테스트를 위한 기법들이다.
운영중 환경의 테스트를 만들때는 테스트가 서비스에 영향이 없도록 신경써야 한다.
문제를 조기에 발견하고 이전 버전으로 롤백을 쉽게 할수 있다면 좋다.
어떤 경우에는 테스트 없이 배포하는게 더 편명한 경우도 있다. 특정 아이디어나 비지니스모델을 빠르게 증명하기 위한 경우.
교차테스트
성능테스트와 견고성 테스트같은 것들이다.
동시 접속자수 테스트속도 테스트 보안테스트 같은 것들이다.
모니터링에서 관찰가능성으로
모놀리스에서 마이크로서비스로 변환되면 모든 장애에 대한 추측이 힘들어진다.
단일 마이크로서비스 단일서버
단일 마이크로서비스 다수서버
다수 서버에서 각각 확인하면 번거러울수 있으므로 ssh 멀티플랙서 같은 도구가 편리할 수 있다.
로드밸런서에 로그를 남기는 방식으로 모니터링
다수 마이크로서비스 다수서버
효율적인 모니터링을 위해 관찰가능성이라는 개념이 필요하다.
관찰가능성이란. 외부출력을 바탕으로 내부상태를 가늠해볼 수 있는걸 말한다.
모니터링을 좀더 체계화되고 지능적이게 하는걸 의미한다.
좀 더 적극적인 모니터링을 관찰가능성이라고 한다.
관찰가능성의 구축
크게 로그집계 메트릭집계 분산추적 으로 나눌수 있다.
로그집계
여러 서버와 서비스를 중앙 로그 집계서버로 집중시켜야 하며. 쿼리로 유용한 정보를 알아오려면 일정한 포멧 규칙이 있어야 한다.
구축 초기부터 상관관계 아이디를 남기는 포맷을 만들어 놓으면 유용하다. 나중에 상관관계 아이디를 추가하려고 하면 더 큰 애를 먹게되고 쉽지 않다.
적절한 분산추적도구를 사용하면 서로다른 서비스간의 로그 타이밍 순서도 추적할 수 있다.
인기있는 로그추적 도구는 플루언트라는게 있다.
휴미오나 데이터독 같은 서비스가 인기있다.
이런 로그집계 솔루션의 단점은 엄청난 양의 데이터 저장공간이 필요하고, 적절한 시점에 대에터를 옮겨야 한다는 것이다. 어떤 로그가 중요한지 선별하는 선택이 힘들수도 있다.
메트릭 집계
CPU 부하 집계나 초당 4xx 오류 집계와 같은 것이다.
이런 집계나 도구를 잘 이용하면 용량계획을 수립하는데도 도움이 된다.
요즘은 수분안에 서버 자원을 재확장하거나 수축할 수 있다.
응답시간 시피유 사용량 디스크공간 등을 집계한다.
카디널리티
수집하려는 데이터에 쉽게 접근할 수 있게 해주는 속성의 수라고 생각하면 된다.
카디널리티는 높을수록 좋은 것이 아니라, 필요한 만큼만 낮게 유지하는 것이 중요하다.
Prometheus는 메트릭 집계를 위한 가장 인기 있는 오픈소스 도구 중 하나다.
분산추적
하나의 요청에 속하는 각각의 작업 단위를 스팬(span) 이라고 한다.
분산 추적(distributed tracing) 은 하나의 요청이 여러 서비스와 작업 단위를 거쳐 처리될 때, 그 흐름을 추적할 수 있게 해주는 방식이다.
이를 위해 각 요청에는 추적 ID(trace ID) 를 붙이고, 요청이 거쳐 간 각 작업 단위마다 스팬 정보를 남긴다. 이 스팬 정보에는 작업 이름, 시작 시간, 종료 시간, 처리 시간, 에러 여부, 호출 관계 같은 정보가 포함된다.
다만 모든 요청을 전부 추적하면 데이터 양이 너무 많아질 수 있기 때문에, 유효한 정보를 얻을 수 있도록 적절히 샘플링(sampling) 하는 것도 중요하다.
상업용 도구로는 Honeycomb, Datadog, New Relic 같은 도구들이 있고, 구현은 OpenTelemetry 같은 표준 API와 규약을 따라 할 수 있다.
마이크로서비스에서는 개별 서비스가 정상처럼 보여도, 전체 요청 흐름에서는 문제가 생길 수 있다. 예를 들어 주문 서비스는 정상이고 결제 서비스도 정상인데, 두 서비스 사이의 호출이 느리거나 실패할 수 있다.
그래서 마이크로서비스 환경에서는 단순히 “각 서비스가 살아 있는가?”만 보는 것으로는 부족하다. 서비스들이 서로 어떤 관계로 연결되어 있고, 요청이 전체 흐름에서 문제없이 처리되는지를 봐야 한다.
분산 추적은 바로 이런 복합적인 서비스 간 흐름을 관찰하기 위한 도구다.
서비스 수준 계약
시스템 수준 계약 (SLA) 란, 시스템을 구축하는 사람과 시스템을 사용하는 사람의 계약이다.
SLA는 최소수준으로 정의하는 걍향이 있어서 SLA를 충족해도 사용자는 만족 목하는 경우가 많다.
서비스수준목표(SLO) 를 달성하면 SLA을 이룰수 있다. 서비스수준지표(SLI) 를 항상 신경써야 서비스 수준 목표를 달성할 수 있다.
알림
서비스에 문제가 발생하거나 서버상태나 지표가 안좋을 경우 시스템을 보살피라고 관리자에게 알림을 보내는데. 너무 알림이 많거나 하면 중요 알림이 희미해재고 피로해질 수 있으므로 적절한 균형으로 진짜 중요한 알림을 받을 수 있도록 해야한다.
예를들며 구글 데이터센터의 하드 드라이버 고장은 흔한 일이다. 심지어 하드드라이버를 서버랙에 고정시키지 않고 찍찍이로 붙여져 있는데는데. 이유는 고장난 하드를 쉽게 버리도 교체하기 위해서였다.
이처럼 특정 고장은 일상적인 것일 수 있다. 알림까지는 필요없을수 있다.
너무 많은 알림은 진짜 중요한 알림과 구분이 안되어 진짜 중요한 알림을 처리누락할 수 있다.
알림의 우선순위가 없거나 담당자가 알림 우선순위를 구분하지 못하도록 능력을 빼앗으면 더 큰 재난이 발생할 수 있다.
알림은 우선순위가 있으며 알기쉽고 어떤문제가 있는 쉽게 진단 가능해야 한다.
시멘틱 모니터링
시스템이 허용 가능한 범위 내에서 동작하고 있다고 판단하기 위해서는, 시스템이 갖춰야 할 특성이 무엇인지 정의할 필요가 있다.
예를 들면 다음과 같다.
“신규 회원은 정상적으로 가입할 수 있다.” “피크 시간대에도 시간당 수만 달러의 제품이 판매된다.” “정상적인 속도로 제품이 배송된다.”
이러한 예시는 앞서 이야기한 SLO(Service Level Objective, 서비스 수준 목표) 와도 일맥상통한다.
이런 관점으로 접근하면, 시멘틱 모니터링은 다음 두 가지 방식으로 확인할 수 있다.
- 실사용자 모니터링
- 합성 트랜잭션
즉, 시멘틱 모니터링은 단순히 시스템이 살아 있는지를 확인하는 것이 아니라, 사용자가 실제로 기대하는 중요한 기능이 정상적으로 동작하는지를 확인하는 모니터링 방식이다.
실사용자 모니터링
이것에 단점은 장보에 노이즈가 너무 많다는 것이다.
또 다른 단점 중 하나는 이미 사용자가 줄어들거나 지표에 이상이 생긴 후에야 시스템이 정상동작하지 않는다는걸 알 수 있다는 것이다.
합성 트랜젝션
운영환경 테스트를 위해 가상의 사용자 상호작용을 주입하여 테스트하는 것이다. E2E 테스트환경과 유사하다.
일부로 잘못된 상호작용을 주입하는 테스트를 해두면 긴급상황에 대처할수 있는 내성이 생긴다. 이런걸 카오스 엔지니어링 이라고 한다.
도구선택
허니코움과 라이트스텝 과 같은 도구가 현재 가장 유용하다고 함.
이런 도구 선택은 마이크로 서비스간에 표준화가 중요하며. 도구를 선택할 때는 민주적으로 다양한 개발자층이 사용하기 쉬어야 한다.
오픈트레이싱이나 오픈텔레멘터리와 같은 도구는 표준 api를 제공하므로 표준선택에 도움이 된다.
모든 지표는 실시간으로 수집되는 정보를 알수 있어야 하며, 규모에 적합한 도구와 방법론을 선택해야 한다.
모든 회사가 구굴처럼 할 필요는 없다. 구글은 너무 많은 지표가 쌓이지 않게 많은양의 지표를 그냥 삭제하고 0억개 -> 500만개 로 샘플링해서 유의미한 부분만 활용한다.
기계화된 전문가
훌륭한 도구가 많이 나오고 있지만 모든 전문지식을 자동화 하는건 불가능하다. 도구가 모든 문제를 해결해주진 못한다.
보안
마이크로 서비스는 보안에 더 신경쓰게 되지만 잘 균형을 맞춰 놓으면 더 보안에 강한 시스템을 갖을 수 있다.
최소한의 방어
애플리케이션 기능에 권한을 부여할때 사용자마다 필요한 기능을 제공한다.
심층방어
공격자로부터 보호하기위해 단일 방어장치보다는 여러 보호장치를 마련하는것이 좋다. 보호장치의 유형에는 1. 예방형 2. 탐지형 3. 대응형이 있다.
자동화
테스트가 그렇게 된 것처럼 보안도 시스템의 주요 프로세스에 포함되는게 좋다.
정적분석울 xss를 미리 보안할수 있는 도구들도 있다.
사이버보안의 5가지 기능
- 식별
무엇을 보호해야 하는지. 해커가 뭘 노릴지 알아야 함 . 이게 바로 위협 모델링
개발자들은 jwt나 tsl같은 것에마누신경쓰지만 대문보다 활짝 열려있는 뒷문이 문제인 경우가 더 많다.
-
보호
-
탐지
-
대응 정보 침해 범위와 데이터를 파악하고 심각한 개인정보가 노출되었다면 조치를 취한다.
-
복구
공격 발생후 복구하는 능력과 재발울 막는 능력을 말한다.
보안의 기초 - 자격증명
사용자 자격증명(관리자패스워드, api 키), 시크릿(ssh키, https키, 데이터베이스 인증키)
특히 시크릿은 생성 저장 배포 모니터링 교체를 신경써야 한다.
쿠버네티스는 시크릿 도구를 제공하고 있으며 볼트 같은 정교한 오픈소스도구도 있다.
클라우드 서비스들도 고유의 시크릿 매니저 서비스를 제공한다.
특히 권한 범위제한의 경우 데베지움과 같은 CDC 읽기전용 기능의 경우 읽기전용 권한만 부여할수 있다.
보안의 기초 - 패치
버안 취약점이 있는 버전으누정기적으로 패치하여 배포해줘야 한다.
클라우드 서비스를 이용하면 하부 시스템의 버전은 클라우드 업체에서 일관 모니터링 하거나 일부는 직접 관리하므로 패치 문제에서 일부 편리해질수 있다.
보안의 기초 - 백업
가장 가치있는 데이터를 주기적으로 백업해라.
올바른 파일시스템기술을 사용하면 서비스는 중단없이 백업가능.
별도의 클라우드 자원에 별도의 계정으로 백업.
보안의 기초 - 재구축
공격을 당했을 때 전체 시스템과 전체 서버를 재설치 해야하는 경우도 있다.
이걸 쉽게 하려면 견고한 백업 복구 프로세스와 결합해야 한다.
쿠버의 경우 사용자 컨테이너 인스턴스는 쉽게 바꿀 수 있지만 쿠버 자체의 하부 컨테이너를 플랫폼을 직접 운영한다면 힘든 작업일 수 있다. 인프라 자체를 바꾸기는 어렵기 때문이다. 이런 점을 고려한다면 클라우드 기반 서비스가 편리할 수 있다.
암묵적 신뢰
네트워크에서 실행되는 모든걸 신뢰할수 있는가?
암묵적 신뢰는 내부에서 발생하는 서비스에 대한 호출을 암묵적으로 신뢰한다는 개념이다.
보통의 조직에서 암묵적 신뢰때문에 보안에 위험에 무감각해진다.
제로 트러스트
내부 경계에 나쁜 행위자가 이미 존재한다고 생각하는 사고 방식이다.
모든 클라이언트가 신뢰할 수 있는 클라이언트인지 의심해야하며 내부 콜이라도 전부 암호화한다.
내부 네트워크도 인터넷망과 동일 취급하기때문에 인터넷에서 내부 서비스에 대한 연결을 언제든 허용할수 있다.
보안에 항상 신경을 써서 구현했으므로, 시스템이 좀 더 유연하게 된다는 뜻이다.
스팩트럼
제로 트러스트라고 해도 모든 영역을 다 같이 취급할 필요는 없다.
공개영역, 비공개영역, 비밀영역으로 몇단계의 스팩트럼으로 나눈 후 더 보안등급이 높은 정보를 각각의 서비스 영역에서 다루도록 계측화 한 후 등급이 더 높은 쪽 서비스는 낮은쪽 서비스의 데이터를 참고할 수 있도록하고 역방향으로는 안되도록 설계할 수 있다.
전송중인 데이터 보안
전송중인 데이터의 보안은 프로토콜의 선택이 중요하며 http의 경우 일반적인 경우 https를 기본으로 적용하는 것이 합당하다. 메세지 브로커와 같은걸 사용할 경우 다음과 같은 4가지 관점에서 기술적 지원이 가능한지 확인하는게 좋다.
- 서버 신원
- 단방향 tls(Transport Layer Security) https 인증 사용
- 클라이언트 신원
- 마이크로서비스간 통신은 상호 멀티 tls가 이루어짐
- 볼트와 같은 툴을 사용하면 쉽게 지원
- 데이터가시성
- 데이터 조작데이터
- Mac 나 hmac로
- hash와 함께 데이터를 전송하면 해시 손상 여부를 확인해 데이터ㅠ 작 여부를 확인할수 있다.
보관중인 데이터
가장 좋은 방법은 잘 알려진 암호와 기법을 잘 알려진 소프트웨어에 맡겨서 사용하는 것이다.
이 작업을 망치는 방법 중 하나는 자체 암호화와 알고리즘을 사용하는 것이다.
특히 패스워드를 보관할 땐 솔트값을 이용하는 해시기술을 절대적으로 이용하는게 좋다.
모든걸 암호화 할 순 없으므로 암호화 해야하는 테이블집합을 관리하는게 현실적이다.
필요 없는 정보는 최대한 저장하지 말라. 그렇게 하면 근본적으로 훔칠 게 적어진다.
암호화 관련된 키는 별도으 ㅣ보안 어플라이언스에 보관해라. 전용장비나 클라우드 보관 서비스를 이용하는게 가장 안전하다.
인증과 권한부여
- 서비스간 인증
- api key를 이용한 방식 과 tls 인증
- 사람인증
- 패스워드나 2단계 mfa인증
일반적인 SSO 인증
SSO로 세션당 단 한번만 인증
요즘에는 oauth2 기반이 사실상 표준으로 자리잡음
sso 게이트웨이
시비스가 직접 아이디 제공자와 핸드셰이크를 하지 않고, 게이트웨이를 두고 중간에서 서비스와 외부세계 사이에 있는 프록시 역할을 하도록 한다.
시볼레스가 이 작업을 수행하는 대표적인 도구이다.
게이트웨이는 좋은 전략이지만 게이트웨이가 편리해보이기 때문에 기능을 조금씩 확장하고 싶은 생각이 들 수 있다. 하지만 게이트웨이가 다용도가 될수록 점점 복잡해지고 파악하기 힘들어진다.
혼동된 대리인문제
인증만 해서는 소용없다. 비밀정보는 충분히 구별된 권한부여를 해야한다.
-
중앙집중식 권환관리
- 편리하긴 하지만 모든 서비스에 권한과 관련된 의존성이 생긴다. 그리고 암묵적 수용 방식에 가깝다. 하지만 우리는 모든 마이크로서비스가 독립적이길 원한다.
-
분산 권한관리
- Jwt 와 같은 웹토큰을 사용하면 서비스간 인중된 정보전달에 편리하다.
회복탄력성
견고성
예상되는 문제를 미리 예측하여 커버하는 능력을 말한다. 견고성이 높을수록 복잡해지는 단점이 있다.
회복력
예상되는 문제가 생겼을 때 회복하는 능력이다.
백업이나, 롤백전략, 재실행전략 같은 것들이다.
확장성
예상치 못한 일이 발생했을때 시스템이 중앙집중이라면 개선하기 힘들다. 시스템이 분산되어 있으면 문제가 되는 부분을 정확히 진단할 수 있고 개별적으로 확장하거나 개선하기 쉽다.
지속성
문제를 계속 인식하는 능력이다. 팀의 개발문화 조직문화와 같은 것들이 이에 포함된다.
기능저하
서비스에따라 어느정도 시간을 타임아웃으로 여길것인가.
어느 시점에 요청실패에 대한 재시도가 유효한가. 서비스의 맥락을 잘 이해해야 그에 따른 적절한 설정을 할 수 있다.
마이크로서비스 아키텍처는 하나의 서비스가 다운되어도 탄력있게 확장가능하게 설계해 좋으면 치명도가 작을 수 있다.
벌크헤드
벌크헤드란 문제가 되는 부분이 다른 부분에 영향을 미치지 못하도록 쉽게 격리하게 만드는 것이다.
서비스별로 사용할 수 있는 리소스, 프로세스 레드 커넥션풀을 따로 마련하여 구축
서비스별로 컨테이너를 따로 두거나 커넥션풀을 할당하는 방식으로 보통 서킷브레이커와 함께 사용
회로차단기
문제가 생겼을 때 문제가 생긴 서비스의 벌크헤드를 직접 차단시킬 수 있는 장치. 일반적으로 널리 사용되는 개념으로 구현체도 많다.
하지만 올바르게 설정하는게 까다로울 수 있다.
비동기인 경우에 큐에 넣어놨다가 회로 회복 후 다시 시도할수 있지만, 동기 요청인 경우에는 성능에 영향을 줄수있다.
멱등성
메세지 브로커와 같은걸 사용하면 전달은 보장되지만, 같은 메세지를 두번ㅆ기 보내는 사태가 벌어질 경우 설계를 멱등성에 기반에 해놓으면 내구성이 좋아진다.
위험분산
이중화나 위험분산 같은 개념이 MSA 서비스에서는 중요하다. AWS의 경우 각각의 리전은 서로 다른 클라우드 시스템을 갖으며 하나의 리전은 2개 이상의 가용영역을 갖고 있으므로 이런 부분을 참고하여 서비스의 이중화 배치나 서비스 배치에 유의하여 활용하는게 좋다.
CAP 정리
- 일관성©
분산된 여러 노드가 일관된 답을 내놓는 특성이다.
- 가용성(A)
모든 요청이 어쨋든 응답을 한다는 것이다. 일시적으로 노드가 데이터가 약간 불일치 하더라고 가만하고 어쨋든 응답을 한다.
- 단절내성(P)
시스템간 시스템내의 부분간 통신이 가끔 불가능한 상황에서 처리할 수 있는 능력이다.
AP는 가용성을 보장하는 시스템
CP는 단일성을 보장하는 시스템
다양한 환경에서 대부분 AP가 올바른 선택이다.
실제 현실세계에서 문제가 생겼을 때 AP는 간단하게 해결 가능하지만 CP자체는 구축도 어렵고 완벽한 해결책도 사실은 없으며, 여러 다른 부가적 문제도 많다.
카오스 엔지니어링
게임데이 같은 운영 환경 실험을 통해 견고성에 영향을 주는 시스템의 부분을 파악할 수 있으며, 견고성을 넘어 시스템의 탄력 회복성 관점으로 바라보는 것이 합당하다. 이런 탄력 회복성을 기르려면 조직 문화 자체의 체질을 좋게 유지해야 한다.
확장
수직확장
다 빠른 cpu와 더 높은 i/o는 지연시간과 처리량이 개선된다(하나의 컴퓨터가 더 많은일을 함).
쉽게 빠르게 확장하고 즉각적인 이점을 갖지만, 요즘은 CPU클럭보다 멀티코어로 확장하므로 소프트웨어가 하드웨어의 멀티코어를 활용하도록 변경하는 추가 비용이 필요할 수 있다.
수직확장을 거듭하다 인프라스트럭처를 확장해야 하는 단계가 오면 확장에 시간과 비용이 커지므로 항상 수평복제를 염두한 시스템을 만들어야 한다.
수평복제
일반적으로 로드벨런서를 이용할수 있다.
다른 부분으로는 경쟁소비 패턴이나 디비리플리케이션 같은 읽기전용 복제본을 만드는 것이다.
수평복제는 더 많은 인프라스트럭처가 필요하므로 더 많은 비용이 들 수 있다.
장애가 발생한 컴포넌트의 부하를 다른 컴포넌트로 단순히 이전하는 방식은 일반적인 상황에서는 피하는 것이 좋다. 남아 있는 컴포넌트에 과도한 부하가 집중되어 연쇄 장애가 발생할 수 있기 때문이다.
데이터 파티셔닝
데ㅓ이터의 일부 측면을 기반으로 부하분산 시키는걸 말한다.
샤딩은 a-m 은 디비1에 n-z 는 db2에 보내는 식으로 부하분산을 하는것이다.
데이터베이스 차원에서 기능을 지우너하면 편해진다. 하지만 미이크로서비스 인스턴스 수준에서도 이 전략은 가능하다.
파티셔닝을 위한 전용 서비스 인스턴스를 구축하는 형태로 지원가능
파티셔닝을 올바르게 분배하는게 매우 어려운 일이다.
이름을 기반으로 파티셔닝 했지만 연령별로 그룹핑하여 통계를 내야 하는 작업과 같은 경우 까다로울 수 있다. 보통 캐싱기반 메모리를 사용하며 맵 리듀스 같은 기술을 사용한다.
기능분해
메인시스템에서 기능을 추출해 독립된 마이크로서비소로 만드는걸 말한다.
결합모델
모놀리식 시스템 전체를 확장하려면 많은 비용이 들지만. 일부의 기능이 마이크로서비스로 분산되어 있으면. 특히 요청이 많은 주문과 같은 서비스를 분리해 놓으면 확장하기 더 쉽다.
작게 시작하라
어떤 개념을 적용할 때 거창하게 시작하지 말라. 섣부른 최적화를 하지말고 가성비를 따져봐야 한다.
CQRS와 이벤트소싱은 시스템의 견고성을 위해 좋은 방법이지만 섣불리 적용하면 시스템의 복잡성만 높아질 수 있다. 필요한 경우 적용했을때 개발자 인지자원 등을 고려하여 작게 적용하며 유연하게 적용하라.
캐싱
서비스의 성능과 견고성 확장성에 좋은 영향을 준다.
클라이언트 캐시와 서비캐시가 있으며 요청캐시는 특정 요청된 응답에 대해서 캐싱하는 것이다.
무효화
‘TTL 기반 무효화’, ‘ETAG기반 무효화’, '알림기반무효화’가 있다.
캐싱의 황금 법칙
너무 많은곳에 캐시를 두면 시스템이 복잡해져서 제어하기 힘들 수 있다.
특히 부라우저 캐시의 expire 를 너무 길게 잡으면 재앙이 될 수 있다. 결국 url을 바꿔야한다.
캐시가 만능은 아니다.
자동확장
AWS와 같은 서비스를 활용하면 반응형 자동화 확장이나 축소, 예측적 확장과 축소 둘다 가능하며, 유연하게 대처할 수 있다. 다만 축소할때는 너무 빨리 축소되지 않도록 주의해야 한다. 급격한 추이로 상황이 변경되는 경우 낭패를 볼 수 있다.
다시 시작하기
처음부터 확장에 최적화하는 형태로 개발하려는 것은 오히려 복잡도를 증가시키는 재앙이 될 수 있다. 확장의 신호는 위기가 아니라 좋은 신호로 생각할 수 있다. 처음부터 완벽한 확장의 형태를 만드려고 애쓰지 말고 부하의 원인을 정확히 파학해서 꼭 필요한 부분을 확장하는 것이 좋다.
사용자 인터페이스
페이지별 분해, 위젯기반 분해와 같은 개념으로 프론트엔드의 마이크로 서비스를 분해할 수 있으며, 기기의 종류와 네트워크상황에 따라 중앙집계 게이트웨이나 BFF가 필요하게 된다.
프런트엔드를 위한 백엔드
BFF는 단일 클라이언트를 위한 서버이며 여러 클라이언트에서 통합해서 사용하려고 하면 비대해지고 결국 집계게이트웨이처럼 동작하게 된다.
서비스간의 공유 코드는 결합만 커지게 할 확률이 높기 때문이다.
시버스간에 공통로직이 생기면 추상화하여 새로운 마이크로서비스를 만들어내거나 공유 라이브러리의 형태로 분리시킬수 있다.
꼭 BFF만을 고집할 필요는 없고, 자잘하게 하이브리드 방식을 사용하는게 좋다.
조직구조
므슨하게 결합된 조직이 이상적이며 그렇게 되려면, 각 팀의 의사결정이 독립적으로 분리되어야한다. 권한과 책임이 분산되어야 한다.
콘웨이의 법칙
팀이 시스템을 설계할때. 팀은 그 팀의 소통구조와 비슷하게 설계하게 된다.
시스템의 구조가 정해져 있고 그 위에 팀을 설계할 때도 성립된다.
느슨하게 결합된 조직은 느슨하게 결합된 시스템을 갖게 된다.
팀이 너무 커지면 속도가 느리다.
자율성이 높은 조직이 효과적으로 소통하므로 효율이 높다.
마이크로서비스 아키텍처를 도입하면 큰 조직 안에서 자율성을 갖을 수 있고 큰 조직을 작은 조직처럼 효율적으로 유지할 수 있다.
강력한 소유권
팀이 코드에 대해 강력한 소유권을 가진다.
다른팀이 수정하려면 허락을 받아야 한다.
대규모로 개발조직이 구성된 팀에서는 마이크로소프트 아키텍처가 적합할 수 있다
공동 소유권
마이크로서비스 아키텍처의 주요 이점을 회손할 수 있다. 서비스마다의 기술이 제한되며 서비스간 결합이 증가되는 결과를 초래하게 된다.
횡단 변경사항
서비스간에 횡단 변경사항을 줄이기 위한 횡잔 변경사항을 처리해야 할수도 있다. 장기적으로 단기적 아픔을 견뎌내야 하는 것이다.
활성화팀
스트림 정렬팀은 매우 바람직하지만 특정 기술노하우나 기술전파 및 노하우를 얻기위해서는 특화된 활성화팀이 필요할 수 있다.
플랫폼 팀
플랫폼팀도 활성화팀의 종류일 수 있는데 서비스간 공통코드의 서비스간 의존을 줄이기 위해 파편화 할수도 있지만, 프레임웍과 같은 공통 코드는 추상화하여 관리하고 각각의 서비스 팀에서 팀에 맞게 재확장하여 사용할 수 있으면 좋다.
앙상블 프로그래밍
페어프로그래밍과 비슷한 개념인데… 여러명이서 함께 코딩하는걸 말한다.
지리적 분포
지리적 분포를 고려하여 팀을 구성하는게 커뮤니케이션에 유리하다.
진화하는 아키텍트
아키텍트는 고객이 필요로 하는데 도움이 되는 기술적 비전을 시스템에 통합하는 것이다. 전문 개발자들이 시스템에 대해 공유된 이해를 갖아야 하는데 이게 아키텍트다.
아키텍트는 진화하기 쉽게 설계되어야한다.
그래서 소프트웨어 세계에서의 아키텍트는 건축가 보다는 심시티 시장과 같이 되어야한다.
이런 관점에서 마이크로서비스 아키텍트가 이상적이게 보이기도 한다.
아키텍처… (시니어 개발자)는 무엇이 시스템의 변화를 어렵게 만들지 파악해야 한다.
아키텍트는 계획하는게 아니라 일어나는 것이다.
거주 가능성
아키텍트는 일하기 좋은 환경을 만들고 유지해야할 책임을 갖는다.
원칙
원칙은 팀의 목표에 따라항상 변할수 있으며 10개 미만이어야 한다.
원칙에는 진짜 변경할수 없는 제약조건이 포함되어 있다. 원칙 중에 제약조건을 잘 파악해 두는 것도 도움이 된다.
관행도 좋은 원칙이 될수 있다.
필수기준
모니터링은 관찰가능성의 형태로 시행되어야한다.
서비스가누인터페이스는 같은 스타일로 1개나 2개장도로 제한되는게 좋다.
서비스 인터페이스는, 같은 스타일로 1개나 2개 정도로 제한하는게 좋다.