원래 DB하다가 DE로 넘어왔고

개발자만 있던 회사고 인프라테크는 내 팀이 처음으로 구성된 팀이었음

난 개발하러 왔는데 코꿰여서 울며 겨자먹기로 탈출한 인프라 다시 함 ....


기존 개발자들은 Psql을 많이 썼는데

나도 몇번 건드려보니 개발자들이 좋아할 만한 기능은 꽤 많음

DB현업때 Psql 느낌은 C 함수 매핑 가능한 커스터마이징 디비 느낌이었는데

요즘은 쪼오금 다르더라.


어쨌거나 고객사에 그게 들어가 있었는데

인프라 관리가 이쪽으로 넘어(짬맞음씨발)오다 보니 관리를 해야하는데

Dead tuple 문제가 계속해서 발목을 처 잡음


난 단순히 empty node나 세그먼트 해제 등 데이터 마이그레이션이나 세그먼트 삭제 등 하면 해결 날 이슈일 줄 알았는데

이새끼가 생각보다 문제가 큼..

그리고 '해결할 수 있는 문제가 아님'

서비스하는 내내 영원히 너의 발목을 잡을 수 있음


그래서 지금은 psql 다 빼자고 하고 올전환함.

개발자들이 잘쓰면 문제가없다 ㅎㅎ 하지만 그렇지않다는건 개발자들도 잘알고있음.


참고:

https://www.cs.cmu.edu/~pavlo/blog/2023/04/the-part-of-postgresql-we-hate-the-most.html

The Part of PostgreSQL We Hate the Most // Blog // Andy Pavlo - Carnegie Mellon UniversityAs much as Andy loves PostgreSQL, there is one part that is terrible and causes many headaches for people. Learn what it is and why it sucks.www.cs.cmu.edu


20abd325abc236a14e81d2b628f172695aecc6

(MVCC)


MVCC의 자세한 작동 구조에 대해서는 알아서 알아 보고

어쨌거나 이 MVCC 1황은 오라클인데

MVCC의 기본 개념은 '스냅샷'임.


이 스냅샷을 오라클은 undo 공간을 두는 것으로 해결했고

멀티 버전 컨커런시 머시기라고 하는 만큼 트랜잭션 시점 관리를 위해 필요함

isolation level이니 뭐니 알지? 사실 난 네개 읊으라고 하면 못 읊음 ㅎ


기본적으로 이 undo의 스냅샷은 DB 내부 시간으로 관리되는데 이것이 오라클에서는 LSN으로 대표되고 뭐..마리아디비는 TID인가? 뭐 그런거 있더라

그 내부 시간 단위로 관리되고 dml transaction이 발생하면 그 트랜잭션이 해소될 때까지 해당 트랜잭션에 해당하는 LSN 버전의 데이터를 undo에 저장해 놓는다.

그리고 그건 linked list로 관리되고, 이것도 순서가 오라클하고 Psql하고 다른데 뭐 이건 참고사이트 본문에 적혀 있음.

쉽게 말해서 오라클은 '가장 첫 node가 최신 데이터' psql은 '가장 마지막 node가 최신 데이터임'

일단 여기서부터 좀 병신같은 점이 보이지?


여기서 파생되는 모든 mvcc 기반의 DBMS에서 문제점은

1. 트랜잭션 해소 안되면 undo는 계속 쌓이게 될 것이다(해당 버전 이후에는 transaction log를 undo에 반드시 기록해야 한다. 가지고 있어야되니까)

2. undo가 계속 쌓이면 linked list의 순회 코스트가 발생한다


즉 트랜잭션이 해소되지 않으면 디스크(메모리), 성능 압력이 추가로 발생하게 된다는 뜻임.


근데 Psql은 오라클과 반대 순서대로 리스트를 만들어서 '가장 마지막 node가 최신 데이터임' 느릴 수밖에 없다. 다순회해야됨.

