읽기 통계

Spanner는 읽기에 대한 통계를 저장하는 기본 제공 테이블을 제공합니다. SQL 문을 사용하여 이러한 SPANNER_SYS.READ_STATS* 테이블에서 통계를 검색할 수 있습니다.

읽기 통계를 사용해야 하는 경우

읽기 통계는 애플리케이션이 데이터베이스를 사용하는 방식에 대한 통계를 제공하며 성능 문제를 조사할 때 유용합니다. 예를 들어 데이터베이스에 대해 어떤 읽기 유형이 실행되는지, 실행 빈도가 어떤지, 이러한 읽기 유형의 성능 특성이 어떤지를 확인할 수 있습니다. 데이터베이스의 읽기 통계를 사용하여 CPU 사용량이 높은 읽기 유형을 식별할 수 있습니다. 상위 수준에서 읽기 통계는 리소스 사용량 측면에서 데이터베이스로 이동하는 트래픽의 동작을 이해하는 데 도움이 됩니다.

제한사항

  • 이 도구는 CPU 사용률의 대부분을 차지하는 유사한 읽기 스트림을 분석하는 데 가장 적합합니다. 한 번만 실행된 읽기는 검색하지 않는 것이 좋습니다.

  • 이 통계에서 추적하는 CPU 사용량은 프리페치 CPU 사용량과 기타 오버헤드를 제외한 Spanner 서버 측 CPU 사용량을 나타냅니다.

  • 통계는 최선의 방식으로 수집됩니다. 따라서 기본 시스템에 문제가 있으면 통계가 누락될 수 있습니다. 예를 들어 내부 네트워킹 문제가 있으면 일부 통계가 누락될 수 있습니다.

사용 가능 여부

SPANNER_SYS 데이터는 SQL 인터페이스를 통해서만 사용할 수 있습니다. 예를 들면 다음과 같습니다.

  • Google Cloud 콘솔에 있는 데이터베이스의 Spanner 스튜디오 페이지

  • gcloud spanner databases execute-sql 명령어

  • executeQuery API

Spanner가 제공하는 다른 단일 읽기 메서드는 SPANNER_SYS를 지원하지 않습니다.

읽기 유형별로 그룹화된 CPU 사용량

다음 테이블은 특정 기간 동안 CPU 사용량이 가장 높은 읽기 유형을 추적합니다.

  • SPANNER_SYS.READ_STATS_TOP_MINUTE: 1분 간격으로 집계된 읽기 유형
  • SPANNER_SYS.READ_STATS_TOP_10MINUTE: 10분 간격으로 집계된 읽기 유형
  • SPANNER_SYS.READ_STATS_TOP_HOUR: 1시간 간격으로 집계된 읽기 유형

이러한 테이블에는 다음과 같은 속성이 있습니다.

  • 각 테이블에는 테이블 이름에 지정된 길이의 겹치지 않는 시간 간격에 대한 데이터가 포함되어 있습니다.

  • 간격은 시계 시간을 기준으로 합니다. 1분 간격은 매분 정각에 끝나고 10분 간격은 매시 정각에 시작해서 10분 단위로 끝나며 1시간 간격은 매시 정각에 끝납니다. 각 간격이 끝날 때마다 Spanner는 모든 서버에서 데이터를 수집한 다음 곧 SPANNER_SYS 테이블에 데이터를 제공합니다.

    예를 들어 오전 11:59:30에 SQL 쿼리에 사용할 수 있는 가장 최근 간격은 다음과 같습니다.

    • 1분: 오전 11:58:00–11:58:59
    • 10분: 오전 11:40:00–11:49:59
    • 1시간: 오전 10:00:00~10:59:59
  • Spanner는 읽기 유형별로 통계를 그룹화합니다. 태그가 있으면 FPRINT는 태그의 해시입니다. 그렇지 않은 경우 READ_COLUMNS 값의 해시입니다.

  • 각 행에는 Spanner가 지정된 간격 동안 통계를 캡처하는 특정 읽기 유형의 모든 실행에 대한 통계가 포함됩니다.

  • Spanner가 특정 간격 동안 실행된 모든 개별 읽기 유형에 대한 정보를 저장할 수 없는 경우 시스템은 지정된 간격 동안 CPU 사용량이 가장 높은 읽기 유형부터 우선 저장됩니다.

