[F-Lab 모각코 챌린지 49일차] 강의 돌아보기

부추·2023년 7월 19일
0

F-Lab 모각코 챌린지

목록 보기
49/66

최근 며칠간 배웠던 개념을 초간단하게 복습해보자! 개발자가 개발을 하고, 배포하고, 띄운 인스턴스에 user의 요청이 가고 DB를 거쳐 응답이 내려지기까지 어떤 솔루션들이 사용되는지 생각해보장.


형상관리 툴 : GIT

기능 개발, 버그 수정, 리팩토링 등의 이유로 코드는 항상 새로 작성되거나 수정된다. 또한 팀 프로젝트에서 코드는 한 사람이 작성하는 것이 아니기 때문에 개발자마다 다른 코드를 작성하기도 한다. 시기에 따라, 그리고 작성자에 따라 코드는 각각의 "버전"을 가지고 있고, 이를 기록하고 관리하기 위한 툴이 필요하다.

그것이 GIT! GIT은 커밋 단위로 코드의 버전을 관리하고, branch를 나누는 방법으로 버전을 분기하여 코드를 작성하게 해준다. 각 브랜치는 분기되고, commit 단위로 코드가 추가되고, merge되기도 하고 서로 다른 브랜치에서 동일한 코드가 수정되었을 경우 conflict가 일어나기도 한다. (팁 : conflict를 막는 법 : conflict를 애초에 안일어나게한다;)

