[Kakao Cloud School] 4번째 회고록

lango·2022년 11월 28일
0
post-thumbnail

Intro


공부할 것은 많다.

이번 주는 많은 내용을 일주일이라는 짧은 시간에 배우게 되었다.

node의 기본적인 문법을 배우고, API 통신에 필요한 모듈들을 활용해 CRUD 실습을 진행하면서 클라이언트와 서버간 데이터를 교환하는 흐름에 대해서 이해도를 높일 수 있었다.

그리고 데이터베이스를 활용해 서버와 통신하면서 데이터를 어떤 시점에 적재하고, 가져오는지 알 수 있었으며, 그 과정을 어떻게 효율적으로 구성할 수 있을지 고민하는 시간들을 가지게 되었다.

배움에는 끝이 없다.라는 말을 최근 많이 공감하고 있다. CS 지식과 함께 알고리즘 공부도 병행하는데 모르는 것도 많고, 잘못 알고 있던 것들도 많았다. 이러한 점을 매주매주 알게되고, 또 고치고 있기 때문에 공부하는 것이 즐겁게 느껴진다.




Day - 14

오늘은 Docker에 mariaDB 이미지를 컨테이너에 올려서 활용하는 시간을 가졌다. 개인적으로 궁금했던 내용들이 많아 재미있게 배울 수 있었던 하루였다.


DB를 Docker에 설치해서 사용하라고?

이전부터 많은 개발자들이 docker를 활용해 컨테이너에 DB를 올려두고 사용하는 방식을 보았다.

그래서 도커를 활용해 컨테이너 내에 DB를 설치하여 외부에서 접근하는 방식이 좋은 방식인지 궁금하여 찾아보았다.

Docker는 무엇인가?
Docker와 같은 가상화 컨테이너는 애플리케이션을 신속하게 구축, 테스트 및 배포할 수 있는 소프트웨어 플랫폼이다. 즉, 컨테이너의 빠른 생성과 파괴를 통해 원활한 배포, 구축을 도와주는 소프트웨어다.

데이터베이스는?
데이터베이스는 여러 사람이 공유하여 사용할 목적으로 체계화해 통합, 관리하는 데이터의 집합이다. 영속(permeanent)된 데이터를 위해 만들어진 개념이다.

docker는 이미지를 컨테이너화해서 생성 및 소멸시키는 과정을 통해 배포환경과 개발환경을 일치시키기 쉽도록 도와준다. 이미지를 구성하는 도중 설정이 잘못되더라도 컨테이너를 삭제하고 다시 만들고 설정하면 되기에 굉장히 편리하다.

이러한 생성 및 소멸의 주기가 잦은 성질을 지닌 도커에 데이터베이스를 접목하려 할 때 개념적으로 의구심이 들게 되었다. 데이터베이스는 영속성을 지닌 집합체인데, 컨테이너가 없어지면 데이터도 사라지기 때문에 데이터베이스의 영속성을 무너뜨리게 된다. 물론 대안으로는 별도로 컨테이너와 호스트간 볼륨 설정을 하여 컨테이너가 삭제되더라도 컨테이너 외부에 백업되도록 한다면 큰 문제는 없다.

하지만 데이터의 영속성을 지키기 위해 도커에서 컨테이너와 관련된 볼륨 설정을 해야 하기 때문에 도커를 사용하는 이유 중 하나인 빠르고 편리한 컨테이너 활용에 대한 장점이 흐려지게 된다고 느꼈다.

현재로서는, 간단한 예제나 실습 위주의 미니 프로젝트들을 진행하면서 도커 컨테이너에 MariaDB를 활용하고 있지만, 실무 수준의 프로젝트를 진행할 때는 더욱 고민이 생길 것이다.

단순하게 로컬 환경에서 DB를 설치하여 활용하는 방법도 있고, MS의 Azure나 Google의 GCP, Amazon의 AWS 등에서 데이터베이스만을 위한 서비스를 이용하는 방법도 있다.

마냥 docker를 통해 DB를 이용하는 것이 마냥 좋은 선택은 아닐지도 모른다. 결국 주어진 프로젝트의 규모와 수준에 맞춰 적절히 docker를 이용하는 것이 최선일 것이라고 생각한다.