테이블 스키마

열 이름 유형 설명
INTERVAL_END TIMESTAMP 포함된 읽기 실행이 발생한 시간 간격의 끝입니다.
REQUEST_TAG STRING 이 읽기 작업의 요청 태그입니다(선택사항). 태그 사용에 대한 자세한 내용은 요청 태그 문제해결을 참조하세요. 태그 문자열이 동일한 여러 읽기의 통계는 해당 태그 문자열과 일치하는 'REQUEST_TAG'와 함께 단일 행으로 그룹화됩니다.
READ_TYPE STRING 읽기가 PARTITIONED_READ 또는 READ인지 여부를 나타냅니다. PartitionRead API에서 가져온 partitionToken을 사용한 읽기는 PARTITIONED_READ 읽기 유형으로 표시되고 다른 읽기 API는 READ로 표시됩니다.
READ_COLUMNS ARRAY<STRING> 읽은 열의 집합입니다. 알파벳순으로 나열됩니다.
FPRINT INT64 REQUEST_TAG 값의 해시가 있는 경우입니다. 그렇지 않으면 READ_COLUMNS 값의 해시입니다.
EXECUTION_COUNT INT64 해당 간격 동안 Spanner가 읽기 유형을 실행한 횟수입니다.
AVG_ROWS FLOAT64 읽기가 반환한 평균 행 수입니다.
AVG_BYTES FLOAT64 읽기에서 반환된 평균 데이터 바이트 수입니다(전송 인코딩 오버헤드 제외).
AVG_CPU_SECONDS FLOAT64 프리페치 CPU 및 기타 오버헤드를 제외하고 읽기를 실행하는 Spanner 서버 측 평균 CPU 초입니다.
AVG_LOCKING_DELAY_SECONDS FLOAT64 잠금으로 인해 대기에 소비한 평균 시간(초)입니다.
AVG_CLIENT_WAIT_SECONDS FLOAT64 클라이언트가 Spanner에서 생성하는 만큼 빠르게 데이터를 소비하지 않기 때문에 대기한 평균 시간(초)입니다.
AVG_LEADER_REFRESH_DELAY_SECONDS FLOAT64 모든 쓰기가 관측되었고 Paxos 리더가 확인하기 위해 대기한 평균 시간(초)입니다.
RUN_IN_RW_TRANSACTION_EXECUTION_COUNT INT64 읽기-쓰기 트랜잭션의 일부로 읽기가 실행된 횟수입니다. 이 열을 사용하면 읽기를 읽기 전용 트랜잭션으로 이동하여 잠금 경합을 방지할 수 있는지 확인할 수 있습니다.

쿼리 예

이 섹션에는 읽기 통계를 검색하는 SQL 문의 몇 가지 예시가 포함되어 있습니다. 이러한 SQL 문은 클라이언트 라이브러리, gcloud spanner 또는 Google Cloud Console을 사용하여 실행할 수 있습니다.

일정 기간 동안의 각 읽기 유형의 기본 통계 나열

다음 쿼리는 가장 최근 1분 시간 간격 내 최상위 읽기 유형의 원시 데이터를 반환합니다.

SELECT fprint,
       read_columns,
       execution_count,
       avg_cpu_seconds,
       avg_rows,
       avg_bytes,
       avg_locking_delay_seconds,
       avg_client_wait_seconds
