최근 Dynamo 논문을 읽어보면서 흥미로운 개념을 발견했다.
대부분의 DB의 경우 last writes wins라는 전략을 택한다고 한다. 간단하게 말하자면 마지막에 쓴 자가 기존 데이터를 덮어씌우는 방식이다. 동시 쓰기의 문제를 심플하게 나중에 쓴 사람 걸 채택하는 방식으로 해결한다는 것이다. 이렇게 하는 이유는 개발자의 편의에 있기도 하고, (개발자들은 본인의 client단에 복잡한 충돌 처리 로직을 작성하는 걸 싫어한다고 한다) 단순하게 그 방법이 가장 간단하기 때문이라고도 한다.
그런데 Dynamo 논문에서는 DynamoDB의 경우 last writes wins가 아니라 애플리케이션에서 해당 충돌에 대한 권한을 가질 수 있도록 만들었다고 한다. 즉 애플리케이션 단의 로직으로 해당 충돌 문제를 해결할 수 있도록 했다는 것이다.
위 맥락을 읽고서 그렇다면 어떻게 실제로 이걸 구현해서 사용할 수 있을지에 대해 궁금했었다.
최근 위 고민에 대한 해답을 얻게 되었다. 바로 DynamoDB versioning이다.
실제 DB entity 필드에 versioning과 관련된 필드를 들고 있고, write를 할 때 마다 해당 versioning 필드가 증가한다. 그렇다면 동일한 item을 쓰려는 시도에 있어서 이미 있던 versioning이 증가한 상태에서 쓰려는 누군가는 write에 실패한다.
이런 방식을 Optimistic Locking이라고 한다. 낙관적 잠금 전략이라고 한다.
애플리케이션에서 Item을 가져오는데, 이때 가져온 Item이 지금 쓰려고 하는 그 순간 DynamoDB에 있던 해당 Item의 version값과 같지 않다면 누군가가 이미 해당 Item을 Update했다는 뜻이기 때문에 write는 실패한다. 잘못 덮어쓰는 걸 막아주는 셈이다.
이 방법을 쓰려면
@DynamoDBVersionAttribute
이 어노테이션을 사용하면 된다.
이 경우 처음으로 객체를 저장할때 DynamoDBMapper가 버전 번호를 할당하고 (처음엔 1로 할당) 이후의 write 마다 해당 번호가 오른다고 한다.
참고로 이 Optimistic Locking은 사용하지 않을 수도 있는 옵션이다.
코드 예시를 보자면 아래처럼 사용할 수 있겠다.
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBVersionAttribute
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable
@DynamoDBTable(tableName = "YourTableName")
data class YourDataClass(
@DynamoDBHashKey(attributeName = "Id")
var id: String,
@DynamoDBVersionAttribute(attributeName = "Version")
var version: Long? = null // 초기값을 null로 설정하여 DynamoDB가 버전 관리를 시작하게 함
// 클래스의 다른 속성들...
)
참 영리한 방식이라는 생각이 들었다.
DynamoDB는 Avaliability를 위해서 consistency를 많이 희생했다. replica 3개 중 2개에서만 write success응답을 받고 난 다음 바로 write가 성공했다는 응답을 client에게 주는 것도 DynamoDB가 DB 사이즈와 상관없이 언제나 일관된 응답 시간을 보장하기 위해 99.9%에 달하는 아주 높은 Avalilability를 얻기 위해 사용하는 방식이다. 대신 consistency가 RDB만큼이나 보장되지 않는다. RDB는 아예 consistent하지 않다면 DB자체를 available하지 못하게 만든다. 일관되지 않은 데이터에 접근 자체를 불가능하게 만드는 것이다. 반면 DynamoDB는 write를 하다가 곧장 get을 하면 전혀 다른 값을 얻을 가능성이 존재한다.
하지만 RDB와 NoSQL의 두 가지 장점을 적절한 선에서 어느정도 가져갈 수 있다면?
오늘 다루는 주제가 그 두 가지 장점을 모두 가질 수 있는 방법이라고 생각한다.
기본적으로 DynamoDB가 가지는 managed라는 편리한 서비스라는 점, 제공하는 스케일링과 아주 간단하게 사용할 수 있는 방법인 key, value 접근, 그리고 DB사이즈와 상관없이 언제나 일관된 응답 시간 등 이 모든 managed NoSQL서비스로서의 장점을 가지면서도 손해보게 될 consistency를 versioning을 통해서 조금이나마 향상시킨다면 적절한 선택지가 될 수 있겠다는 생각이 들었다.즉 쓸만한 수준이 되는 것이다. 그것도 아주 괜찮은 솔루션으로써 말이다.
개인적인 생각
최근 DynamoDB를 살펴보면서 매우 신기한 기술적 개념을 많이 접하게 되었다.
정말 재밌는 시간이었고, NoSQL의 가능성에 대해서 알게 되었다. 정말 DynamoDB는 알 수록 재밌는 점이 많다.
현대의 애플리케이션에게는 확장이 용이하고, 애플리케이션에 최적화된 설계를 할 수 있는 DB서비스로써의 NoSQL이 굉장히 매력적인 솔루션이 될 수 있겠다는 생각을 하게 되었다. 정규화를 스스로 부수는 디자인을 미리 해둔다거나, 아니면 ACID원칙을 어기는 자유로움은 변화가 빠르고 또한 스스로도 빨리 변화해야만 하는 현대 애플리케이션에 가장 적합하다는 생각이 든다.
비단 DynamoDB 뿐 아니라 다양한 NoSQL솔루션이 있는 것으로 알고 있다. 다음번에는 어떤 솔루션을 알아볼 지 살펴보는 중이다. 다만 내게 도움이 될 만한 솔루션을 찾고 있다.
개인적으로 DynamoDB의 경우 확장에는 유연하지만 막상 테이블의 디자인에 대해서는 유연하기 보다는 처음에 유연함까지 고려한 설계를 해둬야지만 충분히 쓸 수준이 된다고 생각한다. 그래서인지 첫 디자인을 잘못하게 되면 이후 리스크가 크기 때문에 (설계를 잘못하면 아예 조회할 수 없는 허점이 있다) 설계의 중요성이 크다.
물론 GSI를 활용해서 어떻게든 사용할 수 있겠지만 그렇게 쓰려면 뭔가 잘못되어간다는 느낌이 든다. 귀찮으니까 일종의 GOTO같은 쇼트컷을 자꾸 추가하는 땜질같은 해결책이라고 생각된다.
하지만 애플리케이션에 딱 붙여서 최적화된 접근 패턴을 DB 설계에 녹여서 우리가 쓰고자 하는 영역에만 딱 맞게 쓸 수 있는 정말 괜찮은 솔루션이라는 생각이 든다.
더 나은 무언가
설계를 어떤 식으로 망쳐놔도 자유롭게 쓸 수 있는, 형태에 얽매이지 않으면서도 성능이 일관된 DB는 없을까라는 상상을 했다. CPU보다 Disk가 더 비쌌기 때문에 최대한 중복을 방지하는 구조를 갖고자 했던 RDB가 있었다면 이제는 오히려 Disk가 값싸졌고 CPU 리소스가 더 비싸졌기 때문에 중복이 있더라도 애플리케이션의 액세스 패턴에 맞춰서 설계하는 DynamoDB가 존재한다. 여기서 Disk가 앞으로 더욱 기하급수적으로 값싸진다면 엄청난 중복이 있더라도 상당한 수준의 자유로움을 허용하는 새로운 형태의 DB는 존재할 수 없는 것인가?
자세한 내용은 아래 doc을 참고하면 좋다.
좋은 자료 제공에 감사합니다.
https://serverlessland.com/content/service/dynamodb/guides/knowledge-portal/howdoi_2
'Cloud > AWS' 카테고리의 다른 글
[AWS] Dynamo: Amazon’s Highly Available Key-value Store (0) | 2023.11.10 |
---|---|
[AWS] AWS EBS에 대한 이해 (0) | 2023.10.27 |
[AWS] DynamoDB 제대로 알고 사용하기 (0) | 2023.05.06 |
[AWS] EC2를 사용하지 않을 경우 Elastic Ip / 탄력적 ip에서 과금 발생 (0) | 2022.04.08 |
[AWS] AWS ec2 putty 연결 (0) | 2022.03.18 |