MySQL과 MariaDB는 뭐가 다를까?

mariaDB를 사용하는데 MySQL과 관련된 파일이라던가, 설정같은 내용들을 많이 볼 수 있었는데, 이 둘은 무슨 차이가 있는지 알아보자.

MySQL이란?
90년대 중반에 개발된 MySQL은 시장에서 사용할 수 있는 최초의 오픈 DB중 하나이며 가장 널리 사용되고 있는 관계형 데이터베이스 관리 시스템(RDBMS: Relational DBMS)이다.

MySQL은 단순 쿼리 처리 성능이 어떤 제품보다 압도적이며 이미 오래 사용되어 왔기 때문에 성능과 신뢰성 등에서 꾸준히 개선되어 온 것이 장점이라고 한다.

또한 오픈 소스로써 다중 사용자와 다중 스레드를 지원하고 C언어, C++, JAVA, PHP 등 여러 프로그래밍 언어를 위한 다양한 API를 제공하며 MySQL은 유닉스, 리눅스, 윈도우 등 다양한 운영체제에서 사용할 수 있다.

MariaDB란?
발전하던 MySQL이 2010년에 썬마이크로시스템즈와 오라클이 합병되면서 많은 MySQL 개발자들은 썬마이크로시스템즈을 떠나며 본인만의 프로젝트를 진행하게 된다. 이 중 MySQL의 창시자인 몬티 와이드니어가 만든 프로젝트가 바로 MariaDB이다.

MariaDB는 MySQL 데이터베이스 시스템을 기반으로 fork한 서비스로 MySQL의 개선된 버전이다. 그래서 MariaDB와 MySQL의 호환성은 매우 높다.

또한 MySQL에서 찾을 수 없는 수많은 내장된 강력한 기능과 많은 유용성, 보안 및 성능 개선사항이 함께 제공된다고 한다. MariaDB는 MySQL을 기반으로 만들어졌기에 전반적인 사용법은 매우 유사하다.


10 reasons to migrate to MariaDB (if still using MySQL)

2015년에 현 AWS개발자가 MariaDB를 사용해야 할 10가지 이유를 제시했다.

  1. MariaDB 개발이 좀 더 개방적이고 활발한 커뮤니티를 지님
  2. 빠르고 투명한 보안패치 릴리즈
  3. 다양한 기능
  4. 다양한 스토리지 엔진
  5. 더 나은 성능
  6. Galera 액티브-액티브 마스터 클러스터링
  7. 오라클 관리하의 불확실성
  8. 계속 상승하는 MariaDB의 유명세
  9. 호환성과 쉬운 마이그레이션
  10. 15년 이후에는 마이그레이션이 어려울 수 있다

MySQL VS MariaDB

아무래도 MySQL을 기반하여 만든 MariaDB를 사용하는 것이 좋지 않을까 결론을 지었다.

MariaDB는 MySQL을 포크한 서비스인 점도 있지만 MySQL에 확장성을 더하여 다양한 사용자들의 시행착오들을 반영했을 것이기 때문이다.

그리고 이 둘은 문법적으로도 매우 유사하기 때문에 러닝커브 차이가 크게 나지 않는다는 점에서 정책적인 면에서 더 안정적인 MariaDB에 손을 들어주고 싶다.



검색기능을 구현하는 것은 쉽지 않다.

구글에 HELLO을 검색하든 hello를 검색하든 대소문자 구분이 없기에 결과는 같다.

"      hello" 라고 공백을 포함하여 검색해도 결과는 같다.

그렇다면 hello adel이라고 검색했을 때와 adel hello 라고 검색했을 때는 어떻게 같은 걸까?

공백이 포함된 키워드를 검색해야 한다면 반드시 검색 키워드를 공백기준으로 쪼개어 쪼갠 단어들로도 검색이 되도록 구현해야 사용자 입장에서 불편함이 없어질 수 있지 않을까?

단순한 검색기능 하나를 구현하는 것에도 많은 시간과 고민들을 해야 한다.