FROM spanner_sys.read_stats_top_minute
ORDER BY interval_end DESC LIMIT 3;
쿼리 출력
fprint read_columns execution_count avg_cpu_seconds avg_rows avg_bytes avg_locking_delay_seconds avg_client_wait_seconds
125062082139 ["Singers.id", "Singers.name"] 8514387 0.000661355290396507 310.79 205 8.3232564943763752e-06 0
151238888745 ["Singers.singerinfo"] 3341542 6.5992827184280315e-05 12784 54 4.6859741349028595e-07 0
14105484 ["Albums.id", "Albums.title"] 9306619 0.00017855774721667873 1165.4 2964.71875 1.4328191393074178e-06 0

읽기 유형을 나열하여 총 CPU 사용량을 기준으로 정렬

다음 쿼리는 최근 1시간 동안 CPU 사용량이 가장 높은 읽기 유형을 반환합니다.

SELECT read_columns,
       execution_count,
       avg_cpu_seconds,
       execution_count * avg_cpu_seconds AS total_cpu
FROM spanner_sys.read_stats_top_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.read_stats_top_hour)
ORDER BY total_cpu DESC LIMIT 3;
쿼리 출력
read_columns execution_count avg_cpu_seconds total_cpu
["Singers.id", "Singers.name"] 1647 0.00023380297430622681 0.2579
["Albums.id", "Albums.title"] 720 0.00016738889440282034 0.221314999999999
["Singers.singerinfo""] 3223 0.00037764625882302246 0.188053

집계 통계

SPANNER_SYS에는 특정 기간 동안 Spanner에서 캡처한 집계 읽기 통계를 저장하는 테이블도 포함됩니다.

  • SPANNER_SYS.READ_STATS_TOTAL_MINUTE: 1분 간격 내 모든 읽기 유형의 집계 통계
  • SPANNER_SYS.READ_STATS_TOTAL_10MINUTE: 10분 간격 내 모든 읽기 유형의 집계 통계
  • SPANNER_SYS.READ_STATS_TOTAL_HOUR: 1시간 간격 내 모든 읽기 유형의 집계 통계

집계 통계 테이블에는 다음과 같은 속성이 있습니다.

  • 각 테이블에는 테이블 이름에 지정된 길이의 겹치지 않는 시간 간격에 대한 데이터가 포함되어 있습니다.

  • 간격은 시계 시간을 기준으로 합니다. 1분 간격은 매분 정각에 끝나고, 10분 간격은 매시 정각에 시작해서 10분 단위로 끝나며, 1시간 간격은 매시 정각에 끝납니다.

    예를 들어 오전 11:59:30에 집계 읽기 통계에서 SQL 쿼리에 사용할 수 있는 가장 최근 간격은 다음과 같습니다.

    • 1분: 오전 11:58:00–11:58:59
    • 10분: 오전 11:40:00–11:49:59
    • 1시간: 오전 10:00:00~10:59:59
  • 각 행에는 지정된 간격 동안 데이터베이스에 대해 실행된 모든 읽기 유형에 대한 통계가 함께 집계됩니다. 따라서 시간 간격당 하나의 행만 있습니다.

  • SPANNER_SYS.READ_STATS_TOTAL_* 테이블에 캡처된 통계에는 Spanner가 SPANNER_SYS.READ_STATS_TOP_* 테이블에 캡처하지 않은 읽기 유형이 포함될 수 있습니다.

  • 이러한 테이블의 일부 열은 Cloud Monitoring에서 측정항목으로 노출됩니다. 노출된 측정항목은 다음과 같습니다.

    • 반환된 행 수
    • 읽기 실행 횟수
    • 읽기 CPU 시간
    • 잠금 지연
    • 클라이언트 대기 시간
    • 리더 새로고침 지연
    • 반환된 바이트 수

    자세한 내용은 Spanner 측정항목을 참조하세요.

테이블 스키마

열 이름 유형 설명
INTERVAL_END TIMESTAMP 포함된 읽기 유형 실행이 발생한 시간 간격의 끝입니다.
EXECUTION_COUNT INT64 해당 간격 동안 Spanner가 읽기 유형을 실행한 횟수입니다.
AVG_ROWS FLOAT64 읽기가 반환한 평균 행 수입니다.
AVG_BYTES FLOAT64 읽기에서 반환된 평균 데이터 바이트 수입니다(전송 인코딩 오버헤드 제외).
AVG_CPU_SECONDS FLOAT64 프리페치 CPU 및 기타 오버헤드를 제외하고 읽기를 실행하는 Spanner 서버 측 평균 CPU 초입니다.
AVG_LOCKING_DELAY_SECONDS FLOAT64 잠금으로 인해 대기에 소비한 평균 시간(초)입니다.
AVG_CLIENT_WAIT_SECONDS FLOAT64 제한으로 인해 대기에 소비한 평균 시간(초)입니다.
AVG_LEADER_REFRESH_DELAY_SECONDS FLOAT64 멀티 리전 구성에서 인스턴스 간에 읽기를 조정하는 데 사용된 평균 시간(초)입니다.
RUN_IN_RW_TRANSACTION_EXECUTION_COUNT INT64 읽기-쓰기 트랜잭션의 일부로 읽기가 실행된 횟수입니다. 이 열을 사용하면 일부 읽기를 읽기 전용 트랜잭션으로 이동하여 잠금 경합을 방지할 수 있는지 확인할 수 있습니다.

쿼리 예

이 섹션에는 집계 읽기 통계를 검색하는 SQL 문의 몇 가지 예시가 포함되어 있습니다. 이러한 SQL 문은 클라이언트 라이브러리, gcloud spanner 또는 Google Cloud Console을 사용하여 실행할 수 있습니다.

모든 읽기 유형에서 총 CPU 사용량 찾기

다음 쿼리는 최근 1시간 동안 읽기 유형에서 소비한 CPU 시간 수를 반환합니다.

SELECT (avg_cpu_seconds * execution_count / 60 / 60)
  AS total_cpu_hours
FROM spanner_sys.read_stats_total_hour
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.read_stats_total_hour);
쿼리 출력
total_cpu_hours
0.00026186111111111115