협업과 기능 개발을 위해 [git flow]를 컨벤션으로 많이들 사용한다.

  • main : 주로 현재 배포되어 서비스되고있는 코드 버전이다.
  • develop : 기능 개발의 base 브랜치이다. 배포 직전,
  • hotfix : 버그 수정을 위해 main 브랜치에서 급하게 임시로 뻗어나온 브랜치이다.
  • feature/** : ** 기능을 위해 개발중인 브랜치이다. 주로 develop에서 뻗어나오며, 개발이 완료되고 merge의 기준이 된다.

git에 따른 코드 버전을 모아놓은 저장소가 Github이다. 추가로 놀랐던 점은, 개발자들 역시 소스트리, 깃크라켄, github desktop 등의 GUI툴을 많이 이용한다는 것이었다. 혼자 머릿속으로 branch 그림 그려갔는데 문명의 이기를 조금 누려도 되는 부분인 것 같다.


CI/CD 툴 : Jenkins

Jenkins는 초간단하게 말하면 자동 빌드 및 배포 툴이다. 지속적 코드 통합을 뜻하는 CI(Continuous Integration), 지속적 배달을 뜻하는 CD(Continuous Deployment)를 가능하게 해준다. 젠킨스는 CI/CD 파이프라인을 구성해줌으로써 개발자가 특정 버전의 코드를 개발 완료할때마다 손빌드하고 실행하는 과정을 생략할 수 있게 해준다.
위를 보면, CI/CD를 위한 파이프라인이 어떻게 구성되었는지 보인다. javac를 통해 자바 소스를 컴파일하고, (gradle 등의 빌드 툴을 쓴다면 $ gradlew build..), 테스트를 하고, -jar을 통해 빌드된 jar 파일을 실행시키는 과정이 포함된다.

젠킨스는 상기한 CI/CD 파이프라인을 구성에 포함된 플러그인을 통해 진행한다. 모각코 챌린지동안 실제로 진행했던 실습에서, 나는 젠킨스 플러그인을 이용해 내 WAS가 돌아가는 워커 인스턴스 3개에 SSH 접속을 한 뒤 maven의 정해진 커맨드를 입력할 수 있도록 jenkins를 구성했다.


가상화 도구 : Docker

서버 컴퓨터에 프로세스를 실행하기 위해 필요한 모든 것을 구성하는 것은 힘들다. 여러 개의 프로그램 이미지를 구동시킨다고 했을 때 각각의 프로세스를 VM 위에 돌리려면, VM각각을 위한 하드웨어 자원을 나눠주는 hypervisor 프로그램 위에 VM을 올리고, 그 위에 OS를 깔고, 또 그 위에 프로그램을 적재하는 방식을 써야 한다. OS는 무거운 프로그램이다. hypervisor만으로도 충분히 컴퓨터에 부담인데, 이 모든 것을 진행

docker는 이렇게 OS 단위가 아닌 process 단위의 격리 환경을 제공한다.
개발자는 로컬에서 잘 구성된 런타임(간단하게 실행환경이라 생각하자)과


웹 서버 : NginX

웹 서버는 사용자의 요청을 받고 정적인 컨텐츠를 내려주는 프로그램으로, 동적인 컨텐츠를 응답으로 주는 웹 "어플리케이션(=WAS)" 서버와는 구분되는 개념이다.

웹 서버는 WAS의 앞단에 위치한다. 일반적으로 사용자 요청의 더 빠른 처리를 위해 WAS는 여러 인스턴스를 두게 되는데, 이들 앞에 위치한 WS는 사용자 요청을 각 WAS에 적절히 로드밸런싱, 즉 부하 분산을 해서 요청이 한 곳에만 몰리지 않도록 한다. 그리고 '리버스 프록시'를 통해 실제 서버로의 요청을 막아 사용자가 서버의 실제 IP주소나 상세 정보를 알지 못하도록 하여 보안적인 이점도 달성할 수 있게 한다. 그리고 WS는 그 자체로 웹 서버이므로, 어플리케이션 로직이 필요하지 않는 정적인 콘텐츠에 대한 요청은 WS단에서 응답할 수 있도록 "캐시 서버"로서 구성할 수도 있다.

실습에서는 그 중에서도 nginx를 사용했다. 모든 요청에 대해 프로세스를 생성하는 apache와 다르게, nginx는 하드웨어의 각 코어에 맞는 worker 프로세스, 그리고 각각에 Queue를 둔다. HTTP 커넥션 생성에 대한 요청, 그리고 각 커넥션에 대한 복수의 요청들을 모두 "이벤트"로 보고 워커 프로세스들이 해당 이벤트를 처리할 수 있도록 구성했다.


웹 어플리케이션 서버 : 톰캣

WAS는 사용자 요청에 맞는 어플리케이션 로직을 수행한 뒤 동적인 페이지, 혹은 데이터를 구성해 사용자 응답을 내려주는 서버이다. 우리가 작성한 실습 프로젝트는 DB에서 특정 데이터를 읽어 사용자에게 return하는 IO bound application이었는데, 프레임워크로 스프링 부트를 사용했다. 스프링 부트의 auto configuration에서 WAS로는 톰캣을 기본으로 사용한다.
톰캣은 servlet container이다. 서블릿이란 사용자 HTTP 요청을 받아 로직을 수행하고 사용자 HTTP 응답을 내려주는 그자체의 프로그램 하나이다(사실 자바에선 객체다). 서블릿 컨테이너(=톰캣)가 요청을 받으면 컨테이너에 올라온 서블릿 중 알맞은 서블릿에 사용자 응답을 전해주고 서블릿 로직을 실행시킨다. 그리고 서블릿이 뱉은 응답을 다시 돌려주는 것이다.

기존엔 web.xml에 각 요청 path에 맞는 서블릿 객체를 등록했는데, 지금은 dispatcher servlet이라는 서블릿 하나가 모든 요청을 받는 구조이다. 디스패처 서블릿이 사용자 요청을 받고, Handler Mapping에게 적절한 컨트롤러를 질의하고, Handler Adapter에게 handler 메소드 수행을 요청한 뒤 받은 데이터를 view resolver에게 전달하여 구성된 응답을 다시 servlet container에게 돌려주는 구조를 가진다.


메세지 큐 : Rabbit MQ

사용자 요청에 대한 응답과 상관 없는 데이터에 대해, 그러니까 꼭 동기적으로 실행될 필요가 없는 많은 데이터 처리에 대해 message queue를 도입했다.

사용자가 글을 서버에 post했을 경우 작성된 글이 DB 서버에 post가 된 뒤 정상적인 응답을 받도록 서버를 구성한다면 응답이 굉장히 느려질 것이다. 그리고 해당 작업이 수행되는 동안 WAS 스레드는 대기 상태로, 그동안 사용자 요청을 받지 못하고 있으므로 자원 낭비도 심하다. 이 때 MQ 도입을 고려할 수 있다.
메세지 큐를 사용함으로써 얻을 수 있는 이점이다.

  1. 비동기 처리 가능 : 동기적으로 처리될 필요가 없는 메세지를 MQ에 넣고 이를 consume하는 인스턴스를 따로 구성해서, 로직들을 분리하고 자원의 낭비를 최소화할 수 있다.
  2. 시스템간 의존성을 낮춤 : MQ에 쌓인 데이터들은 인스턴스들에 의존적이지 않다. 인스턴스가 죽어도 MQ의 데이터는 유지되므로, system migration에 대한 걱정이 줄어든다.

검색 서버 : Elastic Search

30만건의 데이터에 인덱스 없이 특정 단어를 검색하면 15초 가까이 되는 시간이 걸렸다. 그러나 ES를 이용해서 검색을 3초 이내의 시간으로 단축할 수 있었다.
Elastic search는 역색인, 샤드, 레플리카를 통해 일반 DB보다 더 빠른 검색 기능과 데이터 안전성을 제공한다. (음.. 근데 사실 데이터 안정성은 ES만의 특징이라고 보긴 힘들다)

역색인은 정보 서적의 맨 뒷장, 단어로 컨텐츠 찾기를 생각하면 된다. ES의 인덱스에 들어오는 document들은 형태소 단위로 분리되어, 헤당 형태소와 document ID가 key-value자료구조로 저장된다. 사용자가 형태소로 select 요청을 날리면, 검색 자체가 key로 이뤄지므로 full scan을 하는 일반 select 쿼리에 비해 훨씬 빠르게 결과 응답을 내려줄 수 있는 것이다.

게다가 ES 인스턴스를 여러개로 분리해서, 즉 sharding을 써서 여러개의 노드들이 분리된 데이터 공간을 탐색하게 구성할 수 있다. 그러면 검색 성능은 더욱 빨라진다!!

profile
부추튀김인지 부추전일지 모를 정도로 빠싹한 부추전을 먹을래

0개의 댓글