Day - 17

오늘은 Node와 MariaDB를 연동하는 과정을 학습하게 되었다. 단순히 연동하는 것도 중요하지만 삽입,탐색,수정,삭제(CRUD) 작업을 통해서 클라이언트와 서버간 데이터를 교환하는 흐름에 대해서 이해할 수 있었다.


DB에서의 인덱스(Index)란?

DB를 사용하면서 데이터 양(row)이 많으면 많을수록 실행결과가 느려진다. 그리고 JOIN문이나 서브쿼리를 사용하게 되면 실행속도는 더욱 늘어난다.

이 경우 인덱스를 적절하게 활용하여 쿼리의 성능을 높일 수 있다고 알고 있었는데, 인덱스를 사용하면 어떤 이점이 있는지 알아보자.

인덱스(Index)란?
추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 성능의 속도를 향상시키기 위한 자료구조이다.

하나의 컬럼에 인덱스를 생성하면, 해당 컬럼의 데이터들을 정렬하여 별도의 메모리 공간에 데이터의 물리적 주소와 함께 저장된다.

인덱스를 생성한 후 WHERE문에 해당 컬럼을 작성하는 작업 등을 하면 옵티마이저에서 판단하여 생성된 인덱스를 탈 수 있다.

옵티마이저는 무엇인가?
옵티마이저는 가장 효율적인 방법으로 SQL을 수행할 최적의 처리 경로를 생성해주는 DBMS의 핵심 엔진이다. 컴퓨터의 두뇌가 CPU인 것처럼 DBMS의 두뇌는 옵티마이저라고 할 수 있다.

만약 인덱스를 타게 되면 먼저 인덱스에 저장되어 있는 데이터의 물리적 주소에서 데이터를 가져오는 방식으로 동작하여 검색 속도를 향상시킨다. 그리고 인덱스를 통해 데이터를 오름차순으로 정렬한 모습을 확인할 수 있는데, 아래 그림을 보면 이해하는데 도움이 될 것이다.

인덱스를 사용하는 이유는?

인덱스를 사용하는 가장 큰 이유는 아무래도 데이터가 정렬되어 있다는 점이 아닐까 생각한다.

이 특징은 특정한 조건을 검색할 때 많이 유리하다.

  • WHERE절
    기본적으로 테이블에 데이터가 쌓이면 특별한 순서 없이 저장된다. 이렇게 되면 조건을 충족하는 데이터를 탐색하는데도 처음부터 끝까지 찾는 풀 테이블 스캔 (Full Table Scan)을 하게 된다. 하지만 인덱스를 생성하여 조건을 검색하게 되면 이미 데이터들이 정렬되어 있기 더욱 빠르게 찾아낼 수 있다. 이 것을 인덱스 테이블 스캔(Index Table Scan)이라고 한다.

  • ORDER BY절
    ORDER BY는 부하를 받는 작업이기에 실행 속도가 느린 편이다. 그런데 인덱스를 활용하면 이미 정렬되어 있어 탐색 후 가져오기만 하면 되기 때문에 이러한 ORDER BY절의 단점을 개선할 수 있다.

  • MIN, MAX 처리
    처음부터 끝까지 탐색하는 것이 아니라 정렬된 데이터에서의 시작 값과 끝 값을 하나씩만 가져오면 되기에 풀 스캔보다 뛰어난 성능을 보여준다.