일정 기간 동안의 총 실행 횟수 확인

다음 쿼리는 가장 최근 1분 간격 내 실행된 총 읽기 유형의 수를 반환합니다.

SELECT interval_end,
       execution_count
FROM spanner_sys.read_stats_total_minute
WHERE interval_end =
  (SELECT MAX(interval_end)
   FROM spanner_sys.read_stats_total_minute);
쿼리 출력
interval_end execution_count
2020-05-28 11:02:00-07:00 12861966

데이터 보관

Spanner는 각 테이블의 데이터를 최소한 다음 기간 동안 보관합니다.

  • SPANNER_SYS.READ_STATS_TOP_MINUTESPANNER_SYS.READ_STATS_TOTAL_MINUTE: 이전 6시간을 포함하는 간격

  • SPANNER_SYS.READ_STATS_TOP_10MINUTESPANNER_SYS.READ_STATS_TOTAL_10MINUTE: 이전 4일을 포함하는 간격

  • SPANNER_SYS.READ_STATS_TOP_HOURSPANNER_SYS.READ_STATS_TOTAL_HOUR: 이전 30일을 포함하는 간격

읽기 통계로 높은 CPU 사용량 문제 해결

Spanner 읽기 통계는 Spanner 데이터베이스에서 높은 CPU 사용량을 조사해야 하거나 데이터베이스에서 CPU 사용량이 많은 읽기 유형을 이해하려는 경우에 유용합니다. 대량의 데이터베이스 리소스를 사용하는 읽기 유형을 검사하면 Spanner 사용자는 운영 비용을 줄이고 일반적인 시스템 지연 시간을 개선할 수 있습니다. 다음 단계에서는 읽기 통계를 사용하여 데이터베이스에서 높은 CPU 사용량을 조사하는 방법을 보여줍니다.

