이번 7주차에서는 나만의 작은 사진 공유 사이트를 만들었다. Express.JS와 MySQL을 이용하여 백엔드 서버를 만들었다. MongoDB를 이용하기 위해 mongoose라는 ORM을 이용했다면, MySQL을 이용하기 위해서 Sequelize라는 ORM을 사용하였다. 또한, Docker를 사용하여 MySQL을 실행하였다. Docker에 대한 설명은 후술하겠지만, 가벼운 가상 머신을 떠올리면 이해가 빠를 것이다.
MySQL workbench도 사용해본 적이 없는 입장에서 바로 docker를 활용한 MySQL과 Sequelize라는 생소한 ORM을 사용하는 것은 꽤나 힘든 일이었다. 관계 설정을 제대로 하는 방법을 몰라서 며칠을 끙끙대며 공식문서와 검색을 해야했고, 나중에 DataGrip을 이용하여 Table 사이의 관계도를 펼쳐 보았을 때 내가 생각했단 관계가 설정되어 있어 얼마나 기뻤는지 모르겠다. 그 외에는 일반적인 CRUD를 구현, jwt를 이용한 로그인과 단방향 해쉬를 이용한 회원가입, 무한스크롤을 위한 api 구축, joi를 활용한 validation, 그리고 jest와 supertest를 활용한 테스트 코드 작성을 해보았다. Sequelize와 jest, supertest, joi는 여전히 모르는 부분이 많고 dotenv와 cross-env 활용한 환경변수 조작에 대해서도 공부할 것이 산더미처럼 쌓여있다.
도커
Docker란, Linux 컨테이너를 만들고 사용할 수 있도록 하는 컨테이너화 기술이다. 개발자가 개발을 하다보면, 서로 다른 환경을 고려하지 못한 경우에 문제가 발생할 수 있다. 스스로 고려하지 못한 환경 변수가 반영되어 코드가 구성된다면, 다른 환경에서는 정상적으로 작동하지 않을 수 있는 것이다. 이를 해결하기 위한 방법으로는 어떤 것이 있을까? 곧바로 떠오르는 것은 바로 가상머신을 활용하여 실행 환경을 통일하는 것이다. 가상머신을 이용하여 컴퓨터를 가상화하고, 최초 설정부터 동일하게 진행한다면 서로 다른 환경에서도 동일한 환경을 구축하여 성공적으로 구현된 기능을 실행할 수 있을 것이다. 그러나 가상 머신을 활용한다고 만사형통인 것은 아니다. 가상머신은 하드웨어의 추상화에서 출발한다. 하드웨어를 추상화하고, 그 위에 다시 OS를 올리고 그 위에서 내가 실행하고자 하는 application이 실행된다. 이런 과정은 필연적으로 너무 많은 리소스를 소모하게 된다. Docker의 경우, Host의 OS 위에 Docker가 올라가고, 그 위에 application을 실행하는 container가 올라간다. 이런 차이로 인해 Docker는 VM보다 비교적 가벼운 조건에서 환경 변수를 조절할 수 있게 된다.
그러나, 도커 또한 만능은 아니다. 사용하는 컨테이너가 점점 더 늘어나고, 더 세분화되면 관리자가 이를 효과적으로 조율하기란 여간 어려운 일이 아니게 된다. 또한, 일반적으로 Docker 데몬을 많이 이용하는데, 이를 위해서는 관리자 권한이 필요하다. 이런 문제로 보안과 관련하여 위험성이 존재할 수 있다. 또한, 가상 머신은 각각의 환경이 모두 분리되어 있어 이런 문제에서 더 안전하다.
미들웨어
미들웨어란, 간단하게 말해서 일종의 함수이다. Express.js에서는 모든 것이 미들웨어로 구현되어 있다고 한다. 로그를 찍어보기 위해서 이용하는 함수부터, json 형식의 데이터를 parsing해주는 함수 등에서 부터 내가 원하는 응답을 내려주는 라우터까지 모든 것을 미들웨어라고 부를 수 있는 것이다. Express.js를 활용하여 서버에서 요청을 처리할 때, Router 객체는 req, res, next로 대변되는 3개의 인자를 받는다. req는 들어온 요청을, res는 내려줄 응답을, 그리고 next는 다음 미들웨어를 호출하는 함수이다. 모든 미들웨어는 코드를 작성한 개발자가 의도한 대로 순서대로 req를 받아서 요청을 처리하고, next를 통해 다음 미들웨어를 호출하거나 최종 미들웨어에서 res에 응답을 처리하는 식으로 작동한다. 굳이 미들웨어와 라우터를 나누자면, 요청이 들어왔을 때 next 함수를 호출하여 다음 미들웨어 혹은 라우터로 요청을 넘기는 경우에는 미들웨어, 그렇지 않고 응답을 처리하는 경우에는 라우터라고 볼 수 있을 것 같다.
레이지 로딩과 이거 로딩
이 두가지 개념은 모두 table 사이의 관계가 정의될 수 있는 RDB에서 이용되는 것이다. Lazy Loading은 정말로 원할 때만 관련 데이터를 가져오는 기술을 말하고, eager Loading은 처음부터 더 큰 쿼리로 모든 것을 한 번에 가져오는 기술을 말한다. Lazy loading을 활용하는 경우, 이외의 데이터에 대한 쓰임이 없다면 데이터를 요청하지 않고, 필요하게 되면 그 때 요청하기 떄문에 메모리와 시간을 효과적으로 이용할 수 있다. Eager loading의 경우 Sequelize에서는 include 기능으로 대변되는 SQL의 join을 활용하여 DATA를 한번에 모두 불러오는 방식이다. 또한, include에서 required라는 변수를 줌으로 해당 값에 모델에서 값이 존재하는 경우에만 불러오는 inner join또한 활용할 수 있다.
이런 과정에서 SQL의 join을 이용하는데, join은 총 4가지 종류가 있다. Inner join, left outer join, right outer join, full outer join이 바로 그것들이다. 첫번째로 inner join은 마치 교집합과 같다. 관계가 설정된 테이블 들에서 값이 모두 존재하는 경우에만 값을 내려준다는 점에서 그러하다. Left outer join과 right outer join은 거의 흡사한데, left outer join에서는 왼쪽에 올 테이블의 값을 모두 불러오고, 오른쪽에 관계가 설정되어 있는 값을 불러오되 관계가 설정된 row가 없을 경우에는 null 값을 불러온다. Right outer join의 경우에는 오른쪽에 오는 table의 row를 모두 불러오고, 왼쪽에 table을 join하는데 이 때 연결된 row가 없는 경우 null 값을 불러온다. Full outer join은 마치 둘을 합쳐놓은 것 같다. 각 테이블의 모든 값을 불러오되, 관계가 설정된 row가 없으면 null 값을 불러온다.
N + 1 문제
간략하게 설명하면, 관계가 설정된 두개의 테이블이 존재할 때, 최초에 1번 쿼리를 이용하여 N개의 data를 불러온 후, 다른 table의 data가 필요하다면 각각의 data에 대해서 1번씩 쿼리를 이용하여 data를 조회해야 하는, 즉 총 N+1번 쿼리를 사용해야 하는 문제이다. 이를 해결하기 위해서는 join을 이용하여 1번의 쿼리를 이용해 필요한 데이터를 조회할 수 있다. 레이지 로딩을 통해 하나의 테이블에서만 데이터를 불러온 경우, 다른 테이블에 존재하는 값이 모두 필요하다면 N+1번 쿼리를 이용해야 하지만, 이거 로딩을 이용하면 join을 활용해 1번의 쿼리로 필요한 모든 data를 불러올 수 있고, Sequelize에서는 include를 통해 이를 구현할 수 있다. Include를 통해 불러오는 table에 또한 include를 활용하여 join된 형태를 사용할 수 있다.
출처 :
1. redhat > 토픽 > 리눅스 컨테이너의 이해 > 도커란?
https://www.redhat.com/ko/topics/containers/what-is-docker
Docker(도커)란? 도커 컨테이너 실행, 사용법, 다운로드, 배포
Docker(도커)란 Linux(리눅스) 컨테이너 생성 및 사용을 돕는 컨테이너 기술을 뜻합니다. Docker 사용법, Docker container(도커 컨테이너), 다운로드 방법을 설명합니다.
www.redhat.com
2. Sequelize v6 공식문서
Manual | Sequelize
Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Amazon Redshift and Snowflake’s Data Cloud. It features solid transaction support, relations, eager and lazy loading, read replication and more. Seq
sequelize.org
3. 티스토리 꿈을 항하여 질주하기
https://sparkdia.tistory.com/17
테이블 조인 종류(Table Join Type)
데이터베이스에서 데이터는 다수의 테이블에 나뉘어 저장되어 있습니다. 데이터의 중복을 제거하고 무결성을 보장하기 위해서 데이터 성격에 따라 분류하여 테이블에 저장을 하는 겁니다. 이
sparkdia.tistory.com
4. 제타위키 - N+1 쿼리 문제
https://zetawiki.com/wiki/N%2B1_%EC%BF%BC%EB%A6%AC_%EB%AC%B8%EC%A0%9C
'항해 99' 카테고리의 다른 글
항해 99 9주차를 끝내며 (0) | 2022.03.15 |
---|---|
항해 99 8주차를 끝내며 (0) | 2022.03.07 |
항해 99 6주차를 끝내며 (0) | 2022.02.20 |
항해 99 5주차를 끝내며 (0) | 2022.02.14 |
항해 99 4주차를 끝내며 (0) | 2022.02.06 |