무조건 인덱스를 사용해야 하는 걸까?

  • DML에서의 인덱스는 취약하다.
    INSERT, UPDATE, DELETE문을 통해 데이터를 추가하거나 값을 변경한다면 인덱스 테이블을 다시 정렬해야 한다.

    결국 기존의 원본 테이블과 인덱스 테이블 두 곳을 유지보수해야 한다는 번거로움이 발생한다. 그래서 DML이 빈번한 테이블보다는 검색(SELECT)의 비중이 높은 테이블에 인덱스를 생성하는 것이 좋다.

    DML(Data Manipulation Language, 데이터 조작 언어)이란?
    데이터베이스의 내부 데이터를 관리하기 위한 언어이다. 데이터를 조회, 추가, 변경, 삭제 등의 작업을 수행하기 위해 사용된다. SELECT, INSERT, UPDATE, DELETE가 있다.

  • 인덱스 스캔이 마냥 좋지는 않다.
    검색을 위주로 하는 테이블에 인덱스를 생성하는 것이 좋지만 무조건 검색 시에도 인덱스가 좋은 것은 아니다.

    하나의 예를 들어보자. 1개의 데이터가 있는 테이블과 100만 개의 데이터가 들어 있는 테이블이 있다고 하자. 100만 개의 데이터가 들어있는 테이블이라면 풀 스캔보다는 인덱스 스캔이 유리하겠지만, 1개의 데이터가 들어있는 테이블은 굳이 인덱스 스캔 없이 풀 스캔이 빠를 것이다.

  • 속도 향상만을 위한 인덱스 남용은 바람직하지 않다.
    인덱스를 관리하기 위해서는 데이터베이스의 약 10%에 해당하는 저장공간이 추가로 필요하다. 이 말은 무턱대고 인덱스를 만들어서는 결코 안 된다는 것이다.


결론은 index를 활용해야 하지만 남발하지 말아야 한다고 느꼈다.

보통 성능 문제 이슈가 발견되면 하나의 대안으로 인덱스를 추가 생성하는 방법이 떠오르게 되는데 이는 좋지 않는 생각일 수 있음을 알게 되었다.

왜냐하면 인덱스를 생성하면서 문제를 해결하기 위한 쿼리문 속도를 줄일 수는 있지만 추후 인덱스가 쌓이게 되면서 INSERT, UPDATE, DELETE시에 데이터베이스의 성능 부하를 일으킬 수 있기 때문이다.

그렇기에 무작정 인덱스를 생성하기보다는 쿼리문의 성능을 더 효율적으로 작성할 수는 없는지 먼저 고민하는 시간을 가져야 한다고 생각한다.



페이징 처리를 위해 일부분의 데이터를 어떻게 가져올까?

페이징 처리를 위해서는 전체 데이터 중에서 원하는 개수만큼의 데이터를 가져와야 한다. 그런데 어떻게 원하는 개수만큼 일부분의 데이터를 가져올 수 있을까?

네이버 뉴스 기사에서는 어떻게 페이지를 처리했는지 살펴보려고 한다. IT/과학 메뉴로 이동하면 기본으로 1페이지 기사들을 볼 수 있다. 이 때의 URL 값은 다음과 같다.
https://news.naver.com/main/main.naver?mode=LSD&mid=shm&sid1=105

그리고 2페이지로 이동했을 때의 URL 값이다.
https://news.naver.com/main/main.naver?mode=LSD&mid=shm&sid1=105#&date=%2000:00:00&page=2

또한, 3페이지로 이동했을 때의 URL 값이다.
https://news.naver.com/main/main.naver?mode=LSD&mid=shm&sid1=105#&date=%2000:00:00&page=3

2페이지, 3페이지 일 경우의 URL에 포함된 파라미터를 잘 살펴보면 page라는 값을 전달하고 있음을 알 수 있다.

그런데 1페이지의 경우는 파라미터에 page 값이 없더라도 1페이지를 보여주고 있다. 즉, page라는 파라미터 값이 없을 경우엔 1페이지를 보여주는 것이다. 이로 인해 페이징 처리를 할 때 파라미터로 넘겨주는 값을 유의해야 함을 알게 되었다.

또한, 가져올 수 없는 데이터, 즉 없는 데이터를 가져오는 요청은 굳이 서버와 데이터베이스까지 접근하여 데이터를 조회할 필요가 없다. 서버가 클라이언트에게 전체 데이터 갯수를 전송해준다면 클라이언트에서는 응답해줄 수 없는 요청에 대해서 서버까지 접근할 필요없이 즉각적으로 대응할 수 있을 것이라고 느끼게 되었다.



Day - 18

Back-End와 Front-End는 왜 분리되었나?