조사 기간 선택

애플리케이션에서 CPU 사용량이 많을 때를 찾아 조사를 시작합니다. 예를 들어 다음 시나리오에서는 2020년 5월 28일 오후 5시 20분경에 문제가 발생하기 시작했습니다.

선택한 기간의 읽기 통계 수집

조사를 시작하는 기간을 선택했으므로 해당 시간 동안의 READ_STATS_TOTAL_10MINUTE 테이블에서 수집된 통계를 살펴봅니다. 이 쿼리의 결과를 통해 해당 기간 동안 CPU 및 기타 읽기 통계가 어떻게 변화했는지 알 수 있습니다. 다음 쿼리는 4:30 pm부터 7:30 pm (포함)까지의 집계 읽기 통계를 반환합니다.

SELECT
  interval_end,
  ROUND(avg_cpu_seconds,4) as avg_cpu_seconds,
  execution_count,
  avg_locking_delay_seconds
FROM SPANNER_SYS.READ_STATS_TOTAL_10MINUTE
WHERE
  interval_end >= "2020-05-28T16:30:00"
  AND interval_end <= "2020-05-28T19:30:00"
ORDER BY interval_end;

다음 데이터는 쿼리에서 반환되는 결과의 예시입니다.

interval_end avg_cpu_seconds execution_count avg_locking_delay_seconds
2020-05-28 16:40:00-07:00 0.0004 11111421 8.3232564943763752e-06
2020-05-28 16:50:00-07:00 0.0002 8815637 8.98734051776406e-05
2020-05-28 17:00:00-07:00 0.0001 8260215 6.039129247846453e-06
2020-05-28 17:10:00-07:00 0.0001 8514387 9.0535466616680686e-07
2020-05-28 17:20:00-07:00 0.0006 13715466 2.6801485272173765e-06
2020-05-28 17:30:00-07:00 0.0007 12861966 4.6859741349028595e-07
2020-05-28 17:40:00-07:00 0.0007 3755954 2.7131391918005383e-06
2020-05-28 17:50:00-07:00 0.0006 4248137 1.4328191393074178e-06
2020-05-28 18:00:00-07:00 0.0006 3986198 2.6973481999639748e-06
2020-05-28 18:10:00-07:00 0.0006 3510249 3.7577083563017905e-06
2020-05-28 18:20:00-07:00 0.0004 3341542 4.0940589703795433e-07
2020-05-28 18:30:00-07:00 0.0002 8695147 1.9914494947583975e-05
2020-05-28 18:40:00-07:00 0.0003 11679702 1.8331461539001595e-05
2020-05-28 18:50:00-07:00 0.0003 9306619 1.2527332321222135e-05
2020-05-28 19:00:00-07:00 0.0002 8520508 6.2268448078447915e-06
2020-05-28 19:10:00-07:00 0.0006 13715466 2.6801485272173765e-06
2020-05-28 19:20:00-07:00 0.0005 11947323 3.3029114639321295e-05
2020-05-28 19:30:00-07:00 0.0002 8514387 9.0535466616680686e-07

여기에서 보면 평균 CPU 시간(avg_cpu_seconds)이 더 높습니다(간격 강조표시). 값이 2020-05-28 19:20:00interval_end의 CPU 시간이 더 높으므로 다음 단계에서 추가 조사를 위해 해당 간격을 선택하겠습니다.

높은 CPU 사용률을 유발하는 읽기 유형 찾기

좀 더 자세히 들어가서 이제 앞 단계에서 선택한 간격의 READ_STATS_TOP_10MINUTE 테이블을 쿼리합니다. 이 쿼리의 결과는 CPU 사용량이 많은 읽기 유형을 나타내는 데 도움이 됩니다.

