Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

데이터베이스 증가 제어:테이블 크기를 작게 유지하고 데이터 팽창을 방지하기 위한 전략

대부분의 웹 애플리케이션은 일종의 데이터 저장소(종종 관계형 데이터베이스)를 사용합니다. 웹 앱이 성공하면 데이터베이스에 데이터를 "저장"하기가 너무 쉬워질 수 있습니다. 그러나 데이터를 축적하면 데이터베이스 테이블(행 수와 저장된 데이터 크기 모두)이 무한정 증가하게 됩니다.

이는 어느 정도까지는 문제가 없지만 일부 데이터 팽창을 방지하는 데 매우 유용합니다. 또는 이를 방지할 수 없는 경우 성장을 적절하게 관리할 수 있도록 인프라를 미리 계획하는 것이 좋습니다.

본격적으로 시작하기 전에 어떻게 애플리케이션이 비대해지게 될 수 있는지 살펴보겠습니다.

더 많은 데이터가 항상 좋은 것은 아닙니다

우리가 작업하는 대부분의 애플리케이션은 시간이 지남에 따라 점점 더 커지는 경향이 있습니다.

데이터베이스에 클라우드 공급자를 사용하는 경우 할당된 스토리지 한도에 도달할 수 있습니다. 그런 일이 발생하면 다른 인스턴스 유형으로 업그레이드해야 합니다. Heroku PostgreSQL 데이터베이스에는 제한이 있습니다. 예를 들어 "취미" 계층 인스턴스는 1GB의 데이터로 제한됩니다.

데이터가 많을수록 쿼리 속도에도 영향을 미칩니다. 인덱스 없이는 가능했던 일이 더 큰 테이블에서는 불가능해집니다. 일부 행 범위 검색 속도가 느려집니다. UPDATE 데이터베이스를 수행하기 위해 더 많은 잠금이 획득됩니다. 그리고 DELETE 작전을 수행합니다.

데이터베이스 테이블이 늘어나는 방식

데이터 축적은 점진적으로 발생합니다. 지금은 문제가 되지 않는 일이 한 달, 여섯 달 후에는 쉽게 문제가 될 수 있습니다. 데이터 축적의 가장 위험한 점은 놓치기 쉽다는 것입니다. 몇 가지 매우 고전적인 시나리오를 생각해 보십시오:

  • 규정 준수를 위해 paper_trail과 같은 gem을 채택합니다. 그리고 audit_log_entries을 받으세요 테이블. 애플리케이션에서 중요한 모드를 갖는 모든 작업은 audit_log_entries에 행을 생성합니다. 테이블. 이러한 감사 로그 항목은 절대 보관되지 않습니다.
  • 업로드를 수락하고 ActiveStorage를 사용하고 있습니다. 업로드한 내용은 절대 삭제하지 않으므로 activestorage_blobs 테이블이 점점 커지고 있어요.
  • 웹에 게시하기 위해 공유 CMS를 실행하고 기사 세그먼트가 데이터베이스에 저장되도록 허용합니다. 귀하의 플랫폼은 성공했지만 대부분의 저자는 책 크기의 기사를 작성합니다. pages 테이블은 수천 페이지만 포함되어 있음에도 불구하고 크기가 매우 커집니다.
  • 사용자 업로드 콘텐츠를 허용하지만 규정 준수를 위해 데이터를 삭제하지 않고 대신 paranoia와 같은 것을 사용합니다. 플래그를 통해 삭제합니다. 당신의 user_items 테이블은 무한정 커지며, 여러분도 모르는 사이에 1,000만 행을 넘습니다.

이러한 패턴은 제때에 포착되지 않으면 영향을 미칩니다. 테이블 크기를 잘 파악하고 있다면 사용자에게 미치는 영향을 최소화하면서 업그레이드를 수행하기 위해 사용량이 적은 시간에 업그레이드해야 할 시기를 예측하고 유지 관리 일정을 계획할 수 있습니다.

예측도 훨씬 쉬워집니다. 예:

  • 오늘 우리 events 테이블이 메모리에 맞습니다. 현재 성장률로는 7개월 안에 기억에 남지 않을 것입니다.
  • RDS 인스턴스 유형의 스토리지 사용량이 30%입니다. 내년 1월에는 90%를 달성할 예정입니다.
  • payments에 전체 테이블 스캔 쿼리가 있습니다. 입력이 쿼리에 따라 달라지는 모든 행에 대해 함수를 계산합니다. 우리는 payments를 알고 있습니다. 테이블은 3주 안에 200만 행을 초과하고 내년 1월에는 2천만 행을 초과할 것입니다.