이전부터 배워왔던 일반적인 소프트웨어 구조는 백엔드와 프론트엔드가 통합된 모놀리식 아키텍처(Monolithic architecture) 형태였다. 이전에 실무에서 개발할 때에도 백엔드와 프론트엔드가 통합된 소프트웨어 구조 안에서 업무를 진행했던 기억이 있다.

모놀리식 아키텍처(Monolithic Architecture)란?
마이크로서비스 아키텍처(Micro Service Architecture)와 반대되는 개념으로 하나의 서비스 또는 애플리케이션이 거대하거나 통합된 아키텍처를 가지는 형태이다.

요즈음 개발 공부를 다시 시작하면서 머릿속에 각인된 것들 중 하나는 이러한 모놀리식 아키텍처가 아닌 백엔드와 프론트엔드가 분리된 서비스를 구축해야 한다는 것이다.

백엔드와 프론트엔드가 통합된 서비스에선 무엇이 불편할까? 프로덕트의 규모가 커짐에 따라 코드량이 늘어나고 일부분의 오류 때문에 유지보수 하기가 굉장히 힘들다는 단점이 존재한다.

웹의 발전에 따라서 규모가 큰 서비스들이 등장하고 성장하면서 이러한 치명적인 단점을 극복하기 위해서 자연스럽게 백엔드와 프론트엔드를 분리하여 구축하게 되었다고 생각한다.

그렇다면 백엔드와 프론트엔드를 분리하면 챙길 수 있는 이점은 무엇이 있을까?

높은 확장성

백엔드와 프론트엔드가 구분되어 있어 개발자가 코드별로 최적화에 신속하게 대응이 가능하다. 그리고 통합형 프로덕트보다 빠르게 빌드할 수 있으며, 리소스 관리도 수월하게 할 수 있다.

자원 최적화

통합형 서비스에선 요청에 대해서 데이터를 읽고 가공하여 템플릿 엔진 등으로 렌더링하는 작업을 수행하는데 반해 분리된 서비스에선 백엔드 단에서 데이터를 가공하여 JSON 형식으로 프론트엔드에 전송하고 일을 마친다. 이로 인해 분리된 서비스에서 서버 리소스 관리가 훨씬 유리하다는 것을 알 수 있다.

기술 전환의 유연함

백엔드와 프론트엔드의 기술 언어를 전환한다고 할 경우 백엔드와 프론트엔드가 분리되어 있다면 상대적으로 서로에게 큰 영향없이 전환할 수 있다.

무조건 백엔드와 프론트엔드를 분리해야 하나?

스스로 내린 결론은 프로젝트 및 개발팀 규모에 맞춰 선택해야 한다는 것이다. 팀과 조직 및 요구사항에 따라서 규모가 클 수록 분리하여 구축하는 것이 더욱 효율적일 것이지만, 반대로 요구사항이 단순하다면 분리해서 구축하는 것은 리소스 낭비가 될 수 있다고 생각이 들었다.



왜 인덱스는 0부터 시작하는 걸까?

일반적으로 프로그래밍 언어에서는 특정한 집합에 존재하는 원소에 접근할 때 어디서부터 어디까지라는 인덱스의 범위를 지정하게 된다.

  • Half-open interval
    인덱스는 시작 수는 포함하고 마지막 수는 제외한다.
  • Zero-based numbering
    첫번째 인덱스는 0부터 시작한다.

예를 들어 10번의 반복을 표현한다면 인덱스의 범위는 다음과 같다.
0 <= index < 10

이렇게 표현하는 이유는 무엇인지 궁금하여 찾아보았는데, 네덜란드의 유명한 컴퓨터 과학자인 다익스트라(Dijkstra)가 작성한 제안서를 볼 수 있었고 내용을 간단하게 살펴보자.

구간을 나타낼 때 4가지의 표현법이 있다.

  • 열린 구간
  • 닫힌 구간
  • 반열린 구간
  • 반닫힌 구간

다익스트라는 이 4가지 방법중 시작은 닫힌구간, 끝은 열린구간으로 표현하는 것이 좋다고 이야기한다. 2에서 12까지의 정수를 표현하는 예를 들어보자.

  1. 1 < n < 13
  2. 2 <= n <= 12
  3. 1 < n <= 12
  4. 2 <= n <= 13

