[Spring boot] JPA PK 매핑 전략, Auto Increment Key와 UUID 선택의 기준

Byuk_mm·2022년 9월 23일
7

Spring Boot Development

목록 보기
9/13
post-thumbnail

Spring Boot 개발 중 학습이 필요한 내용을 정리하고,
트러블 슈팅 과정을 기록하는 포스팅입니다.




✅ Background

지금까지 Spring bootJPA를 사용하면서, EntitiyPK(Primary Key)는 JPA에서 제공하는 GenerationType.IDENTITY 방식을 활용했습니다. 해당 방식은 기본 키 생성을 데이터베이스에 위임하는 방식입니다. 즉, id 값을 null로 하면 DB가 알아서 AUTO_INCREMENT 속성을 적용시켜서 DB에서 생성해주는 방식입니다.

위 방식을 사용하면서 저는 항상 이 방식이 보안적으로 안전한 것이 맞는지에 대한 의문을 품고 있었습니다. EntityPKAUTO_INCREMENT로 들어가게 된다면, 단순히 정수 형식으로 들어가게 된다는 말이고, 클라이언트에서 EntityPK를 클라이언트 사이드의 스토리지쿠키 등에 저장하고 활용할 때 보안적으로 안전하다는 것을 보장하는지에 대한 의문이었습니다.

때문에 프로젝트를 진행하면서 다른 PK 매핑 전략에 대해서 공부해봤고, UUID 방식을 알게 됐습니다. 이번 포스팅에서는 제가 각 EntityPK 매핑 전략을 선택할 때 어떠한 기준을 가지고 선택하게 됐는지에 대해서 적어봤습니다!




✅ Auto Increment Key

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "video_id", updatable = false)
private Long id;

위 코드는 JPAGeneratedValue 애노테이션을 활용해서 Auto Increment Key 방식의 PK 매핑 전략을 적용한 코드입니다.

앞서 말했듯 해당 방식은 DBPK 생성을 위임하며, DB에서 Big_Int 형식의 PK를 자동으로 생성해서 적용시켜 줍니다. 해당 방식은 JPA를 활용할 때, 기본적으로 활용하는 PK 매핑 방식입니다. JPA에서는 위 코드와 같이 ID 애노테이션과 함께 GeneratedValue 애노테이션의 strategyGenerationType.IDENTITY로 설정할 경우 Auto Increment Key 매핑 방식을 사용하게 됩니다.

Auto Increment Key 방식의 장점은 명확합니다.
개발하기 매우 간단하며 DB 자체의 Auto Increment 로직을 활용하기 때문에 성능 면에서 UUID 방식보다 뛰어납니다. 또한 Bi_Int 타입으로 PK가 정의되기 때문에 DB의 용량 측면에서도 장점이 있습니다.

하지만, Auto Increment Key 방식은 단점 또한 명확하다고 생각됩니다.
PK가 1씩 증가하는 형식이기 때문에 특정 테이블의 PK를 유추하기 쉬워지며 이를 통해 테이블의 행의 갯수 또한 유추할수 있습니다. 이는 즉 악의적인 공격에 취약할 수 밖에 없다는 것입니다. 또한 생성되는 PK가 전체 DB에서 유일한 PK임을 보장하지는 않습니다.




✅ UUID


@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name="uuid2", strategy = "uuid2")
@Column(name = "individual_video_id", columnDefinition = "BINARY(16)")
private UUID id;

위 코드는 UUID 방식의 PK 매핑 전략을 적용한 코드입니다. UUID는 16진수로 구성된 128비트의 값입니다. 랜덤으로 생성된 UUID가 충돌을 일으킬 확률은 10억분의 1 확률로 매우 낮기 때문에 상당히 안전한 값이라고 볼 수 있습니다.

이러한 UUID는 앞서 나온 Auto Increment Key 방식의 문제점을 해결합니다. UUID는 값 자체로만 보면 특정 의미를 갖지 않는 값이기 때문에 UUID를 통해 다른 특성을 유추하거나 악의적인 활용을 방지합니다.
또한 전체 DB에서 유일한 PK를 보장합니다. 해당 부분만 보면 UUID 방식의 PK 매핑 전략을 반드시 채택해야할 것만 같습니다. 하지만 이에 상응하는 단점들 또한 존재합니다.

