개발공부, 프로젝트한거 정리하는 블로그
전체
Java/Spring
CS
프로젝트
Table
Search
Exposed란
공식 깃허브의 소개글이다.
Exposed is a lightweight SQL library on top of a JDBC driver for the Kotlin language. Exposed has two flavors of database access: typesafe SQL wrapping DSL and lightweight Data Access Objects (DAO).
With Exposed, you have two options for database access: wrapping DSL and a lightweight DAO. Our official mascot is the cuttlefish, which is well-known for its outstanding mimicry ability that enables it to blend seamlessly into any environment. Similar to our mascot, Exposed can be used to mimic a variety of database engines, which helps you to build applications without dependencies on any specific database engine and to switch between them with very little or no changes.
왜 JPA 냅두고 Exposed를 쓰나?
JPA는 영속성 컨텍스트와 1차 캐시, 변경 감지 등의 기능을 제공해준다. 이는 분명 편리한 기능이긴 하지만, 반드시 필요한 기능은 아니다. 또한, 이런 기능을 제공하기 위해 JPA와 Hibernate의 구조가 크고 복잡해 이해하기 힘들다.
또한, JPA와 코틀린의 궁합이 썩 좋지 않은 것도 문제다. JPA는 말 그대로 자바를 위한 것이기 때문에, 코틀린 환경에서 이를 사용할 때 문제가 발생하기도 한다. 당장 관련 키워드로 검색해 보면 사례가 많이 나온다. 물론, 대부분의 사례는 이미 명확한 해결법이 존재하기 때문에 문제가 되지 않을 수 있다. 그러나 모든 코드를 코틀린으로 작성한다면, 처음부터 코틀린을 위한 프레임워크를 사용하는 것도 합리적이라 생각한다.
DSL 방식 사용법
Exposed를 사용하는 방식은 공식적으로 DAO 방식과 DSL 방식이 있다. DAO 방식은 Spring Data JPA의 Repository와, DSL 방식은 QueryDSL 과 비슷한 사용 방식을 보여준다. 두 사용법 모두 명시적으로 커넥션을 얻고, 트랜잭션을 시작하는 API를 호출해야한다.
현업의 테이블 구조는 토이프로젝트와는 차원이 다르게 복잡하다. 따라서, 복잡한 쿼리가 필요하고, 이는 DSL 방식을 사용하는 압력으로 작용한다. 그래서, DSL 방식의 사용법을 익혀봤다.
DSL 방식으로 Exposed를 사용하기 위해서 필요한 클래스는 2종류다. 하나는 데이터를 담을 대상인 DTO이고, 다른 하나는 테이블을 표현하는 클래스다. 즉, JPA에서는 @Entitiy 어노테이션을 붙인 클래스가 데이터를 담을 대상이면서 테이블을 표현하는 클래스였지만, Exposed의 DSL 방식에서는 두 역할이 분리되어있다.
Exposed - 코틀린 SQL 프레임워크
2024/12/21
Kotlin
DB
작성 완료
생각하게 된 계기
우아한테크코스 교육과정에서 “데벨업”이란 이름의 개발자 취준생 커뮤니티 제작 프로젝트를 진행하고 있다. 프로젝트 진행 과정에서 개발 서버와 운영 서버를 분리하게 되었다. 따라서, 두 서버에 다른 이미지로 만들어진 컨테이너가 동작하게 된다. 만약, 이미지 관리를 하나의 레지스트리에서 한다면, 각 서버에서 어떤 이미지를 pull 받아야 하는지 결정하는 과정이 CD 에 추가되어야 한다. 복잡한 작업이 될것이라 예상되어 개발용 레지스트리와 운영용 레지스트리를 분리하는 방법을 찾게 되었다.
상용 서비스 vs 직접 운영
기본적인 레지스트리인 도커 허브에선 무료 플랜에선 프라이빗 레지스트리를 하나만 제공한다. 또 다른 서비스인 깃허브 패키지 역시 무료 플랜에선 용량과 트래픽 제한이 있다. 다른 상용 서비스들도 여럿 있지만, 프라이빗 레지스트리를 위해선 돈을 지불해야 한다. 반면, 직접 운영하는 경우 서버 임대 비용을 제외하면 별도의 비용이 발생하지 않는다. 따라서, 직접 레지스트리를 운영하는 방법에 대해 학습할 가치가 있다고 판단했다.
구축 과정

