엔지니어링


카드 매출 데이터 DB 분리 (Part. 2)

한국신용데이터
2023-02-06
조회수 192


안녕하세요. 한국신용데이터 관리서비스팀 Tony(정원재) 입니다.

지난 글에서 캐시노트 DB가 가지고 있는 문제를 파악하고, DB 분리 결정 배경과 작업 전 코드 조사 내용을 공유드렸습니다.

이번 글에서는 조사 후 코드 변경 작업과 DB 분리 작업 과정에 대해서 공유해 드리겠습니다.


코드 변경 작업

Business class 처리

Business와의 연결을 제거하면 실제로는 거의 연결된 부분이 없어서 코드 수정 작업량이나 난이도는 생각보다 높지 않았습니다.

루비의 특징 상 메서드와 프로퍼티 조회의 호출 방식이 다르지 않았기 때문에
Business에서 has_many를 통해 연결되어 있는 부분을 메서드로 변환했습니다.

before:

has_many :card_sales_data, dependent: :destroy

after:

def card_sales_data
CardSalesData.where(business_id: id)
end

이렇게 변경한 뒤 조회 테스트를 진행해 보았습니다. 조회 결과는 기존과 동일한 것을 확인했습니다.

삭제 배치 처리

쓰기 부분도 캐시노트 서비스에는 삭제하는 부분만 존재했습니다. 그래서 이 부분만 처리를 진행하면 되었습니다.

그래서 business를 삭제하는 부분에

CardSalesData.where(business_id: business.id).delete_all

를 추가했습니다. 그리고 기존에 테이블에 설정되어 있는 cascade와 fk 등을 제거 했습니다.

이관 대상 테이블 아닌 테이블과의 join 풀기

코드 변경 작업 중에서는 가장 어려운 작업이었습니다.

대표적인 부분을 예로 들면 group by로 조회하는 서브 쿼리를 outer join을 한 뒤 where 조건으로 사용하고 있는 케이스였습니다.

처음에는 이 메서드의 조회 결과만 동일하게 동작하면 될 것이라 생각하고 Join을 풀어 변경을 했습니다.

레일즈 콘솔에서 메서드 호출 결과를 비교해보며 동일한 값이 조회되는 것을 확인했고 개발이 마무리 되었다고 생각했습니다.

그런데 Spec을 통한 테스트 진행 중 오류가 발생하는 곳들이 쏟아져 나오기 시작했습니다. ActiveRecord를 통한 조회가 여기서 끝난 것이 아니었습니다.

def self.where(business:, **opts)
business.something_data.where(blahblah)
end

해당 기능은 위와 같은 형태의 구문으로 되어 있었습니다. 이 결과가 리스트와 같은 자료구조로 전달이 될 것이라고 예상했던 것인데… 오류가 발생하는 곳들을 살펴보니 다른 곳에서 조회를 돕는 헬퍼였기에 뒤에 이어지는 다른 ActiveRecord 조건들이 실행되지 않으며 오류들이 발생하게 되었습니다.

다시 ActiveRecord의 흐름이 이어지도록 변경하려 몇 시간을 씨름했지만, 저의 짧은 RoR 실력으로는 거기까지 변경을 어려웠습니다. 😭 그래서 다른 개발자 분께 제가 하고자 했던 작업의 내용을 전달드렸고, 원하는 코드를 얻게 되었습니다. 이 후 테스트를 통해 동일한 결과가 조회되는 것을 확인하고 다음 작업으로 넘어가게 되었습니다.

놓치고 있던 부분

변경한 코드를 적용하기 전 리뷰를 거치는 과정에서 제가 누락시킨 부분이 있다는 것을 확인하게 되었습니다.

Get Tony (정원재)’s stories in your inbox

Join Medium for free to get updates from this writer.


Subscribe

캐시노트 서비스에서는 DB의 view를 사용하고 있던 부분이 존재했습니다. 일부 view 중에 이관 대상 테이블과 아닌 테이블이 join 되어 사용되고 있는 부분이 있어 오류가 발생할 수 있다는 것을 확인 하게 되었습니다. 코드레벨에서 탐색만 진행했던 것이 DB 관련 사용처는 발견하지 못했던 원인이었습니다. 운영 배포 후 알게 되었으면 아찔 했을 내용이었습니다. 다행스럽게도 운영 배포 전에 발견하여 너무 감사한 일이었습니다.🙏