솔직히 이거 순회비용이 아주 많이 들진 않을것 같다는 생각인게 transaction lock때문에 데이터가 끝없이 밀리는 경우가 흔치 않고 이건 사용자 문제라고 넘어갈 수 있거든. 아마 존나존나 옛날엔 성능이 느리니까 이걸 해결해야 된다고 생각했을 수도 있어.

문제는 Psql이 '고작' 이걸 해결하기 위해서 최악의 악수를 둬버림


응 그럼 모든 데이터 version을 걍 인덱스에 때려처넣어보자~

라는 미친 발상을 해 버린것임...


3bb8c235ecdd36af60b898a518d60403f8ac6418969bbae5cd

(몬가..몬가 엄청난 일이 일어나버림..)


여기서 파생되는 문제


1. 자원 활용도가 개병신같아짐

2. index 순회 코스트가 늘어남


3. 트랜잭션 끝나고 안 쓰는 구버전 노드 데이터가 인덱스에 떡하니 붙어있음

그리고 이것이 Dead Tuple임.


DBMS의 모든 데이터는 기본적으로 세그먼트, 블록, 페이지로 어느 정도 계획되어 관리됨.

그렇기 때문에 사용하지 않는 공간이 있다고 '반환하지 않음'

내부적으로 aging하는 것들이 있고 이것이 주기적으로 돌면서 정리하는데

이것도 정리 안되는 것들이 있고 이부분은 사용자들이 충분히 인지하고 있어야함. 대부분은 DBA가 알고 있으니까 개발자한테 시어머니질을 한다.


대표적으로, delete dml 연산으로 지운 데이터들은 세그먼트가 바로 반환되지 않는다.

어떤 DB는 반환할 수 없는 경우도 있음. Truncate 해야 반환된다.

애초에 세그먼트를 재구성 하기 때문에, 기능이 있다고 해도 운영관리측면에서도 리스크가 커서 함부로 막 날릴 수 없다.



29b8d122a5c62db662ba98a518d6040391b62f96d5362a14de


아까 얘기한 Psql에서의 dead tuple 문제는 굉장히 치명적인데, dead tuple을 정리해주는 vacuum이라는 개념이 있으나 이것이 dead tuple을 완벽히 정리해주지 못한다.

dead tuple은 DB의 성능 비율에서 가장 높은 비중인 인덱스의 순회 코스트를 늘리는 행위이기 때문에, 이것이 엄청난 악영향을 불러옴.

dead tuple로 인해 성능이 느려지면, 트랜잭션 수행 시간도 늘어나게 되고, 다시 dead tuple이 더 많이 늘어나는 부정적 피드백으로 돌아온다.

그리고 느려지면 또 vacuum이 더 안된다! 인덱스 물고 있는놈이 많아지면 또 해제 못하고 주기적으로 다시 돌면서가능할 때만 vacuum된다. 그 예시가 위의 그래프임.

autovacuum은 저 사이에 수백번은 족히 돌았지만, 실제로 수행된 건 얼마 안됨.


그리고 그 결과는 데이터 폭발로 인한 디스크 부족, 그리고 운영 장애로 이어지게 되는것임.

참고로, 이건 파일 세그먼트를 다 붙잡고 있는 문제라서

'다시 껐다 켠다고 해결되지 않는다'


디스크 풀로 인한 데드 튜플은 해제도 잘 안되더라.

논리 마이그레이션으로 해결하는 수밖에 없다. 그리고 그건 매우 족같은 업무 중 하나임.



지금 보면 이런 개멍청한 찐빠구조를 왜 만들었나 싶을 수도 있을 건데

Psql 만들어진 시기 보면 나름대로 그 시기 최선의 구조로 만들어서 이론상 성능은 빠를 수 밖에 없었다

근데 그 성능 확보하자고 하는 일이

영원히 Psql의 발목을 붙잡을 약점이 됐으니

소프트웨어 설계라는것이 장기적인 안목에서 생각하기는 참 어렵구나 하는 생각이 들 때가 있다


근데 그래서 난 안써 ㅋㅋ