최종적으로 구현된 자체 레지스트리 웹페이지
위와 같은 레지스트리 웹페이지를 만든 과정을 소개한다.
레지스트리 컨테이너 띄우기
compose.yml
레지스트리에 https 적용하기
도커에서 레지스트리가 https 적용이 되어있지 않은 경우 거부하는 것이 기본 설정이다. 예외 설정을 할 수 있지만, 레지스트리를 따로 운영하는 이유가 보안 때문이므로 앞뒤가 맞지 않는다. 따라서 https 를 적용해야 한다고 생각했다.
레지스트리에 https를 적용하는 방법도 있다. 하지만, 추후 웹 UI 도 붙일 것이고 이 곳에도 https 를 적용해야 하는 것이 자명했다. 따라서 https 적용하는 것을 분리하여 nginx를 추가하고 리버스 프록시와 https 를 적용하는 것이 나을 것이라 판단했다. 아래는 이에 따라 변경된 compose.yml 이다.
compose.yml
도커 레지스트리 직접 운영하기
2024/08/18
Docker
보안
운영
작성 완료
의존
어떤 요소 A가 동작하기 위해서 다른 요소 B가 필요하다면, A가 B를 의존한다.
Ladder가 동작하기 위해서는 List<Line> 이 필요하다. 즉, Laddder는 List와 Line을 의존한다.
정말 간단하게 자바에서 import 하는 모든 것을 의존한다고 보면 된다. 단, 그게 전부는 아니다.
이하의 글에서 A 를 의존을 하는 쪽, B를 의존 대상 이라 표현한다.
주입
주입의 사전적 의미는 다음과 같다.
어떤 물체 안에 액체나 기체 따위를 집어넣음.
- 네이버 국어사전
어떤 대상의 외부에서, 내부로 무언가를 집어 넣는 것!
의존성 주입
의존을 하는 것이 의존 대상이 되는 것을 직접 만들지 않고, 외부에서 의존 대상을 집어 넣는 것!

조금 더 쉬운 이해를 위해 코드로 살펴 보자
의존성 주입
2024/03/23
우테코
프로그래밍 일반
Java
작성 완료
시스템 요구사항
생각의 흐름
인증 토큰? JWT? 세션?

그림 1. 기본적인 인증 구조
처음 생각한 인증 구조는 위와 같았다. REST API로 로그인을 하면 일종의 인증 토큰이 발급되고 이를 인증이 필요한 API 요청을 할 때마다 헤더에 실어 보내는 구조다. 일반적인 상황이라면 JWT 를 사용하면 간단하지만, 이 조건을 충족하려면 인증 정보를 어떤 방식으로든 서버에 저장해야 했다. 그래야 기존의 인증 토큰으로 인증을 시도할 때 거부할 수 있기 때문이다. 이를 위한 가장 간단한 방법은 전통적인 세션을 사용하는 방식이다.
그런데, 두 API서버가 WAS 단위로 분리되어있기 때문에 같은 세션을 사용하기 위해서는 추가 설정이 필요하다.
분산 환경에서 세션 문제 해결하는 방법
여러 서버가 같은 세션을 가져야 하는 상황이 분산 환경에서 많이 발생할 것이라 생각하여 분산 환경에서 세션 문제를 어떻게 처리하는지 알아보았다.
분산 환경에서 위와 같은 세션 문제를 해결하기 위한 방법으로 Sticky Session 과 Session Clustering 을 들 수 있다. 전자의 경우 세션아이디를 이용해 로드밸런싱을 하는 것으로, 모든 요청이 하나의 서버로 전달되는 것을 보장하기 때문에 분산 서버들끼리 같은 세션을 공유할 필요가 없다. 후자의 경우 세션 정보를 공유하는 방식으로 세션을 생성할 때 분산 서버들에 모두 동일한 세션을 생성하거나, 하나의 공통된 세션 저장소를 공유하는 방식이다. 우리가 해결해야 하는 상황과 비슷한 것이 Session Clustering 이다. 자세히 알아볼 필요가 있었다.
Session Clustering
기본적으로 여러 서버가 같은 세션을 공유하는 가장 간단한 방법은 중앙화된 세션 저장소를 만들고 모든 서버가 이 중앙 세션 저장소에 접근하여 세션 정보를 확인하는 것이다. 이 방법은 모든 트래픽이 결국 중앙의 세션 저장소에 집중되므로 세션 저장소의 부하가 문제가 될 수 있다.
다른 방법으로는 각각의 서버가 독립된 세션 저장소를 가지되, 세션 정보의 추가, 변경, 삭제가 발생하였을때 일종의 이벤트가 발생하게 하고 각각의 서버(혹은 세션 저장소)가 이 이벤트를 처리해 반영하는 방법이 있다. 부하가 분산된다는 장점이 있겠지만 당연히 구현이 쉽지 않을 것이다.
서비스 초기에 트래픽이 많을리 없으니 일단 중앙의 세션 저장소를 두는 방식을 선택했다.
Redis 를 이용한 인증 시스템 구축
2023/07/15
아키텍처
보안
작성 완료
Logging 작업을 정리한 계기
지금 진행하고 있는 골키퍼 버전2 프로젝트를 개발하면서 구글 로그인 기능을 처음 구현했다. 처음 하는 거다보니 예상하지 못한 오류들이 많이 발생했고, 브레이크 포인트를 걸면서 확인해가기에는 오류가 너무 많았다. 그래서 Logging 작업을 철저히 해놓고 다시 오류를 고쳐나가기로 했다.
오류가 났는지 정확히 확인하기 위해서는 http 요청, 비즈니스 로직을 타면서 호출되는 Spring Bean, http 응답 정보를 기록해야 한다고 판단했다.
Logging 이란?
본론에 들어가기 전에, Logging이 뭔지부터 정의하고 넘어가보자. 요즘 핫한 ai 에게 Logging 이 뭐냐고 물어보면 이렇게 대답해준다.
Logging is the process of recording events or information in a computer system for the purpose of analysis, tracking, and debugging. It allows developers to monitor the behavior of their software, understand and diagnose issues, and gain insights into how it's being used. Logs can also be used for auditing, performance analysis, and security purposes.
-Chat GPT
한국말로 번역하면, “컴퓨터 시스템에서 발생하는 각종 이벤트나 정보들을 기록하는 작업으로 분석, 추적, 디버깅을 그 목적으로 한다.” 라고 번역할 수 있다.
Spring Boot 에서 Logging
Spring Boot, 정확히는 implementation 'org.springframework.boot:spring-boot-starter-web' 을 적용한 Spring MVC 웹 시스템에서 로그를 남길때 사용할 만한 기술들은 4가지 정도가 있다.
Filter
자바로 웹 개발을 할 때 사용되는 원천기술인 Servlet 스택에 포함된 요소이다. Servlet 컨테이너가 요청을 올바른 Servlet에 전달해 주기 전에, Filter를 거치게 된다. 그림으로 표현하면, 이런 식이다.

