21 min to read
벡엔드 면접 대비 cs 질문 정리
api 구축
저희 API는 각 기능별로 모듈화되어 구성되었고, REST 원칙을 따랐습니다. MSA 구조로 전환하면서 각 서비스는 독립적으로 동작하도록 설계되었으며, Kafka 메시지 큐를 통해 서비스 간 통신을 비동기적으로 처리했습니다. 성능 최적화를 위해 Redis 캐싱,msa로의 전환, Read Replica를 적용했고, Prometheus와 Grafana를 통해 실시간 모니터링을 설정하여 시스템 안정성을 유지했습니다.
Rest api
우선 rest란 뭔지에 대해 알아야 하는데 rest란 URI를 통해 어떤 자원인지 명시하고, HTTP Method를 통해 해당 자원을 처리하도록 설계된 것으로 웹의 기존 기술과 http 프로토콜을 그대로 사용하기 떄문에 웹의 장점을 최대한 활용할 수 있는 아키텍쳐 스타일 입니다
rest api는 이러한 rest 의 특징을 api에 적용한것으로 url에 정보의 자원을 표현하고 자원에 대한 행위를 http method로 표현합니다
cs관련 지식
- 네트워크
브라우저에 url 입력하면 일어나는 일
특정 웹사이트에 접속하기 위해서는 구글이나 네이버 같은 도메인이 아니라 ip주소를 입력해야한다 하지만 ip주소는 길고 가독성이 떨어지기 때문에 아이피 주소가 아닌 이 아이피 주소와 매칭해놓은 DNS서버를 사용한다 DNS는 도메인 네임 시스템의 약자로 도메인과 아이피 주소를 저장하고 있는 서버이다
-
- 브라우저는 DNS 서버에 접속하기 전에 캐싱한 DNS 기록을 통해 해당 도메인 주소와 연결된 아이피주소가 있는지 확인한다
-
- 있다면 그 아이피 주소로 이동한다 만약 없다면 http를 통해 dns서버에 입력된 도메인 서버를 요청한다 dns 이름의 가장 높은 계층인 루트 도메인 부터 시작해 점점 아래로 내려간다 루트도메인(.) 최상위도메인(com, net, kr, jp) 두번째 수준 도메인(google.com, naver.com) 세번째 수준 도메인(www.goole.com, www.naver.com) 이렇게 찾아가 아이피 주소를 찾는다
-
- 연결이 되면 브라우저는 get요청을 해 해당 아이피 주소의 웹페이지를 요청헌다
-
- 서버는 html문서를 브라우저에 응답하고 브라우저는 html을 파싱해 렌더링을 하고 리소스를 요청한다
-
- 모든 리소스가 로드되면 웹페이지에 접근할 수 있다
Oauth2란?
인증을 위한 개방형 표준 프로토콜로 제 3자 애플리케이션이 사용자를 대신해 애플리케이션에서 제공하는 자원에 대한 접근 권한을 위임하는 방식을 제공
구글, 네이버들에서 제공하는 간편 로그인 기능도 이 프로토콜 기반의 사용자 인증 기능을 제공
Authorization Code방식 사용
클라이언트는 구글 로그인페이지로 리다이렉트하고 사용자가 승인하면 구글은 사용자를 콜백url로 리다이렉트
이 url에서 패스포트는 제공된 인증코드를 사용하고 구글로부터 액세스토큰과 리프레시 토큰을 받음
이후 이 토큰을 사용해 사용자 프로필을 얻고 이 프로필을 사용해 로컬 데이터베이스와의 사용자 인증 및 생성과정 수행
- 인증(Authentication, 어펜티케이션)과 인가(Authorization, 어쏠제이션)의 차이 인증은 사용자가 사용자와 시스템간에 공유되는 합의된 정보를 시스템에게 전달해 자신의 신원을 증명하는과정 인가 특정 리소스에 접근할 권한이 있는지 확인
tcp와 udp의 차이점
tcp는 전송제어 프로토콜로 인터넷 상에서 아이피 규칙으로만 통신하기에는 부족하거나 불안정한 단점들을 커버해 전송을 제어하며 신뢰성을 보장한다
tcp는 연결지향적으로 3 way handshaking 과정을 통해 송신자와 수신자간의 연결을 설정한다 tcp는 데이터패킷이 손실이나 손상되지 않도록 보장한다 확인 응답(ACK)를 통해 데이터가 올바르게 수신되었는지 확인하고 손실된 패킷은 재전송한다 또한 송신자가 수신자의 처리능력을 초과하지 않도록 데이터 전송 속도를 조정한다
udp는 사용자 데이터그램 프로토콜로 신뢰성보다 속도를 중시하는 응용프로그램에 사용된다 udp는 최소한의 프로토콜 메커니즘을 갖춘 간단한 무연결 통신모델로 서로 주고받을때 정보를 보내거나 신호전송 절차를 거치지 않고 보내는쪽에서 일방적으로 데이터를 전달하는 통신 프로토콜이다 udp는 비연결지향적이며 패킷이 손실되거나 손상될 가능성이 있고 순서를 보장하지 않는다
클라이언트 사이드 랜더링과 서버사이드 랜더링의 차이
- 클라이언트 사이드 랜더링
브라우저에서 자바스크립트를 사용하여 페이지의 콘텐츠를 동적으로 랜더링하는 방식 클라이언트(브라우저)가 맡아서 하는 방식 -> 서버에서 받은 데이터를 클라이언트인 브루우저가 화면에 그린다 html파싱부터 자바스크립트 읽기를 전부 브라우저에서 하기 때문에 시간이 더 걸림
초기 로드 속도는 느리지만 이후 서버와의 상호작용이 줄어들고 브라우저 내에서 상태변경이 일어나기 떄문에 이후 페이지 전환 속도는 빠르다 검색엔진 최적화에는 보완이 필요하다
- 서버사이드 랜더링
서버쪽에서 화면을 랜더링하여 보여주는 방식 서버로부터 완전한 html파일을 받아 화면을 구성하기 때문에 첫화면 로딩 속도가 빠르다 이후 페이지전환시에는 서버로부터 새로운 페이지를 받아야 해 전환속도가 느리다 검색크롤러가 서버에 렌더링된 html을 바로 인덱싱이 되 검색엔진 최적화가 가능하다
서버는 네트워크가 느리거나 검색엔진 최적화가 필요할떄, 페이지의 상호작용이 별로 없을떄 클라이언트는 네트워크가 빠르거나 검색엔진 최적화가 필요 없을때 페이지의 상호작용이 많이 필요할때 사용한다
call by value/ call by Reference의 차이
- call by value
값에 의한 호출 -> 함수에 변수를 전달 할때 그 변수의 값을 복사해 전ㅁ달 함수내에서 변수의 값을 변경해도 원래 변수의 값에서는 영향을 미치지 않음 함수 외부 내부가 독립적임
- call Reference
참조에 의한 호출이라고 하며 함수에 변수를 전달할떄 변수의 참조 또는 주소를 전달 함수내에서 참조된 변수의 값을 변경하면 원래 변수의 값도 함꼐 변경된다 내부와 외부가 연결되어있다
자바스크립트는 기본자료형과 참조자료형의 차이로 인해, 인자 전달 방식이 값에 의한 전달(Call by Value)과 참조에 의한 전달(Call by Reference)처럼 동작
실제로 JavaScript는 모든 인자를 값에 의한 전달(Call by Value) 방식으로 처리하지만, 참조 자료형의 경우 값 자체가 객체에 대한 참조값
call by value 방식은 함수가 호출될때 값의 복사가 이루어져 메모리가 더 쓰이지만 안전하게 작동할 수 있다 call by Referenece 방식은 메모리 효츌적이지만 실수로 원본 데이터를 변경할 위험이 있다
모놀리식 아키텍쳐/ 마이크로 서비스
모놀리식 아키텍쳐는 애플리케이션이 모든 기능이 하나의 단일 코드베이스와 하나의 배포단위에 통합도어 있는 것을 의미함 모든 기능들이 하나의 시스템에서 동작하므로 환경세팅에 시간이 적게 들고 모든 기능들이 하나의 시스템에서 동작하기 때문에 테스트가 쉽다
하지만 코드가 무수히 많아지면 코드의 가독성이 떨어지고 이해하는데 시간이 올리걸리기 떄문에 유지보수가 어렵다 특정기능에 오류가 발생하면 전체 시스템에 그 영향이 가 전체 시스템에 오류가 발생하게 된다
마이크로 서비스는 서비스가 커질수록 시스템이 무거워지는 모놀리식의 단점을 해결하기 위해 여러 모듈을 조합하여 애플리케이션을 구현하는 방식으로 개발부터 배포까지 효율적으로 수행할 수 있다
시스템이 독립적으로 구성되어 있기 때문에 이해해야 하는 코드의 수가 적고 유지보수가 쉽다 서비스가 독립적으로 나눠져 있기때문에 효율적으로 개발과 배포가 가능하다 하지만 관리해야하는 복잡성이 증가하고 서비스가 독립적으로 실행되므로 인프라 비용이 증가한다
프록시 서버
프록시 서버는 클라이언트와의 서버간의 중계 역핧을 수행하는 서버이다 프록시 서버를 사용하게 되면 클라이언트가 네트워크 상에서 다른 서버로 직접 연결하지 하지 않고 중간에 프록시 서버를 경유하여 통신하게 된다
Rest api
rest api는 rest 원칙을 사용한 api를 의미하며 rest란 소프트웨어 프로그램 아키텍쳐의 한 형식으로 자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든것을 의미합니다
자원, 메서드, 표현으로 구성되어 있고 url을 통해 자원을 명시하고 http method를 통해 해당자원을 조작하는 형식입니다
(uri와 url의 차이 uri는 인터넷상 자원의 위치를 의미하고 url은 이런한 자원을 식별하기 위한 문자열의 구성으로 uri는 url을 포함합니다 )
장점으로는 HTTP 표준 프로토콜에 따르는 모든 플랫폼에서 사용이 가능하고 메시지가 의도하는 바를 명확하게 나타내므로 의도하는 바를 쉽게 파악할 수 있다
restful api는 rest 원칙을 잘 따르고 있다는 것을 의미 합니다
- api 프로그램에서 다른 프로그램의 구성요소나 서비스와 상호작용하기 위한 인터페이스를 제공하는 기술
프로세스와 스레드
프로세스는 운영체제로부터 자원을 할당받은 작업의 단위이고 스레드는 프로세스가 할당받은 자원을 이용하는 실행흐륾의 단위 프로세스는 프로그램을 시켜 정적인프로그램이 동적으로 변하여 돌아가고 있는 상태 캄퓨터에서 작업중인 프로그램을 의미 원래는 프로세스 하나만 사용했지만 기술 발전으로 인해 프로세스 사용에는 한계가 생겨 하나의 프로세스 안에서 동시에 진행되는 흐름의 단위로 여라기 작업들의 흐름이 동시에 진행된다 같은 프로세스 내에서 실행되는 스레드들은 동일한 메모리 공간을 공유해 자원을 공유한다
IoC와 DI
IoC는 제어의 역전으로 프로그램의 흐름을 개발자가 아닌 외부에서 관리되는 것입니다 객체간의 결합도를 줄이고 유연한 코드를 작성할 수 있게 되어 유지보수가 편하게 된다
IoC는 DI와 DL로 나눠집니다 DI는 의존성 주입으로 객체간의 의존성을 개발자가 내부에서 new 를 사용해 직접 호출하는게 아닌 외부에서 객체를 생성해 넣어주는 방식으로 테스트와 유지보수가 쉬워집니다
DL은 의존성 검색으로 객체가 필요로 하는 의존성을 외부컨테이너로부터 가져오는 방식으로 객체가 의존성을 요청하고 외부 컨테이너가 제공합니다
보안
JWT에 대해
jwt는 json web token의 줄임말로 json 객체에 인증이 필요한 정보들을 담아 비밀키로 서명한 토큰 사용자가 로그인 요청을 보내면 서버는 비밀키를 이용해 토큰능ㄹ 발금하고 이 토큰을 헤더에 담아 클라이언트에 보낸다 그 후 클라이언트는 jwt를 로컬에 저장한 후 api 호출이 올때마다 헤더에 토큰을 담아 보내고 서버는 헤더를 확인해 사용자의 신원을 파악하고 인증이 되면 api 응답을 보낸다 매번 헤더에 보내야 하는 이유는 http가 Connectionless하고 Stateless해 한번 통신이 일어난 뒤 연결이 끊어지고 이전 상태를 유지 하지 않아 과거에 어떤 정보를 보냈는지 기억하지 못한다는 점 때문이다
OAuth는 제3자 인증방식으로 사용자가 신뢰할 수 있는 서버에 정보를 맞겨 놓고 접근 할 수 있는 권한을 주는것이다 사용자측에서도 민감한 정보를 굳이 입력받지 않아도 되고 서버측에서도 민감 정보를 굳이 관리하지 않아도 되는 장점이 있다
jwt의 구조
크게 3파트로 분리되어있고 .을 기준으로 분리되어 있다 헤더: 허더에는 암호화시킨 알고리즘의 종류와 토큰의 타입이 무엇인지 명시해져있다
페이로드: 암호화되어있는 정보와 토큰의 발생시간, 만료시간이 명시되어있다
시그니쳐: 헤더와 페이로드를 인코딩 후 비밀키를 이용해 서명을 생성, 토큰의 위변조를 검증합니다
세션 vs 쿠키 vs 캐시
http의 특징은 Connectionless하고 Stateless하기 때문에 클라이언트가 누구인지 확인해야 하기 때문에 쿠키와 세션을 사용한다
-
쿠키 쿠키는 클라이언트에 저장되는 키와 값이 같이 들어있는 데이터 파일로 사용자가 인증이 유효한 시간을 명시할 수 있으며 유효시간이 정해지면 브라우저가 종료되도 인증이 유지된다는 특징이 있다 클라이언트의 상태를 로컬에 저장후 참조한다 쿠키는 클라이언트에 저장되므로 xss와 같은 공격에 취약 할 수 있다
-
세션 쿠키 기반이지만 사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리 서버측에서 관리 서버는 클라이언트를 구분하기 위해 세션 아이디를 부여함 브라우저가 서버에 접속해서 브라우저가 종료할때까지 인증 상태를 유지 한다 사용자의 정보를 서버에 두기 때문에 쿠키보다 보안에 좋지만 사용자가 많아질 수록 서버의 메모리를 많이 차지한다
-
캐시 사용빈도가 높은 데이터를 고속으로 엑세스 할 수 있는 위치에 두는것 데이터출력과 가까운 지점에 임시적으로 저장 데이터 재사용을 전제로 하고 실제 데이터 엑세스 부하를 줄일 수 있다
DB
n+1문제
n+1문제는 데이터베이스와의 상호작용 시 쿼리를 1번 날렸지만 의도하지 않은 n번의 쿼리가 추가로 실행되는것을 의미합니다 조인이 설정된 엔티티를 조회할 경우 조회된 데이터갯수만큼 연관관계의 조회 쿼리가 추가로 발생해 데이터를 읽어오게 됩니다 onetomany에서 one을 조회했더니 각 one의 many를 다시 조회하는 일이 발생하는 것을 예로 들 수 있급니다
-
lazy loading(지연로딩) 필요한 시점에 데이터를 로딩하는 방식으로 초기에는 데이터가 전부 로딩되지 않는다 typeORM에서 엔티티 설정할때 칼럼의 속성을 Promise로 정의하면 실제로 해당 속성에 접근할때 쿼리가 실행됩니다
-
Eager Loading(즉시 로딩) 특정 엔티티 조회시 연관된 모든 데이터를 한꺼번에 로딩하는것으로 연관된 모든 엔티티를 가져온다는 장점이 있지만 불필요한 데이터 로딩과 메모리 사용량의 증가가 있어 성능에 영향이 갈 수 있습니다 typeORM에서 relatuins을 통해 명시적으로 가져올 연관된 엔티티를 특정하면 됩니다
nosql과 RDBMS
관게형 데이터베이스는 정해진 데이터 스키마에 따라 테이블에 저장되고 데이터는 관계를 통해 여러 테이블에 분산된다 각 테이블은 사전에 정의된 스키마에 따라 구조화되고 스키마는 테이블의 열과 데이터 타입을 정의한다 스키마를 준수하지 않은 레코드는 테이블에 추가 할 수 없다 데이터의 무결성을 유지하기 위해 제약조건을 사용하며 중복을 피하기 위해 정규화를 사용한다
nosql는 RDBMS의 반대로 고정된 스키마가 없고 다양한 데이터 모델을 지원해 언제든지 데이터를 조정하고 새로운 필드를 추가할 수 있습니다
레코드는 json과 비슷한 형식으로 저장되며 문서라고 부른다 또란 nosql은 대용량의 데이터를 빠르게 읽고 쓸 수 있다 RDBMS는 변경될 일이 없고 명확한 스키마가 중요한 경우 사용하고 nosql은 데이터의 구조가 변경되거나 확장 될 수 있는 경우, 읽기를 자주 하지만 데이터 변경은 자주 없는 경우 사용한다
sql은 주로 스케일 업을 통해 성능을 향성시키고 no-sql은 스케일 아웃을 통해 서버를 추가해 확장시킨다
no-sql을 사용해야하는 경우는 데이터의 구조가 자주 변경되거나 실시간 데이터 처리가 필요한 경우 no-sql을 사용한다
MySQL이 아닌 다른 RDBMS
mysql이 아닌 다른 RDBMS에는 PostgreSQL, SQLite, MariaDB등이 있습니다
PostgreSQL는 mysql과의 차이점 mysql은 스토리지 엔진 또는 소프트웨어 모듈과 함께 사용하는 경우에만 ACID 규정을 준수하지만 PostgreSQL는 모든 구성에서 완벽히 호환됩니다
다중버전동시성제어는 레코드의 중복사본을 생성헤 동일한 데이터를 병렬로 안전하게 읽고 업데이트 하는 기능으로 mysql은 이 기능을 제공하지 않지만 PostgreSQL은 지원합니다
MariaDB는 mysql의 포크버전으로 mysql의 개선버전입니다 mysql과 호환성이 높고 mysql보다 더 빠른 성능과 고급기능을 제공합니다
mysql은 순수 관계형 데이터베이스이지만 PostgreSQL는 객체 관계형 데이터베이스입니다 여러 프로그래밍 언어의 데이터 유형인 객체를 사용해 상속과 같은 객체 지향언어의 개념을 사용할 수 있습니다
mysql과 postgresql의 차이
mysql은 read에 강점이 존재하고 postgresql는 write, update에 더 좋은 성능을 내고 성능은 postgresql가 전반적으로 더 좋다
또한 오픈소스중 가장 많은 ansi sql을 지원합니다
정규화
데이터베이스 설계시 데이터의 중복을 최소화하고 데이터의 무결성을 보장하기 위해 데이터를 구조화하는 과정
- 1형 정규형
테이블의 칼럼이 원자값을 가져야 한다
-
2형 정규형 제 1 정규화를 진행한 테이블에 대한 부분함수종속을 완전함수종속을 만족하게 하는것 기본키가 부분집합의 키가 결정자가 되어서는 안된다 부분함수 종속 -> 기본키중 특정 컬럼에만 종속되는것을 말함
-
3형 정규형 이행적 종속을 없애기 위해 테이블을 분리하는것 이행적종속(a -> b b->c 면 a ->c 가 성립)
-
BCNF 모든 결정자가 후보키여야 한다
-
4형 정규형 다치 종속을 제거한다 다치종속은 같은 테이블내의 독립적인 두개 이상의 칼럼이 또 다른 컬럼에 종속되는것을 말한다
역졍규화
역규화란 정규화의 반대로 성능을 올리기 위해 데이터베이스의 구조를 의도적으로 데이터 중복을 허용 하는 것을 말합니다
트랜잭션과 ACID
트랜잭션은 데이터베이스에서 하나의 논리적 작업 단위를 나타내며, 여러 데이터베이스 연산을 하나의 작업 단위로 묶어주는 기능을 한다 트랜잭션의 속성으로는 원자성,영속성, 일관성, 고립성이 있다
-
원자성 트랜잭션은 논리적으로 쪼개질 수 없는 단위이기때문에 내부의 sql문은 전부 성공하거나 전부 실패해야 한다
-
일관성 트랜잭션 이전과 이후는 일관된 상태를 유지해야 한다
-
고립성 여러 트랜잭션이 실행되더라도 서로 영향을 주지않고 독립적으로 싱행되는것처럼 보여야 한다
-
영속성 커밋된 트랜잭션의 결과는 데이터베이스에 영구적으로 저장되어야 한다
객체지향이란
객체지향은 프로그램 설계방법론 중 하나로 프로그램을 객체라는 기본단위로 나누고 이 객체들이 서로 상호작용헤 프로그램을 구성하는 방법입니다 기존의 방식이였던 절차적 방식은 명시적인 순서로 처리하는것이 중요했습니다 그 결과 복잡해지면 이해하기 힘든 스파게티 코드를 만들게 됩니다 이한 문제점을 해결하기 위해 프로그램을 함수단위로 나눈 구조적 프로그래밍이 나오게 되지만 전역네임스페이스의 포화문제에 직면하게 되고 이를 해결하기 위해 나온것이 객체지항 프로그래밍입니다
oop의 특징
하나의 객체에 대해 객체가 가진 특정한 목적을 위해 필요한 변수나 메서드를 하나로 묶어 외부에 들어나지 않게 하는 캡슐화
복잡한 시스템을 단순화하고 어떤 대상에 공통적인 속성과 기능을 추출해 정의한것 추상화,
기존의 클래스를 재활용해 새로운 클래스를 작성하는 상속,
동일한 메서드가 서로 다른 객체에서 다르게 동작할 수 있게 하는 다형성 이라고 한다
In-Memory Database
디스크가 아닌 주메모리에 모든 데이터를 저장하는 데이터베이스로 기존의 DB들보다 자료접근이 빠른게 장점입니다 하지만 데이터가 휘발성이기 때문에 서버가 다운되거나 전원이 꺼지게 데이터가 날아간다는 단점이 있습니다 그렇기 때문에 로그인 세션등 날아가도 괜찮은 임ㅅ기 데이터에 자주 쓰입니다 또한 속도가 빠르기 떼문에 많은 데이터를 실시간으로 빠르게 처리해야하는 애플리케이션에서도 쓰입니다
- redis를 쓴 이유 redis는 단순한 키값 구조가 아니라 여러 자료구조를 지원합니다 string, hashset, sortedset를 사용했습니다 또한 다른 인메모리디비인 멤케시드와 비교해보면 인메모리 디비지만 스냅샷을 통해 디스크에 백업을 할 수 있다는 장점이 있습니다
레디스의 단점은 여러 자료구조를 지원하기 때문에 다른 인메모리디비보다 오버헤드가 있을 수 있고 설정이 복잡해 질 수 있습니다 또한 단일 스레드 환경이기 때문에 동시성이나 다중처리가 필요한 작업에서는 한계를 보입니다
xss
Cross-Site Scripting으로 공격자가 웹 페이지에 악성 스크립트를 삽입하여 다른 사용자가 해당 페이지를 방문할 때 악성 스크립트가 실행되도록 하는 공격 기법 사용자 입력을 검증하지 않는 다면 악의적으로 들어간 스크립트가 실행된다
CSRF
공격자가 인증된 사용자가 모르게 특정 웹 애플리케이션에 요청을 보내게 하여 사용자의 권한으로 악의적인 작업을 수행하게 하는 공격 기법
SQL Injection
SQL Injection은 공격자가 애플리케이션의 SQL 쿼리에 악의적인 SQL 코드를 삽입하여 데이터베이스를 조작하거나 민감한 정보를 탈취하는 공격 기법
인프라 클라우드
aws 인프라 구축 경험
깃액션을 통한 cd로 aws의ECR를 도커 이미지 저장소로 사용하고 가상서버인 EC2를 써 프로젝트를 실행했습니다 데이터베이스로는 aws의 RDS를 사용해 mysql를 사용했고 프로젝트를 디벨롭 하면서 하나의 ec2에 부하가 너무 심하게 가해져 메인 서버를 여러 서버로 나누고 소켓서버와 메인서버로 들어오는 요청을 ALB를 사용해 경로기반 라우팅을 했습니다 또한 하나의 메인서버 부하를 담당하기 때문에 부하테스트중 과부하가 걸리는것을 확인했고 (그라파나로 cpu 보니 남은 idle이 0.23) 이를 해결하기 위해 ECS를 사용해 인스턴스 수를 유동적으로 1개에서 3개까지 유동적으로 사용하고 elb를 사용해 트래픽을 분산했습니다
로드 밸런서
로드 밸런서는 네트워크 트래픽을 여러 서버로 분산시키는 장치 또는 서비스로 서버의 부하를 분산시켜 시스템의 성능과 가용성을 향상 시킵니다 또한 서버중 하나가 장애가 발생해도 로드밸런서는 자동으로 다른 서버로의 트래픽을 전환해 서비스 중단을 방지합니다
컨테이너 Devops
Docker란 무엇인가
도커는 애플리케이션을 신속하게 구축 테스트 할 수 있는 플랫폼으로 컨테이너 가상화 기술을 사용해 애플리케이션과 종속성을 함께 패키징해 일관되게 실행되게 한다 컨테이너 가상화는 다른 애플리케이션과 격리된 환경에서 실행할 수 있도록 하는 기술로 컨테이너는 os커널을 공유하지만 독립된 파일 시스템을 제공한다 도커는 일관된 환경을 보장해 개발환경과 운영환경의 통일성을 보장하고 모든 의존성을 컨테이너에 담을 수 있어 환경간 통일성을 보장한다
- 도커의 등장배경 기존에 서버에 대한 관리는 문서를 통해 이루어졌는데 이는 환경이 다를 가능성이 있으며 실수가 있을시 서버가 제대로 동작하지 않았습니다
이란 문제를 해결하기 위해 설정에 필요한것을 코드로 적어놓는 설정파일이 등장했지만 이해하고 관리하는데 힘들었고 한 서버 내에서 같은 프로그램을 여러 환경으로 배포하기가 복잡했습니다
이에 가상화를 사용해 os를 만들어 동작하게 하는 가상머신이 등장했습니다 하지만 가상머신은 설정이 어렵고 결굴 만든 사람이 설정문서를 작성해야 하는데 이는 처음 설정파일의 문제로 돌아가게 됩니다
이에 리눅스 커널에 직접 격리하는 자원 격리가 등장했지만 너무 어려웠고 이를 손쉽게 사용가능하게 만든것이 도커 입니다
CI/CD란 무엇인가
ci는 지속적인 통합으로 빌드와 테스트를 자동화하는 과정이다 ci는 변경사항을 자동으로 테스트해 애플리케이션에 문제가 없다는 것을 보장해준다 코드를 정기적으로 빌드하고 테스트 하기 떄문에 충돌을 방지하고 모니터링 할 수 있다
cd는 배포준비가 된 코드를 자동으로 배포하는 과정을 말한다 성공적으로 통합된 코드가 레포지토리에 자동으로 병합되면 이 코드를 배포한다
AWS
클라우드 시스템
클라우드 컴퓨팅은 컴퓨팅 리소스를 인터넷을 통해 서비스로 사용할 수 있는 주문형 서비스로 직접 물리적 리소스를 관리할 필요가 없으며 사용한 만큼 비용을 지불합니다
aws ACM
SSL/TLS 인증서를 사용해 쉽게 관리 및 배포할 수 있도록 도와줍니다
#### AWS ECS ecs는 aws에서 제공하는 컨테이너 오케스트레이션 서비스로 오토 스케일링을 통해 도커 컨테이너를 쉽게 실행하고 확장할 수 있습니다 이 도커가 어느 그룹으로 들어갈지를 체크
AWS ASG(Auto Scaling Group)
오토스케일링이란 클라우딩 컴퓨팅 환경에서 수요에따라 리소스를 자동으로 조절하는 기능 ec2의 인스턴스의 수를 자동으로 조정해 가용성과 성능을 유지합니다 기존을 세워놓고 cpu 사용량이 이 기준을 넘으면 인스턴스 수를 늘리고 이를 오토스케일링해 관리한다
AWS ALB
어플리케이션 레벨 로드 밸런싱 서비스로 7게층에서 작동합니다 http와 https 트래픽을 로드벨런싱을 하고 http로 오는 값을 https로 보내주고 , api는 api 서버로 ws요청은 소켓서버로 보냅니다
로드밸런싱은 트래픽 부하를 여러 서버로 분산시켜 각 서버가 과도한 부하가 걸리지 않게 하는 기술입니다
aws ECS와 EKS의 차이
마이크로서비스 개발 시에 각각의 용도에 따라 여러개의 컨테이너가 필요하다 컨테이너를 관리를 자동으로 해주는 것을 컨테이너 오케스트라툴이라고 함 쿠버네티스가 대표적이고 aws에는 eks, ecs가 있다
- ecs란 컨테이너의 라이프사이클을 관리하는 aws의 오케스트레이션 서비스다. 배포, 관리를 간소화하는 완전 관리형 컨테이너 오케스트레이션 서비스로 도커를 기반으로 운영된다
ec2 인스턴스 위에 클컨테이너를 실행해 클러스터를 관리하고 인스턴스를 시작하고 중지한다 aws의 서비스를 이용하여 쉽게 배포 와 운영이 가능하다
eks보다 관리가 쉽고 클러스터를 관리하는데 추가적인 비용이 없다 또한 여러 컨테이너 오케스트라네이션 기술(롤링배포, 오토스케일링)이 가능하다
- eks란 쿠버네티스 기반으로 aws에서 운영하며 ec2에 직접 쿠버네티스를 사용하는것보다 클러스터의 운영, 확장, 업드레이드등을 자동으로 해주기 때문에 더 효율적이다
쿠버네티스를 aws와 결합해서 사용하게 해주는 서비스 이기 때문에 쿠버네티스에 대한 지식이 있으면 추천 다른 서비스에 비해 비용이 비쌈
메세지 큐
카프카
카프카는 대규모 실시간 데이터 처리를 위해 설계된 오픈 소스 분산 이벤트 스트리밍 플랫폼으로. 주로 대용량의 데이터를 빠르게 처리하고, 저장하며, 다양한 시스템과 애플리케이션 사이에서 데이터를 신속하게 전송하는 데 사용됩니다.
카프카는 클러스터 시스템을 사용하는데, 여러 브로커로 구성되어 있습니다. 각 브로커는 카프카가 설치된 독립된 서버이며, 이들이 모여 데이터를 처리합니다.
이런 카프카 클러스터에 데이터를 보내는 것을 프로듀서(퍼블리셔)라고 합니다. 이들은 카프카 안의 특정한 토픽에 메시지를 보내게 됩니다.
토픽이란 카프카에서 메시지를 분류하는 카테고리를 말합니다. 각 토픽은 하나 이상의 파티션으로 구성되어 있는데, 파티션은 토픽을 나누는 단위로 데이터를 효율적으로 관리하고 분산 저장 하게 합니다. 파티션은 클러스터 내의 다른 브로커에 할당될 수 있으며, 각 파티션에는 메시지가 순차적으로 저장됩니다. 이 구조는 메시지 처리의 병렬성을 향상시켜 대량의 데이터 처리를 가능하게 합니다.
이렇게 보낸 메시지를 읽어와 작업을 처리하는 구성 요소는 컨슈머(서브스크리이버)라고 합니다. 컨슈머는 하나 이상의 토픽을 구독하며, 이 토픽의 메시지들을 읽어서 필요한 작업을 수행합니다.
저희 프로젝트에서는 카프카를 2번 활용하는데 첫번째는 메인서버가 프로듀서이며 매칭서버가 컨슈머 이고 , 두번째는 매칭서버가 프로듀서 이며 체결 서버가 컨슈머 입니다
메인서버에서 온 주문을 매칭서버로 보내고 매칭서버에서 주문 요청의 유효성을 검증하고 주문을 매칭해 체결 서버로 보내게 되면 체결 서버가 받아 체결을 진행합니다
- 카프카의 원리
Apache Kafka는 대규모 실시간 데이터 처리를 위해 설계된 오픈 소스 분산 이벤트 스트리밍 플랫폼으로. 주로 대용량의 데이터를 빠르게 처리하고, 저장하며, 다양한 시스템과 애플리케이션 사이에서 데이터를 신속하게 전송하는 데 사용됩니다.
Kafka는 높은 처리량, 내구성, 확장성이 특징이며, 메시지를 효율적으로 전송하기 위해 메시지 브로커 시스템을 사용합니다.
카프카는 여러 클러스터에서 여러 브로커를 통해 작동하며 이를 여러 서버에 분산시켜 동시에 처리가 가능해 병목현상을 줄이고 처리량을 크게 향상 시킬 수 있습니다 또한 비동기 통신을 사용해 응답을 기라지지 않고 다른 작업을 계속 진행 할 수 있습니다
카프카가 빠른 이유
설계 방식과 데이터 처리 방식에 있습니다
Kafka는 메시지를 디스크에 append-only 방식으로 저장합니다. 이는 데이터를 디스크에 연속적으로 추가하는 방식으로, 디스크의 랜덤 액세스가 발생하지 않고, 디스크의 순차적 쓰기 작업이 이루어지기 때문에 매우 빠른 쓰기 성능을 제공합니다.
Kafka는 네트워크로 데이터를 전송할 때 zero-copy 기술을 사용합니다.
운영체제가 데이터를 메모리 버퍼에서 네트워크 소켓으로 직접 전송할 수 있도록 하여, 데이터 복사 과정에서 발생하는 오버헤드를 줄여줍니다
또한 Kafka는 데이터를 소량씩 처리하지 않고 배치(batch)로 묶어서 처리합니다. 즉, 데이터가 쌓이면 한꺼번에 읽거나 쓰도록 설계되어 있어 네트워크 호출을 줄이고, 시스템 자원의 활용을 극대화하여 높은 처리량을 유지할 수 있습니다.
Docker와 Docker-compose
도커를 사용해 애플리케이션을 컨테이너로 패키징해 개발 서버와 배포시 환경을 통일합니다
도커 컴포즈를 통해 한번에 이러한 도커 컨테이너를 여러개 정의하고 한번에 실행할 수 있게 해줍니다
이를 사용해 msa환경에서 컨테이너 여러개를 생성해 각각 다른 인스턴스에 배포 하고 관리할 수 있습니다
MSA 도입 시 문제점
MSA는 서비스가 여러개로 쪼개져 있어 서비스 간 통신이 필요합니다 이를 저희 팀에서는 카프카를 통한 비동기 통신을 통해 통신의 속도와 성능을 높일 수 있었습니다
또 각 시스템이 독립적으로 구성되어있어 테스트가 어려워졌고 문제 발생시 문제의 원인을 찾기 위해 경로를 추적해야 하는데
또한 ec2인스턴스의 수가 늘어나 비용 문제가 발생했습니다
AWS와 GCP의 차이
aws는 다양한 서비스와 많은 자료를 보유하고 있지만 서비스의 다양성으로 인해 익숙해지는데 시간이 걸리고 높은 비용이 단점입니다
GCP는 사용한 만큼 돈을 내는 요금제를 통해 비용이 더 저렴하지만 aws에 비해 더 적은 서비스를 제공하고 있습니다
AWS SAm을 통해 서버리스 구축한 경험
aws sam은 서버리스 어플리케이션을 구축하기 위한 오픈소스 프레임워크로 yaml 템플릿을 통해 aws의 서버리스 프로그램을 간단하게 정의할 수 있습니다
sam init을 사용해 템플릿을 만든후 sam 폴더 안에 프로젝트를 만든 후 템플릿.yaml에 들어가 자신이 만든 프로젝트에 맞게 고친 후 sam build, sam deploy를 통해 배포합니다
서버리스 아키텍쳐의 단점
서버리스 아키텍쳐는 사용한 리소스에 대해서만 비용을 지불하고 자동으로 스케일링 된다는 장점이 있지만 요청이 들어올때마다 인스턴스를 초기화하는 과정에서 나타나는 콜드 스타드 문제와 최대 실행 시간이 15분으로 제한되어 있습니다
CI/CD
깃허브에서 메인 브런치에 코드가 push 될때마다 파이프라인이 자동으로 빌드를 시작합니다 먼저 lint와 jest를 통해 테스트 후 문제가 없다면 도커파일이나 도커 컴포즈를 통해 도커 이미지를 빌드하고 푸시합니다
깃허브 액션은 깃허브를 통해 쉽게 사용할 수 있으며 디양한 액션을 통해 쉽게 파이프라인을 구축 할 수 있지만 젠킨스보다 유연하지는 않아 복잡한 요구사항이 있다면 많은 플러그인과 양한 옵션을 통해 파이프 라인을 자유롭게 구성할 수 있는 젠킨스를 선택하는게 좋습니다
Jmeter를 사용한 성능 테스트 경험
주식 프로젝트 진행 중 주식 체결이 한번에 몰릴때 체결이 잘 진행되는지 확인하기 위해 스트레스 테스트를 선택하였고 100명의 사용자가 회원가입, 로그인, 주문을 진행했을때 제대로 잘 진행되고 있는지 TPS는 얼마나 나오는지를 체크하였습니다
처음에는 100명의 유저가 500번 요청을 할경우 504오류가 났지만 서버 분리, 매세지 큐 도입, 스케일링을 통해 개선한 결과 100명의 유저가 1000번 요청시 평균 tps가 894.2로 개선되었습니다
프로메테우스와 그라파나를 통한 모니터링 개념
각 서버에 node-expoter를 설치해 시스템 매트릭을 수집하게 한 후 이를 프로메테우스를 통해 주기적으로 수집하고 이를 그라파나를 통해 시각화 했습니다
그라파나의 Contact point 을 통해 슬랙과 연결하고 alert rule을 통해 메인서버의 cpu가 80% 이상 사용되거나 서버가 다운되면 알람이 가게 했습니다
테스트 경험
jest 모듈을 사용해 하위 객체듫을 모킹해 가짜 객체를 만든 뒤 특정 메서드에 특정값을 반환하도록 설정 한 다음 각 메서드를 호출하여 예상대로 동작하는지 체크했습니다
TDD 의 중요성
TDD란 코드 작성 전에 테스트를 먼저 작성한 후 그 테스트를 통과하는 코드를 구현하는 개발방법론으로 테스트 중심의 개발을 통해 코드의 버그를 예방하고 리팩토링을 안전하게 할 수 있습니다
테스트 기반의 코드를 작성하기 떄문에 각 기능이 명확하게 정의될뿐만 아니라 버그를 예방할 수 있고 테스트 코드가 존재하기 때문에 리팩토링 시에도 안전하게 리팩토링이 가능하다
TDD는 Red-Green-Refactor로 진행되며 실패하는 테스트를 작성하는 레드, 테스트를 통과하는 최소한의 코드를 작성하는 그린을 작성한 후 그린 코드를 리팩토링해 더 좋은 구조호 바꿉니다
라이브러리와 프레임워크의 차이
라이브러리는 특정 기능을 제공하는 코드 집합으로, 개발자가 필요할 때 직접 호출해서 사용하는 방식입니다. 개발자가 제어권을 가지고 특정 기능을 구현할 때 사용합니다
반면 프레임워크는 애플리케이션의 전체적인 구조를 제공하며, 개발자가 그 틀에 맞춰 코드를 작성해야 하며 프레임워크가 애플리케이션의 흐름을 제어합니다
라이브러리와 프레임워크는 개발 과정에서 생산성을 높이고 코드의 재사용성을 향상시키기 위해 사용됩니다.
개발자가 처음부터 모든 기능을 직접 구현하게 되면 중복된 코드가 많아지고, 효율성이 떨어지며 유지보수가 어려워질 수 있습니다.
라이브러리와 프레임워크는 검증된 기능들을 제공하여 반복적인 작업을 줄이고, 구조화된 코드 작성을 유도합니다.
Comments