이들 모두는 사고나 중단으로 나타날 가능성이 있습니다. 하지만 충분히 일찍 공격하면 이를 상당히 쉽게 완화할 수 있습니다. 예:

  • events에서 30일이 지난 모든 데이터에 대한 보관을 설정합니다. 테이블.
  • 4개월 안에 RDS 인스턴스를 업그레이드하세요.
  • 전체 테이블 스캔을 제한하려면 WHERE을 추가하세요. 대신 훨씬 더 작은 행 하위 집합에서 함수를 계산하도록 쿼리에 조건을 지정했습니다.

데이터베이스 성장에 대한 가시성 확보

데이터베이스 증가를 감시하려면 다음 두 가지 방법이 있습니다:

  • 특수 도구(예:MySQL용 통계)를 설치하고 Prometheus, Telegraph 또는 기타 도구를 통해 측정항목 수집 엔진에 연결하세요.
  • AppSignal을 사용하세요. 특히 이미 애플리케이션에 사용하고 있다면 더욱 그렇습니다.

AppSignal은 여러 측정항목 유형을 저장할 수 있으며, AppSignal이 지원하는 측정항목 유형 중 하나는 gauge입니다. . gauge 환경당 단일 시계열입니다(예:production , staging 또는 development ) 수시로 업데이트할 수 있습니다. AppSignal 측정항목도 태그를 허용하므로 태그가 지정된 일부 gauge를 자동으로 생성할 수 있습니다. 데이터베이스 테이블에 대한 측정항목입니다. 그렇게 합시다:

  • db.row_count 테이블당 테이블의 대략적인 행 수(나중에 대략적인 수치에 대해 알아보겠습니다)
  • db.data_size_bytes 테이블이 사용하는 바이트 수
  • db.index_size_bytes 테이블의 인덱스가 사용하는 바이트 수에 대해

측정항목 이름 뒤에 값 유형을 붙였습니다. 이는 나중에 측정항목 표시 방법을 정의할 때 도움이 됩니다. 별도의 "데이터" 및 "지수" 측정항목도 중요합니다. 테이블에 많은 행과 몇 개 이상의 인덱스가 포함되어 있는 경우 해당 인덱스의 크기는 저장된 데이터 크기의 2~3배가 될 수 있습니다. 모든 인덱스는 자체적으로 파생된 데이터를 저장하므로 약간의 스토리지 오버헤드가 발생하기 때문입니다.

빠른 데이터베이스 테이블 행 계산

행 수의 "대략적인" 부분이 필수적입니다. 일반적으로 테이블의 정확한 행 수를 원하는 경우 SELECT COUNT(1) FROM my_table과 같은 쿼리를 수행할 수 있습니다. . 그러나 우리가 원하는 것보다 느릴 수도 있습니다.

COUNT일 때 , 데이터베이스는 쿼리 중에 테이블의 행 수가 변경되지 않도록 보장하므로 쿼리가 실행되는 동안 테이블을 잠그거나 분기 트랜잭션을 생성합니다. 테이블이 클수록 쿼리 속도가 느려집니다. 더 많은 행이 검색되고 더 많은 잠금이 누적됩니다.

따라서 우리가 원하는 것은 행 수의 "충분히 가까운" 근사치(성능 추정을 위해 10~30,000개 이하의 행이면 충분함)일 때 내부 데이터베이스 엔진 통계를 사용하여 이러한 유형의 데이터를 쿼리할 수 있습니다.

행이 "페이지"에 기록되므로 대부분의 데이터베이스는 테이블 데이터에 대한 액세스를 최적화했습니다. 데이터베이스 엔진은 대략 삽입 순서대로 어떤 행이 어떤 페이지에 할당되었는지 추적합니다.

  • 1~100행은 1페이지에 있습니다.
  • 101-200행은 2페이지에 있습니다.
  • 201-300행은 3페이지에 있습니다.

등등.

엔진은 테이블당 페이지 수와 사용하는 페이지당 대략적인 행 수를 알고 있으므로 할당한 페이지 수를 계산한 다음 이를 페이지 크기(페이지당 행 수)로 곱하여 해당 추정치를 제공할 수 있습니다. 여기에는 몇 가지 장점이 있습니다. 계산이 매우 빠르며 쿼리가 실행되는 동안 테이블을 잠글 필요가 없습니다.

MySQL의 레코드 테이블 크기

그런 다음 테이블 통계를 위해 데이터베이스 엔진을 쿼리해야 하기 때문에 수행해야 하는 작업은 데이터베이스마다 다릅니다. MySQL부터 시작해 보겠습니다. 실행해야 할 쿼리는 다음과 같습니다.

 

