데이터 인사이트

데이터 전문가 칼럼
데이터 전문가가 전하는 데이터 노하우

성동찬의 ‘어쩌다 DBA’ (1회) : 살아남기 위해 DB 공부를 시작하다

작성자
관리자
작성일
2020-08-28 18:11
조회
96
 

성동찬의 ‘어쩌다 DBA’ (1회)

살아남기 위해 DB 공부를 시작하다

 
성동찬
카카오뱅크 DBA. 성동찬은 개발자로 사회에 첫발을 내디뎠다가 ‘어쩌다가’ 전사 서비스 담당 DBA가 됐다. 자기 스스로를 국내 금융권 최초의 ‘오픈소스 DBA’로 보고 있다. 금융 서비스에서 ‘규모 있게’ MySQL을 활용하는 DBA로서 독자들과 그 경험을 나누기를 원한다.

(페이스북: dongchan.sung)
 

몇 년 전, 포털 서비스 DBA로 일할 때다. 서비스를 오픈하는 날이었는데 크게 걱정되지는 않았다. 며칠 간 서비스에서 사용할 쿼리들을 취합-검토해 봤는데 전체적으로 문제가 될 만한 지점이 보이지 않았다. 오픈 후 성능이 나지 않는 쿼리들만 손보면 괜찮겠지, 하며 애써 안도했다. 서비스가 드디어 오픈됐다.

여기저기 커넥션이 불안정하다.
애플리케이션의 응답도 늘어지고 있다.
거의 서비스 불능 상태에 이르렀다.
하지만 유입중인 쿼리를 봤을 때 전체적으로 큰 문제는 없어 보인다.

 

• 서울-부산 간 네트워크 지연 7ms

서울에서 부산 서버로 ping을 날려 보면 대략 7ms 정도 지연이 나온다. 서울에는 데이터 노드들, 이 속에는 DB뿐 아니라 캐시 레이어도 같이 있었다. 문제는 이 데이터를 이용하는 애플리케이션 서버들이 부산에 위치한다는 점이었다. 대형 혹은 트래픽이 많은 서비스의 경우, 자주 사용되는 데이터를 상대적으로 느린 DB로부터 매번 읽기보다는 바로 원하는 데이터에 접근할 수 있도록 2차 캐시, 예를 들면 레디스 혹은 멤캐시를 애플리케이션과 DB 사이에 두곤 한다. 문제는 2차 캐시에 ‘자주 사용하는 데이터 질의(query)’를 했을 때, 이 질의 시점에 매번 7ms 네트워크 지연이 관여하면서 전체적으로 서비스 속도가 나지 않고 있었다.

DB 얘기를 하는데 갑자기 웬 네트워크 지연? 하지만 이 시점에 한번쯤 고민해봐야 할 이야기이기에 다소 뜬금없지만 ‘지연’이라는 단어를 꺼냈다.

 

• 어쩌다가 DBA

필자는 아마도 국내 금융권 최초의 ‘오픈소스 DBA’일 거다. 금융 서비스에서 ‘규모 있게’ 오픈소스 DB인 MySQL을 활용하기 시작했는데, 이런 환경 속에서 내 역할은 무엇일까?

필자의 태생은 개발자다. 대학 졸업 후 첫 회사에 들어가 애교로 넘길 수 있는 수습 기간을 마치고 처음 맡았던 서비스, 얘기는 여기부터 시작된다.

‘기술 내재화와 비용 절감’이 유행처럼 번져 나갔던 시기였다. 사실 지금 생각을 해봐도, 엔지니어의 역량을 과연 어떠한 방법으로 제대로 ‘수치화할 수 있을까? 하는 의문이 든다. 그래도 아무튼 당시에 ‘기술 내재화’라는 목표를 향해 ‘외주로 개발-관리’하던 사이트들을 하나둘 가지고 들어와 내부 직원들이 맡아가는 과도기였다.

 

• 살아남기 위해 DB 공부를 시작하다

필자가 입사 직후 맡았던 서비스는 그해 처음으로 기술 내재화하기로 결정됐던, 가입 고객에게 포인트로 ‘혜택’을 주던 서비스였다. 회사 매출에서 꽤 높은 비중을 차지하고 있는 서비스였던 만큼, 개발자 사이에서도 굉장히 고된 업무로 정평이 나 있었다. 고된 업무 기준으로는 회사 톱2에 드는 서비스였다. 아무튼 기술 내재화를 목표하며, 10년 전 이 핫한 서비스는 ‘그랜드 오픈’을 했다.

오픈 직후부터 장애가 끊임없이 이어졌다. 그때만 해도 필자는 경험이 부족했으므로 말그대로 머리가 하얘졌다. 크게 무슨 대책이라도 내놓을 수도 없던 상황 속에서 난생 처음 무한 장애 속에서 허덕일 수밖에 없었다.