SELECT
  read_columns,
  ROUND(avg_cpu_seconds,4) as avg_cpu_seconds,
  execution_count,
  avg_rows
FROM SPANNER_SYS.READ_STATS_TOP_10MINUTE
WHERE
  interval_end = "2020-05-28T19:20:00"
ORDER BY avg_cpu_seconds DESC LIMIT 3;

다음 데이터는 쿼리에서 다시 반환되는 결과의 예시로서 avg_cpu_seconds의 순위를 기준으로 상위 3개의 읽기 유형에 대한 정보를 반환합니다. 쿼리에서 ROUND를 사용하여 avg_cpu_seconds의 출력을 소수점 이하 4자리로 제한합니다.

read_columns avg_cpu_seconds execution_count avg_rows
[TestHigherLatency._exists,TestHigherLatency.lang_status,TestHigherLatency.score,globalTagAffinity.shares]1 0.4192 1182 11650.42216582
[TestHigherLatency._exists,TestHigherLatency.lang_status,TestHigherLatency.likes,globalTagAffinity.score] 0.0852 4 12784
[TestHigherLatency._exists,TestHigherLatency.lang_status,TestHigherLatency.score,globalTagAffinity.ugcCount] 0.0697 1140 310.7921052631

1 _exists는 특정 행이 있는지 여부를 확인하는 데 사용되는 내부 필드입니다.

CPU 사용량이 높은 한 가지 이유는 몇 가지 읽기 유형을 더 자주 실행하기 때문입니다(execution_count). 읽기가 반환한 평균 행 수가 증가했을 수도 있습니다(avg_rows). 읽기 유형의 이러한 속성 중 하나라도 해당하는 것이 없는 경우 avg_locking_delay_seconds, avg_client_wait_seconds 또는 avg_bytes와 같은 다른 속성을 검사할 수 있습니다.

높은 CPU 사용량을 줄이기 위한 권장사항 적용

앞의 단계를 수행했다면 이 권장사항 중 어느 것이 상황에 도움이 될지 고려해 보세요.

  • 지정된 간격 동안 Spanner가 읽기 유형을 실행한 횟수는 측정값이 합당한지 또는 문제의 징후를 나타내는지의 기준이 되는 측정 항목의 좋은 예입니다. 측정 항목의 기준을 설정하면 정상적인 동작 상의 예상치 못한 편차의 원인을 감지하고 조사할 수 있습니다.

  • CPU 사용량이 대부분의 경우 비교적 일정하게 진행되지만 갑자기 사용자 요청 또는 애플리케이션 동작의 급격한 증가가 있을 때 이와 관련하여 급격한 상승이 나타나고, 이는 모든 것이 예상대로 작동한다는 표지입니다.

  • 다음 쿼리를 사용하여 각 읽기 유형에 대해 Spanner가 실행된 횟수별로 순위가 지정된 상위 읽기 유형을 찾습니다.

    SELECT interval_end, read_columns, execution_count
    FROM SPANNER_SYS.READ_STATS_TOP_MINUTE
    ORDER BY execution_count DESC
    LIMIT 10;
    
  • 특히 멀티 리전 인스턴스 구성을 사용할 때 가장 짧은 읽기 지연 시간을 찾고 있다면 강력한 읽기 대신 비활성 읽기를 사용하여 AVG_LEADER_REFRESH_DELAY_SECONDS 구성요소의 읽기 지연시간을 줄이거나 제거합니다.

  • 읽기만 수행하고 단일 읽기 메서드를 사용하여 읽기를 표현할 수 있는 경우, 해당 단일 읽기 메서드를 사용해야 합니다. 단일 읽기는 읽기-쓰기 트랜잭션과 달리 잠기지 않습니다. 따라서 데이터를 쓰지 않을 때는 비용이 많이 드는 읽기-쓰기 트랜잭션보다 읽기 전용 트랜잭션을 사용해야 합니다.

다음 단계