그런 다음 출력에서 몇 개의 열을 가져옵니다. 우리가 관심을 갖고 있는 것은 Data_length입니다. , Index_lengthRows . 테이블의 크기는 Data_length + Index_length의 합으로 정의됩니다. 이며, 페이지 기준 대략적인 행 수는 Rows입니다. .

전체 데이터베이스에 대해 이 데이터를 수집하는 코드 블록으로 패키지해 보겠습니다. 우리는 ActiveModel와 작업하고 있지 않기 때문에 클래스에서는 ActiveRecord에서 직접 제공하는 쿼리 메서드를 사용하겠습니다.

 

PostgreSQL의 레코드 테이블 크기

PostgreSQL에 대해서는 SHOW TABLE STATUS와 같은 단축 쿼리가 없기 때문에 좀 더 정교한 쿼리가 필요합니다. . 내부 PostgreSQL 테이블을 쿼리해야 합니다:

 

이는 public에만 해당됩니다. 스키마(사용할 가능성이 있는 기본 스키마) 다른 스키마를 포함하려면 WHERE t.table_schema = 'public'을 제거해야 합니다. 조건을 지정하고 table_info.fetch('name')을 교체하세요. table_info.fetch('full_table_name') 사용 .

통계를 정기적으로 업데이트하세요

이 블록은 정기적으로 실행되어야 하므로 Sidekiq 스케줄러나 cron에서 실행되는 Rake 작업에 넣는 것이 좋습니다. 예를 들어 good_job을 사용하는 경우 다음과 같이 "cron" 섹션에 추가할 수 있습니다:

 

대시보드 만들기

데이터가 들어오면 대시보드를 구축하세요. 필요에 따라 다음 대시보드를 복사할 수 있습니다:

 

Add dashboard를 클릭하세요 그리고 Import dashboard 나타나는 모달 대화 상자에서. 대시보드는 다음과 같은 그래프를 제공합니다:

데이터베이스 증가 제어:테이블 크기를 작게 유지하고 데이터 팽창을 방지하기 위한 전략

그리고 이 테이블 크기 그래프는 다음과 같습니다:

데이터베이스 증가 제어:테이블 크기를 작게 유지하고 데이터 팽창을 방지하기 위한 전략

와일드카드 태그를 사용하여 데이터베이스의 모든 테이블에 대한 그래프를 자동으로 작성하는 방법에 유의하세요.

데이터 해석

데이터를 볼 때 행 수나 크기가 기하급수적으로 또는 선형적으로 증가하는지 살펴보세요. 즉, 테이블이 점점 더 커지고 있습니다.

이 내용을 보면 몇 가지 옵션이 있습니다. 하나는 이러한 무한한 성장을 고려하여 설계하는 것입니다. 즉, 업그레이드 시기를 파악하고 다음으로 가장 적합한 크기로 업그레이드할 수 있는지 여부를 파악하는 것입니다. 또 다른 방법은 정기적인 삭제 작업을 설정하는 것입니다. 제 전 동료인 Wander Hillen이 이 주제에 관해 훌륭한 기사를 썼습니다.

예를 들어 위 스크린샷에서 일부 테이블은 정기적으로 축소됩니다. 이때 정기적인 정리 작업이 실행됩니다. 특정 지점까지 데이터가 누적되는 것을 볼 수 있지만 행의 수신은 상당히 일정한 반면 크기와 행 개수는 감소합니다.

이러한 감소가 발생하고 테이블의 데이터 양이 꾸준한 속도로 증가하는 한 데이터베이스는 갑작스러운 한도 초과로 인해 놀라지 않을 것입니다.

요약:데이터베이스 테이블의 데이터 팽창 방지

이 게시물에서는 데이터베이스 증가에 대한 가시성을 확보하고 데이터 양을 줄이는 방법을 살펴보았습니다.

데이터 팽창은 시장에서 성공을 거둔 애플리케이션에 대한 실질적인 위험입니다. 데이터베이스 테이블에 대한 지표를 설정하면 데이터베이스를 수직으로 확장할 시기와 정기적인 오래된 데이터 정리 설치가 필요한지 여부를 더 잘 예측할 수 있습니다. 약간의 SQL과 결합된 태그가 있는 AppSignal 게이지를 사용하면 이 데이터를 편리하고 쾌적한 형식으로 얻을 수 있습니다.

데이터베이스에 놀라지 마세요!

데이터베이스 증가 제어:테이블 크기를 작게 유지하고 데이터 팽창을 방지하기 위한 전략

율리크 타르카노프

게스트 작성자 Julik Tarkhanov는 Cheddar Payments의 소프트웨어 엔지니어이자 여러 Ruby 오픈 소스 라이브러리의 저자입니다.

Julik Tarkhanov의 모든 기사