어찌 됐든 장애는 이어지고 있었고, 문제의 지점을 찾아내 반드시 해결해야 했다. 지금 생각하면 경악할 만한 사실 하나가 있다. 당시 오픈했던 그 서비스는, 누적 데이터가 없는 상태로 오픈했다는 점이다. 즉 가입 고객정보 외에는 누적된 서비스 데이터가 없었으므로 DB 기준으로는 절대 큰 문제가 없어야 정상이었다. 그러나 매번 지속되는 장애와 성능 저하, 그 중에서도 가장 심각했던 부분이 DB였다.

행운은 고난 중에 찾아온다고 했던가. 그 순간 아마도 내게 가장 큰 행운 하나가 주어졌다. ‘DBA 출신의 조직장을 만난 게’ 바로 그거다. 당시 그 조직장은 DB에 유입되는 쿼리 몇 개를 골라 필자를 포함해 담당 개발자들에게 튜닝 포인트를 짚어 주었다. 그걸 적용했다. 당장 문제가 되는 최악의 성능 저하 요소를 해결할 수 있었다.

이후 DB 최적화를 위해 ‘서비스 개발자’ 입장에서 늘 고민했다. 개발자로서 내 자신의 역량을 높이고자 부단히 노력해왔다. 조금 지나치게 표현한다면, 아마도 살아남기 위해 DB 공부를 시작했지 싶다.

필자가 기억하는 그 사이트의 굵직한 튜닝 요소는 다음 세 가지였다.

1. 트리거 기반의 포인트 관리
2. 로그 테이블 파티셔닝 관리
3. 애플리케이션 캐시 활용

 

• 트리거 기반의 포인트 관리

우선 트리거란 특정 테이블에 "INSERT/UPDATE/DELETE"와 같은 데이터 조작이 발생하는, 각각의 이벤트에 따라 곧바로 시행되는 DB 기능이다.

DB를 다루는 지금에 와서는 트리거를 딱히 좋아하지 않는다. 우선 MySQL은 트리거를 활용해 Online Alter를 구현해 놓은 서드파티 전용 툴이 있기도 하지만, 무턱대고 트리거를 사용하기에는 지금도 부담스럽다. 트리거는 개인적으로 지향하는 ‘무중단’ 서비스 달성에 상당 부분 제약을 주는 기능이기도 하다.


그림 1. 트리거를 활용한 통계 테이블 관리

당시 필자가 참여했던 그 서비스는 매출과 직접적으로 연관돼 있던 ‘포인트 관리’가 애플리케이션적으로 제대로 이뤄지지 않던 상황이었다. 애플리케이션 여기저기에 퍼져 있던 취약 지점을 어떻게든 개선해야 했다. 애플리케이션에서 문제를 제대로 해결할 수 없다고 판단했다. 실제 데이터가 변경되는 시점에서 DB 레벨로 보정하는 것이 최선이라고 보고 이를 적용했다.

 

• 로그 테이블 파티셔닝 관리

모든 로그 성격의 데이터가 한 테이블로 저장돼 있었다. 물론 데이터가 거의 없던 시점에는 성능 관점에서 전혀 문제가 되지 않았다. 하지만 고객들이 포인트를 시시각각 적재하고 사용하면서 테이블 조회 성능이 빠르게 저하되고 있었다. 당장 문제가 되지는 않았지만, 장기적인 ‘일정 부분의 일관된 성능’을 보장하기 위해서는 월별 파티셔닝 관리가 필요했다. 물론 개발자 관점에서 접근했다. DB 관리자가 없던 ‘당시’ 상황을 고려해 봤을 때, ‘애플리케이션 레벨’의 테이블 파티셔닝이 훨씬 유리해 보였다. 이 또한 이행했다.

그림 2. 애플리케이션 레벨의 테이블 파티셔닝


• 애플리케이션 캐시 활용

서비스 전체적으로 로컬 캐시를 최대한 활용했던 점은 당시 서비스 최적화 요소 중에서 단연 으뜸으로 뽑고 있다. 우선 그 사이트는 사용자가 로그인 후 페이지를 이동할 때마다 무조건 DB로부터 몇몇 데이터를 읽어오는 구조였다. 즉 DB야말로 단일 장애점(single point of failure, SPOF)이었다.

장애 여부를 떠나 DB로의 누적된 트래픽 증가에 따라 서비스에 대한 사용자의 쾌적한 경험 제공이라는 바람해외에는 DB에 반드시 의존할 필요는 없었다. 그래서 반드시 읽어 올 데이터를 제외한 나머지 부분은 초반 로딩 이후 애플리케이션 캐시(당시에는 EH Cache)에 최대한 담았다.