DB 분리 작업

DB 계정 변경

현재 DB와 새로운 DB가 동일한 DB 계정을 사용하고 있으면 DB 커넥션이 변경되었는지 알기 어렵습니다. 그래서 이관 대상으로 정해진 테이블들을 조회하는 커넥션의 계정을 다른 계정으로 변경했습니다.

이렇게 계정이 변경된 상태로만 배포되어도 join이 풀어지지 않은 부분에 대한많은 오류가 확인이 가능했습니다. 그래서 테스트 환경에서 서비스의 핵심 기능들을 확인해 나갔습니다.

확인이 완료 된 후, 운영 서버에 현재까지의 작업 내용을 적용했습니다. 하루 정도 모니터링을 진행하다 보니 놓쳤던 부분들에 대한 오류가 발생했습니다. 핵심기능은 아니었고, 빠르게 수정이 가능한 부분들이었습니다. 롤백보다는 핫픽스로 수정 후 재배포로 오류들을 수정했습니다. 잘 사용 되지 않는 기능들은 더 이후에 발생할 수도 있을 것이라 생각 되어 일주일 정도 추가로 지켜보았습니다.

추가적인 오류 발생이 없다는 것을 확인하고, 마지막 남은 작업들을 진행하게 되었습니다.

이관 시나리오

  1. 기존 캐시노트 DB(RDS)를 Aurora Postgresql로 Replication 연결 (데이터 동기화. 분리 진행 전 미리 준비해 두었음)
  2. Aurora Replication을 Aurora Writer로 Promotion (데이터 동기화 끊김, 약 10분 정도 소요)
  3. 카드 매출 데이터 DB (Aurora)의 테이블 중 이관 대상이 아닌 테이블의 이름 변경
  4. 카드 매출 데이터를 사용하는 어플리케이션들의 DB 엔드포인트를 Aurora로 변경하여 배포
  5. 기존 캐시노트 DB의 커넥션 확인
  6. 기존 캐시노트 DB에서 이관대상 테이블의 이름 변경
  7. 서비스 기능 확인

의 순서로 분리를 진행했습니다.

작업 중 이슈

대부분의 작업은 순조롭게 진행되었지만, 2가지 이슈가 발생했습니다.

  • 테이블 이름 변경 지연
    vacuum이 수행되고 있는 테이블은 모든 DDL 수행이 불가능하여, 수행 중인 vacuum 프로세스를 강제 종료한 후 재수행이 필요했습니다.
  • FK로 인한 잡 실패
    이관된 테이블에 FK가 설정되어 있어 수행되어야 하는 잡이 실패하고 있어, FK 제거 후 잡을 재수행했습니다.

작업 결과

우여곡절이 많았지만, 분리 작업은 순조롭게 완료가 되었습니다. 아래는 분리 후의 캐시노트 DB의 CPU 그래프 입니다.

작업 진행 후 캐시노트 DB CPU

최적화가 필요한 쿼리들이 있어 그래프의 모양이 안정적이진 않습니다. 하지만 높은 수치가 30% 정도로 예전처럼 불안정한 상태는 아닙니다. 이제 다른 작업들을 시도해 볼 수 있게 되었습니다. 🎉

또한 카드 매출 데이터의 디비는 생성 전 적절한 DB 파라미터들을 적용해 두었습니다. Vaccum 이슈로 이전에는 수행할 수 없었던 로직 개선이나 클렌징 작업들이 수행 가능해졌습니다.

분리 후 남은 작업들

분리는 완료 되었지만, 이제부터가 진짜 시작인 것 같습니다.

  • 분리된 카드 매출 DB의 CPU 안정화를 위한 데이터 파이프라인 개선
  • DB 버전업 및 각종 패치 + Aurora 전환
  • 불필요한 데이터 클렌징
  • Slow 쿼리 해결을 위한 인덱스 변경 작업 및 로직 개선

남아있는 과제들을 처리하며 다음 번에는 더 흥미로운 주제로 찾아 뵙도록 하겠습니다.

이상 한국신용데이터 토니였습니다. 😉








0 0

월간 인기글