최근 1달 간 너무 고민이 많았습니다;;;
pgsql빠이자 DB에 대해 잘 아는 사람이 저 밖에 없어서 당연히 프로젝트는 pgsql
처음에 프로토타이핑 할 때야 데이터가 몇 건 없으니까 별 문제가 없었습니다.
크롤러 계열인데 프로토타입이 완성되어서 시운전을 하는데 크롤러의 성능이 낮을 때는 데이터가 슬슬 들어와서 체감을 못했습니다.
근데 데이터가 천만건을 넘어가니까 여기저기 걸린 FK와 트리거들 때문에 성능이 나오지 않기 시작했습니다 =_=
크롤이라지만 웹문서를 다 긁어서 넣는게 아니라 메타데이터만 넣기 때문에 한 레코드 크기가 작은데도 양이 워낙 많으니까 데이터 클러스터 크기가 너무 큽니다.
이리저리 튜닝해보고 하다가 초당 500레코드 정도는 쌓게 되었는데 문제는 이 장비의 메모리가 15기가 뿐이라는거;
디스크는 RAID 0으로 4개 붙여서 IO 확보는 되어 있는데 데이터 클러스터가 60기가를 넘어서니 입력은 그럭저럭 되지만 조회가 너무 느렸습니다.
인덱스 파일만도 수십 기가가 되니까 이걸 읽어서 뭘 한다는 것이 너무 부담이 가더군요 =_=
이 시스템의 목표는 크롤 속도도 중요하지만 조회가 번개 같아야 합니다.
그래서 서버 3대를 올려서 LDAP를 세팅하고 분산되게 referral 걸고.. 크롤러를 LDAP로 되게 바꿔서 돌렸는데 LDAP가 읽기는 그럭저럭 괜찮은데 극악의 쓰기 성능을 보여줘서 3일만에 GG
pgsql로 다시 해보려고 서버 세팅을 한 대 더 해서 slony-I을 올려서 한 대는 쓰기만, 한대는 읽기만 하도록 했습니다.
근데 이게 문제가 slony-I이 master에서 일어나는 쿼리를 로깅해서 slave에서 그대로 다시 쓰는 방식입니다.(세련되지 못 한..)
master에서 일어난 변경이 slave까지 도달하는데 몇 시간이 걸립니다 -_-;;
데이터가 억단위가 되니까 밀린 로그가 천만건 단위가 되더군요..
이 때 가장 문제가 되는게 master에서 일어나는 autovacuum이야 전체가 지연되니까 그런갑다 하는데 slave에서 일어나는 autovacuum은 리플리케이션 지연을 일으켜 버립니다.. ㅠㅠㅠㅠㅠㅠ
그래서 이것도 철수.....
결국 구조를 병렬화 하기로 하고 역할별로 pgsql 서버를 분산했습니다.
DB는 3개로 하고 장비 2대에 나눠 담았습니다. 각각 DB는 xxx1, yyy1, xxx2, yyy2 처럼 incremental하게 늘어날 수 있도록 어플도 병렬로 async하게 쿼리하도록 바꾸고요.
이 중 DB 2개는 insert만 일어나고 DB 1개는 대량의 update가 일어납니다.
이렇게 해서 돌리는데 처음에는 신나게 돌아가더라구요. 크롤러 성능도 좋아져서 초당 1500 이상의 레코드를 쌓고 있었습니다.
이제 되었구나 ㅠㅠㅠㅠㅠ 싶어서 하루 자고 일어났는데 아침에 보니 대량의 update가 일어나는 놈이 하염없이 vacuum을 돌리고 있더군요. 수많은 update waiting..... 크롤러는 임시 휴업 상태..
그래서 이 대량의 update가 일어나는 DB를 mysql myisam 테이블로 옮겼습니다.
지금은 pgsql 2대 에서 DB 한 개 씩, mysql에 DB 한 개.
그럭저럭 데이터가 잘 들어갑니다.
pgsql에서는 전혀 join이 일어나지 않고 key-value 처럼만 동작하는데 이것도 문제가 생겨났습니다.
select * from 테이블 where id in (0, 1, 3, 4, 5, 6, 7, ... ) 처럼 데이터를 가져오는데 이 PK값으로 접근하는 것도 데이터 파일을 랜덤 엑세스 하니까 몇 초씩 걸립니다.. 수십기가의 파일을 읽었다 놨다 하느라 그러는 거지요.
쿼리 플랜을 보면 예상 코스트, 실제 코스트는 0.000... 단위인데도 OS 레벨의 파일 열기 등에 대한 계산은 여기에 포함 안되더군요 =_=
게다가 크롤러 데몬이 300개 정도가 도는데 각 서버로 세션을 하나씩 맺습니다. 그럼 pgsql 세션이 300개가 되고요. 이것들이 엄청난 속도로 레코드를 쌓으니까 조회하려고 연결하는 웹서버의 세션이 생성되는 시간이 오래 걸립니다 ㅠㅠㅠㅠㅠㅠ
그래서 DB서버의 포트를 localhost:5433으로 바꾸고 DB서버에 pgpool을 띄웠습니다.
그리고 크롤러에서는 연결을 맺었다 끊었다 하게 하고요. pgpool이 없으면 이렇게 못하겠죠;
그랬더니 세션이 2/3으로 줄어서 그나마 조회를 할 수가 있게 되었습니다..
pgsql 서버의 시스템 로드가 140 쯤 되더군요 -_-; 이런 수치는 처음 봤음..
그래도 목표 품질이 나오지 않아서.. 지금은 pgsql을 완전히 걷어내려고 하고 있습니다.
파일 DB엔진을 하나 들고 와서 C로 pgsql 역할을 할 놈을 만들고 있습니다.
어차피 대량의 데이터로 가니까 mysql은 정렬 인덱스로만 쓰이고 데이터는 key-value 베이스로 갈 수 밖에 없더군요 ㅠ
어쩔수 없이 pgsql을 버리고 있습니다 ㅠ;
pgsql은 좋지만 현재 프로젝트의 용도에는 맞지 않는 것 같아서..
그 동안 거의 10년간 웹서비스를 개발했지만 수억 단위의 양을 넣어본 적은 없어서 DB책들에 있는 인덱스에 의한 random disk seek, disk IO, OS level cache 등등의 내용이 뭘 의미하는지, vacuum이 왜 치명적인지 이제야 알 것 같습니다.
ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
|