추가로 온갖 콘텐츠 제공자(contents provider, CP)들과 사이트가 제휴돼 있던 상황이었다. 그때만 해도 CP들의 서비스 영속성은 생각보다 견고하지 않았다. 그들의 서버는 언제든 장애가 날 수 있던 상황이었다. 장애 시 이를 재빠르게 ‘공지 전환’할 수 있어야 했다. 그래서 각 페이지 URI를 따져 공지 혹은 페이지 전환 필요 여부를 관리할 수 있도록 [그림 3]과 같이 애플리케이션 캐시로 구현했다.


그림 3. 애플리케이션 캐시 사용

그해 가을, 마침내 그 서비스 개편이 있었다. 필자가 생각했던 튜닝 포인트들을 애플리케이션 레벨에서 적용했다. 결과는 대성공이었다. 데이터가 누적됨에 따라 조금씩 성능이 저하되는 DB 리스크를 해결하기 위해 준비해 놓았던 고사양 서버로의 스케일업을 하지 않아도 되는 나름 짜릿했던 성공 경험이었다. 이후 어쩌다 보니 전사 서비스 DBA가 되어버렸다.

 

• 데이터 흐름을 경시했더니…

떨어지는 낙엽도 조심해야할 때였을까? 서비스 튜닝 대성공 이후, 마음이 조금은 느슨해졌던 것 같다. DBA로 완벽하게 전향하고서도 수많은 장애를 겪어보았지만, 지금도 생생히 기억나는 값진 장애 경험 하나가 있다.

사이트의 목적이 고객에게 혜택을 주는 것이었으므로 상황에 따라 각각 다른 이벤트들이 존재했다. 무조건 이벤트에 응모하면 추후 관리자가 당첨자를 선정해 발표하는 타입의 이벤트도 있었다. 응모 시점에 바로 당첨자가 선정되는 이벤트도 있었다.

문제는 오픈 이후 몇 주 뒤 시행했던 대형 선착순 이벤트(후자)에서 발생했다. ‘1만 원을 100원에 드립니다’ 형태로 이뤄지던 선착순 즉석 당첨 이벤트였다. 서비스를 오픈하기 한 달 전부터 사이트 메인 배너에 광고하고 있었다. 이미 엄청나게 많은 회원이 이벤트 오픈을 목이 빠져라 기다리던 상황이었다.

한창 DB 업무에 자신감을 붙여서 트리거로 이러 저런 걸 구현하며 배워가는 과정이었다. 트리거의 효과를 제대로 맛본 나머지 트리거를 마치 ‘마법의 도구’처럼 지나치게 맹신하고 말았다. 이벤트 현황 통계 테이블을 하나 만들어 놓고, 이벤트별로 ‘현재 이벤트 응모 수’와 ‘현재 당첨자 수’를 저장하는 칼럼을 만들었다. 여기다 이벤트 응모 혹은 당첨자 발생 시 동일 로우(ROW)의 칼럼 각각을 업데이트하도록 트리거를 생성했다.

여기서 선착순 즉석 당첨 이벤트가 계획 대로 매우 ‘핫하게’ 이뤄지면서, 동일 데이터를 업데이트하는 두 개의 트리거에서 경합이 발생했다. 트랜잭션들이 서로 교착상태에 빠졌다. 결국 서비스 불능 상태에 도달하고 말았다.


그림 4. 트랜잭션 경합 문제

대응은 간단했다. 사용자 입장에게 큰 의미가 없던 ‘이벤트별 당첨자 수’ 칼럼에 업데이트하는 트리거를 제거한 거다. 그 현황은 관리자에게만 의미가 있을 뿐, 사용자 기준으로 봤을 때는 큰 의미가 없는 데이터였기 때문이다. 응모 이벤트에 대한 본인 당첨 여부만 중요했지 고객 서비스 기준으로는 별 의미가 없었다.

이후 선착순 시작 시 순간 사용자가 몰리기는 했지만, 이전과 같이 트랜잭션 처리로 인한 교착 상태에 빠져드는 일은 없었다(사실 지금 생각해보면 이벤트의 특정 로우에만 트랜잭션 처리가 몰릴 수 있는 이같은 처리도 좋은 방안은 아니었다).

사용자들이 어떤 식으로 데이터 트래픽을 유발하고, 그 데이터가 어떻게 흐를지를 미리 고민해보지 않고 트리거만 맹신해 데이터를 처리했던 내 자신에 대해 크게 반성을 했던 기회였다. 그 이후부터는 ‘흐르는 데이터’를 늘 염두에 두게 됐다.

 

• DBA, 데이터를 놓고 고민하는 사람

많은 서비스 현장에서 DBA들이 고군분투 한다. DBA의 롤은 알려진 바와 같이 다음과 같다.