Spring Boot에서 Filter 의 동작 위치
즉, Spring 컨테이너와 무관한 내용들(http 요청)을 로그로 남기기에 적당한 위치라고 볼 수 있다.
Interceptor
Spring MVC Framework 에서 제공하는 기술로, 컨트롤러 실행 전후에 특정 작업을 추가할 수 있도록 하는 구성 요소이다. 다수의 컨트롤러에 대해 동일한 기능을 적용해야 할 때 사용할 수 있는 것이다. 그림으로 표현하면
Spring Boot REST API System Logging
2023/01/31
Spring
인덱스란?
DB의 테이블의 동작속도를 향상시키기 위해 DBMS 내부에서 사용하는 자료구조. 책의 목차나 색인과 같은 역할을 한다.

인덱스 이미지 출처 : https://mangkyu.tistory.com/96
테이블의 각 row 들은 별도로 정렬되어있지 않고 아무렇게나 삽입되어 있다. 따라서, 테이블에 특정 행을 조회하는 경우 테이블 전체를 탐색하는 FULL-SCAN 이 발생하게 된다.
테이블의 특정 컬럼에 인덱스를 생성하면, 인덱스 테이블이 생성되는데, 이 인덱스 테이블은 key-value 형태를 가진다. 이때 key 는 인덱스를 설정한 컬럼의 데이터가 되고, value 는 원본 테이블의 각 row 를 가리키는 pointer 가 된다. 중요한 점은, 인덱스 테이블은 정렬되어있다는 점이다. 따라서, 인덱스를 사용하면 FULL-SCAN 이 발생하지 않고 인덱스를 이용해 빠르게 검색할 수 있게 됩니다.
인덱스를 사용할때의 장점
•
검색이 빨라진다.
인덱스를 사용할 때의 단점
•
용량이 증가한다.
•
잘못된 인덱스 사용은 오히려 성능의 감소를 불러오게 된다.
인덱스를 설정할때 고려해야 할 점
1.
쿼리를 더 효율적으로 작성할 방법은 없는지 생각한다.
2.
해당 테이블이 조회가 자주 발생하고, 변경은 적게 발생하는 테이블인지 확인 한다.
3.
Cardinality 가 높은 컬럼에 인덱스를 걸어준다.
DBMS 가 인덱스를 구현할 때 사용하는 자료구조
[데이터베이스] DB 인덱스
2022/12/22
CS
DB
Load more
독서록
Search