4번 방식인 2 <= n <= 12가 가장 좋다고 이야기 하는데, 그 이유는 시작과 끝의 간격은 전체 요소의 개수와 일치하는 것이 좋기 때문이라고 한다.

2와 12 사이의 숫자는 총 11개, 위 방식의 시작과 끝의 차이는 11로 전체 요소의 개수와 일치한다.

그리고 n개의 요소를 가진 배열의 인덱스를 표현할 때 앞에서 언급한 4번 방식을 이용하면 다음과 같이 2가지로 표현할 수 있다.

  1. 0 <= i <= n
  2. 1 <= i < n+1

위 2가지 방법중 2번보다 1번 방식이 요소의 개수와 구간의 숫자가 일치하기에 더 나은 방식이라는 것이 다익스트라의 견해이다.

결국 위 견해에 의해서 많은 프로그래밍 언어의 인덱스는 0부터 시작하게 되었다고 한다.



데이터 삭제는 GET? POST? DELETE?

여태 배우고 사용해왔던 HTTP Method들 중에 GET방식과 POST방식은 모두 클라이언트에서 서버로 데이터를 전송하는 방식으로 사용한다. 둘의 차이점을 간단하게 설명하면 GET은 가져올 때 사용하고 POST는 수행할 때 사용한다는 것이다.

GET은 서버에 저장된 데이터를 가져오는 작업에 주로 사용하고, POST는 서버의 데이터나 상태를 변경하는 데 사용하는 것으로 알고 있다. 애초에 GET방식과 POST방식은 목적 자체가 다르다.

GET방식을 수정이나 갱신하는 용도로 잘 활용하지 않는 이유는 URL에 데이터를 포함하여 요청하기 때문에 누구든지 URL에 접근하고 조작하여 저장된 데이터에 영향을 끼칠 수 있기 떄문이다. 반대로 단지 데이터를 가져와 열람하는 목적이라면 POST방식보다 GET방식이 적절하다고 할 수 있다. 즉, 데이터를 수정하거나 추가할 때는 반드시 POST방식으로 작업을 진행해야 한다.

그런데 데이터를 삭제하는 작업은 GET, POST, DELETE 중 어느방식으로 해야하는 것인지 궁금해졌다.

실제로 사용자의 데이터를 삭제하는 경우도 있지만, 삭제의 의미가 데이터를 삭제하는 것이 아니라 일시적으로 사용할 수 없는 상태로 변경하는 경우도 있다.

그래서 서버의 실제 리소스를 삭제할 때는 DELETE 방식으로 삭제 작업을 진행해야 하고, 삭제하지 않는 경우라면 GET이나 POST방식으로 데이터의 상태를 변경하여 삭제된 것처럼 취급하는 작업을 진행하면 되는데 이 때, 삭제한 데이터를 클라이언트에게 전송하여 화면에 출력하여 사용자에게 알려줘야 할 경우도 포함된다고 생각이 들었다.

간단하게 정리해보면 서버에서 삭제 작업을 마칠 경우엔 DELETE 방식을, 서버에서 삭제 작업을 한 후 클라이언트에게 전송할 경우는 GET이나 POST 방식으로 삭제 작업을 하도록 하자.






Final..

아직 배울 것이 너무나도 많고 실력도 부족한 비기너이지만, 인정받는 주니어로 커가기 위해 노력하는 것이 쉽지는 않다. 그저 되는대로 넘어가지말고 동작원리부터 이해하기 위해 찾아보고 고민하는 시간을 가지는 건 항상 어렵다.

하지만 내가 알고 있는 지식을 동료에게 똑바로 알려주고 싶다. 그러기 위해 1부터 100까지 이해하지 못하더라도 1부터 100까지 알기 위해 노력했다는 것을 남기기 위해 배우고 공부하자.



혹여 잘못된 내용이 있다면 지적해주시면 정정하도록 하겠습니다.

참고자료 출처

profile
찍어 먹기보단 부어 먹기를 좋아하는 개발자

0개의 댓글