"DB 시스템이 원활하게 수행되도록 DB의 전체적인 관리 운영에 대한 최고의 책임을 지는 개인 또는 집단으로 일반적으로 DBA라 한다. DBA는 DB의 구성 요소 결정, 스키마 정의, 저장 구조와 접근 방법 선정, 권한 부여와 유효성 검사 같은 보안 정책 수립, 백업 및 복구 절차 수립, 정보의 무결성 유지, 성능 향상과 재구성뿐만 아니라 DB와 관련된 모든 행정적 책임을 지고 있다." _네이버에서 발췌

나는 전문화한 일반적인 정의로서, DBA 관점에서 벗어나서,DBA를 좀 더 데이터를 보는 사람으로 얘기를 해보고 싶다. 그 사람은 개발자일 수도 있고, 시스템-네트워크 엔지니어일 수도 있다. 이제 막 서비스를 런칭하는 스타트업 입장에서 경험과 실력을 다진 전문 DBA를 고용할 수 없을 수도 있다. 하지만 적어도 그 서비스 안에서 어떠한 방식이든 사용자의 데이터를 고민하는 누군가는 있다. 필자는 이렇게 데이터를 놓고 고민하는 사람이야 말로, 그 서비스에서는 유일무이한 DBA라고 생각을 한다.

• ‘쿼리를 잘하고 싶어요’

꽤나 오래 전 얘기다. 늘 뒤편에서 DB 운영 지원을 하던 직장 동료가 퇴사하며, 개인적으로 필자에게 질문을 던졌다. 너무도 갑작스러운 질문에 당황했지만 내가 생각하는 쿼리에 대해 얘기를 해보았다.

“쿼리는 DB에게 일을 시키기 위해 전달하는 언어에 불가합니다. 일을 시키고자 한다면, (DB에게) 어떤 일을 해야 할지를 명확하게 정의해 줘야겠죠. 그 일을 DB가 처리하는 과정에서 흐를 만한 데이터를 한번 상상해 보세요. 최대한 간결하고 직관적으로 풀어보세요. 그러면 조금은 답이 보이지 않을까요?”

쿼리는 데이터를 흐르게 하는 하나의 수단일 뿐 그 이상도 이하도 아니다. 중요한 것은 어떤 ‘쿼리’를 실행할 것인가에 있지 않고 ‘어떤 데이터’를 추출하려는지에 있다. 쉽게 말해 데이터 분포도를 고려해 인덱스를 잘 활용할 수 있는 방안을 찾는 데에 있다.

대량의 데이터 스캔이 필요해서 생각보다 여러 데이터를 처리해야하는 입장이라고 해보자. 이때는 별도 통계 테이블을 만들어 주기적 혹은 실시간으로 테이블에 업데이트하는 방안도 생각해 볼 만하다. 굉장히 정적인 데이터일 경우에는 이를 DB 외적인 캐시 영역에 저장해 변경 시에만 캐시 데이터를 업데이트하도록 유도해볼 수도 있다. 소셜 서비스가 빠른 속도로 발전함에 따라, 엄청난 양의 데이터가 쏟아지고 있다. 이런 데이터를 고가의 엔터프라이즈 클러스터에서 저장-관리하려면 엄청난 비용을 감수해야 한다. 자연스럽게 데이터 분산에 대해 고민할 것이다. 데이터에 따라 샤딩 혹은 캐시를 제대로 활용하는 방법도 알아야 할 필요가 있다.

소견이지만, DBA가 이런 데이터 입장에서 서비스를 고민하면서 방향 설정을 제대로 해야 한다. 데이터가 조금이라도 더 효율적으로 흐르게 하기 위해서는 영역을 따지지 말고 분석하고 고민하고 계발해야 한다.

이 영역은 시스템-네트워크-개발 등을 가려서는 안 된다. 마치 서울과 부산의 최적의 길을 알려주는 ‘스마트한’ 내비게이션과 같이, 현재의 교통 상황과 도로 상황을 잘 조합해 가장 빠르게 목적지로 도달할 수 있는 데이터 내비게이터 역할을 해야 한다.

• 스마트한 데이터 내비게이터로서 DBA

아찔한 장애에 직면하고 이를 해결했던 짜릿한 경험 속에서 지금까지 필자 가슴에 새겨 넣은 교훈은 여전히 이것 하나다. ‘문제의 해결점은 DB 외적인 부분에 있을 수 있으므로 반드시 데이터를 봐야 한다.’ 스마트한 데이터 내비게이터, 필자가 생각하는 DBA에게 가장 중요한 덕목이다.

지금도 수많은 DBA가 각자의 철학에 따라 현장에서 활동하지만, 때로는 나처럼 데이터를 우선하는 DBA도 있다는 것을 알리며 이 글을 마무리하고자 한다. (다음 호에 계속)

 

출처 : 한국데이터진흥원

제공 : 데이터 전문가 지식포털 데이터온에어(dataonair.or.kr)