가장 큰 단점은 DB의 성능 저하 이슈가 있을 수 있다는 것입니다.

The main disadvantage of UUID is a performance in relation databases. In the database like MSSQL, MySQL or Oracle primary keys can have some performance issues. The main problem is inserting to database. If we have clustered primary key in our database, the SQL engine has to do some reordering rows while inserting new rows. So this can be an issue if the table contains a large number of rows. This issue can be lowered by sequential guid(for example in MSSQL ) 출처

위 글을 정리해보자면 다량의 rowinsert할 때, SQL enginePK를 기준으로 테이블의 row를 계속해서 reoderning 합니다. 이 과정에서 상대적으로 크고 복잡한 값을 갖는 UUIDPK는 성능적인 저하가 발생할 수 밖에 없습니다. 또한 Storage 측면에서도 UUIDAuto Increment Key 방식보다 대략 4배 정도 더 큰 공간을 차지하게 됩니다.

즉 성능과 용량면에서 UUID는 큰 단점이 존재합니다.




✅ Auto Increment Key와 UUID, 선택의 기준.


결론적으로 두 방식 중 어떠한 방식의 PK 매핑 전략을 선택할 것인지는 Entity의 성격과 각각 매핑 전략의 장단점을 기준으로 선택해야합니다.

무작정 UUID 방식의 보안적 안정성만 보고 UUID 방식을 선택하기에는 DB의 성능과 용량 저하 이슈는 분명 큰 이슈입니다.
무작정 Auto Increment Key 방식의 편리함과 성능을 보고 Auto Increment Key 방식을 선택하기에는 분명 PK를 감춰야할 Entity가 존재합니다.

저는 아래의 두 경우를 제외하고는 모든 EntityAuto Increment Key 방식의 PK 매핑 전략을 Entity에 적용했습니다.

1. 클라이언트 사이드에서 확인이 가능한 PK인 경우.
https://www.youtube.com/watch?v=clFP_6pW_Y0
위 링크는 유튜브에서 한 영상의 주소입니다. 보시다시피 위의 URL 쿼리에 특정 UUID가 활용된 것을 볼 수 있습니다. 이렇듯 클라이언트 사이드에서 직접적인 파악과 활용이 가능한 EntitiyPKUUID 방식을 활용하여 사용자로 하여금 테이블의 특성을 감추고 악의적인 공격을 예방합니다.

2. 클라이언트 사이드에서 고유키, 식별자의 역할을 해야할 경우.
쿠폰의 코드 값과 같이 PK가 유추하기 어렵고 고유한 값을 가져야하는 경우 UUID 방식을 활용합니다.

지금까지는 아무 생각없이 무조건 Auto Increment Key 방식을 적용시켜왔으나, Entity의 특성을 기준으로 PK 매핑 전략을 선택함으로써 보안적으로 안전하며 성능에 대한 고려까지한 Entity 설계가 가능했습니다.




✅ 참고

https://mareks-082.medium.com/auto-increment-keys-vs-uuid-a74d81f7476a

https://davidyang2149.dev/front-end/uuid-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C/

https://ssunw.tistory.com/entry/14-PK-%EB%A5%BC-auto-increment%EC%9E%90%EB%8F%99-%EC%A6%9D%EA%B0%80-%ED%95%A0-%EA%B2%BD%EC%9A%B0-%EC%83%9D%EA%B8%B0%EB%8A%94-%EB%AC%B8%EC%A0%9C%EC%A0%90

profile
어디야 벽벽 / 블로그 이전 -> byuk.dev

4개의 댓글

comment-user-thumbnail
2022년 12월 25일

jpa에 pk를 위임하고 그 pk를 서비스단에서 유의미한 값으로 uri path라던가...그렇게 사용하는게 정말 좋을까 의문이 들긴하네요. 개발용 db랑 운영 db랑 같은 데이터라도 pk가 달라진다면 이슈 해결하기 어려울 것 같아요. 그런 관점에선 어떨까요

1개의 답글
comment-user-thumbnail
2024년 4월 23일

유튜브 URL 예제 같은 경우 pk가 노출되는게 아니라 url 단축키 전략이 사용된 것 아닌가요?

답글 달기