LLM WikiAccess-protected knowledge portal

WIKI

TiDB 8.5.7: CPU-aware hotspot scheduling과 partial index로 분산 OLTP의 숨은 낭비를 줄이는 방식

왜 지금 봐야 하나 TiDB 8.5.7 은 2026 07 09에 나온 패치 릴리스다. 그런데 이번 릴리스는 일반적인 버그 수정판으로 보기 어렵다. 읽기 hotspot을 어떤 신호로 옮길지 , 어떤 행만 인덱싱할지 , 누가 연결 슬롯을 얼마나 가져갈지 라는 세 가지 운영 경계를 함께 바꿨기 때문이다. 기존 TiDB 운영에서 자주 보이는 낭비는 대체로 세 종류다. QPS와 byte throughput은 비슷한데 특정 TiKV만 C

경로human/study/content/database-frontier/48-tidb-8-5-7-cpu-hotspot-partial-indexes-resource-guards.md
카테고리Study
태그#guards #hotspot #indexes #mysql #partial #resource #study

왜 지금 봐야 하나

TiDB 8.5.7은 2026-07-09에 나온 패치 릴리스다. 그런데 이번 릴리스는 일반적인 버그 수정판으로 보기 어렵다. 읽기 hotspot을 어떤 신호로 옮길지, 어떤 행만 인덱싱할지, 누가 연결 슬롯을 얼마나 가져갈지라는 세 가지 운영 경계를 함께 바꿨기 때문이다.

기존 TiDB 운영에서 자주 보이는 낭비는 대체로 세 종류다.

TiDB 8.5.7은 이 세 문제에 각각 CPU-aware hot Region scheduling, partial index, max_user_connections를 내놨다. 서로 다른 기능처럼 보이지만, 운영자 관점에서는 모두 “보이지 않던 낭비를 제어면으로 끌어올린 것”이라는 공통점이 있다.


TiDB 8.5.7에서 새로 열린 제어면

TiDB 8.5.7이 줄이려는 세 가지 낭비 1) 연결 경계 클라이언트 / 서비스 계정 → TiDB 인스턴스별 연결 슬롯 소비 new: max_user_connections 2) SQL / 인덱스 경계 모든 행에 보조 인덱스를 유지할지, 조건을 만족하는 행만 인덱싱할지 new: partial index 3) 스케줄링 경계 hot Region을 QPS/byte만 볼지, CPU까지 포함해 옮길지 new: CPU-aware scheduling TiDB 인스턴스 연결 수락 / 거절 세션별 자원 점유 Optimizer + Index Writer predicate를 만족하는 행만 보조 인덱스 유지 PD hot Region 재배치 판단 TiKV store heartbeat flow_cpu 보고 운영자가 실제로 보게 되는 변화 읽기 hotspot 판단에는 cpu-read-rate / flow_cpu가 추가되고, 인덱스는 조건부로만 유지되며, 사용자별 연결 상한이 TiDB 인스턴스 경계에 생긴다. 즉, 같은 하드웨어에서도 “어디서 새고 있는지”를 더 좁은 경계에서 제어할 수 있게 된다.
TiDB 8.5.7: CPU hotspot, partial index, 사용자별 연결 제한이 각각 어느 경계에서 낭비를 줄이는지

1. CPU-aware hot Region scheduling: QPS가 아니라 CPU로 읽기 hotspot을 옮긴다

TiDB의 기존 hot Region scheduler는 읽기 hotspot을 주로 query ratebyte throughput으로 판단했다. 이 방식은 네트워크와 요청 수만 비슷하면 균형처럼 보인다. 하지만 실제 운영에서는 다음 같은 경우가 자주 생긴다.

이때는 “트래픽은 균형인데 CPU는 한쪽만 먼저 죽는” 이상한 상태가 나온다. 8.5.7의 변화는 이 지점을 정확히 겨냥한다. TiKV가 hot Region의 read CPU 사용량을 store heartbeat로 보고하고, PD가 그 값을 read hotspot scheduling의 우선순위로 사용할 수 있게 됐다.

실제로 확인해야 할 제어면은 두 곳이다.

  1. pd-ctl hot read / hot history 결과에 flow_cpu가 보이는지
  2. pd-ctl hot storescheduler config balance-hot-region-scheduler에서 CPU 기반 설정이 보이는지
tiup ctl:v8.5.7 pd -u http://<pd-host>:2379 hot store
tiup ctl:v8.5.7 pd -u http://<pd-host>:2379 scheduler config balance-hot-region-scheduler

문서 기준으로, CPU 보고가 가능한 클러스터에서는 balance-hot-region-scheduler의 기본 read-prioritiescpu,byte로 잡힌다. CPU 보고가 되지 않으면 PD는 자동으로 query,byte, 더 좁게는 byte,key로 되돌아간다. 즉, 업그레이드만 했다고 항상 CPU-aware scheduling이 켜지는 것이 아니라, TiKV가 CPU 신호를 정상 보고하는지까지 확인해야 한다.

운영자가 같이 봐야 하는 설정은 다음 두 개다.

이 기능의 의미는 “load-based replica read가 필요 없어졌다”가 아니다. load-based replica read는 읽기 요청을 다른 replica로 우회시키는 질의 경로 제어이고, CPU-aware hot Region scheduling은 Region 자체를 어느 TiKV에 둘지 바꾸는 배치 제어다. 둘은 같은 층위의 기능이 아니다.

정리하면 8.5.7의 이 기능은 read hotspot을 QPS/throughput 문제에서 CPU 편향 문제까지 확장해 다룬다는 점이 핵심이다.


2. Partial index: 전체 테이블이 아니라 필요한 행만 인덱싱한다

8.5.7의 SQL 레이어 변화 중 가장 실무적인 것은 partial index다. TiDB는 이제 CREATE INDEX ... WHERE ... 또는 ALTER TABLE ... ADD INDEX ... WHERE ... 형태로, 조건을 만족하는 행에만 보조 인덱스를 생성할 수 있다.

CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  status VARCHAR(20),
  created_at DATETIME,
  deleted_at DATETIME
);

CREATE INDEX idx_queued_orders_created_at
  ON orders (created_at)
  WHERE status = 'queued';

이 기능이 필요한 상황은 분명하다.

TiDB 문서가 강조하는 중요한 조건은 하나다. 옵티마이저는 질의 조건이 partial index의 predicate와 일치하거나, 그 predicate를 함의할 때만 이 인덱스를 선택한다.

즉, 아래처럼 쿼리 필터와 인덱스 predicate를 의도적으로 맞춰 설계해야 한다.

현재 8.5.7에서 predicate가 지원하는 범위도 넓지 않다. 공식 release notes 기준으로 partial index predicate는 다음 정도만 안정적으로 지원한다.

이 제한은 오히려 운영자에게 명확한 메시지를 준다. 이번 릴리스의 partial index는 범용 논리식 엔진이 아니라, 희소 조건을 빠르게 잘라내는 1차 도구에 가깝다. 즉, soft-delete, 상태 플래그, 큰 점수 구간, 비어 있지 않은 큐 같은 패턴에서 먼저 써보는 편이 맞다.

실제 도입 판단은 세 가지를 같이 봐야 한다.

  1. 인덱스 크기 감소: 전체 secondary index 대비 얼마나 줄었는지
  2. 쓰기 비용 감소: predicate 밖의 행이 많은 만큼 INSERT/UPDATE/DELETE 부담이 실제로 내려가는지
  3. 플랜 선택 안정성: EXPLAIN에서 partial index가 예상한 쿼리에 꾸준히 선택되는지
EXPLAIN SELECT *
FROM orders
WHERE status = 'queued'
ORDER BY created_at;

운영적으로는 “partial index를 만들었으니 무조건 빨라진다”보다 predicate가 정말 희소한가, 질의가 그 predicate를 일관되게 따르는가가 더 중요하다. 조건이 넓거나 애플리케이션 필터가 자주 흔들리면, 이 기능은 기대만큼의 저장 공간 절감이나 플랜 안정성을 주지 못한다.


3. max_user_connections: noisy tenant를 인스턴스 경계에서 자른다

세 번째 변화는 화려하지 않지만 공유 클러스터 운영에서는 매우 현실적이다. 8.5.7부터 TiDB는 한 사용자가 TiDB 인스턴스 하나에 맺을 수 있는 최대 연결 수max_user_connections로 제한할 수 있다.

공식 문서 기준 핵심 속성은 다음과 같다.

SET GLOBAL max_user_connections = 200;

CREATE USER 'etl_worker'@'%' IDENTIFIED BY '***'
  WITH MAX_USER_CONNECTIONS 30;

ALTER USER 'readonly_api'@'%'
  WITH MAX_USER_CONNECTIONS 20;

중요한 경계는 이 제한이 클러스터 전체가 아니라 “TiDB server instance 하나” 기준이라는 점이다. TiDB 인스턴스가 4대라면, 로드밸런서 분산 상태에 따라 같은 계정이 총 120개 연결을 가질 수도 있다. 따라서 이 기능은 “전사 공통 사용자 총량 규제”보다 다음 상황에 더 맞는다.

TiDB release notes는 이 기능이 한 사용자의 과도한 token consumption이 다른 요청의 응답을 밀어내는 상황을 막는 데 유용하다고 설명한다. 운영자 입장에서는 “쿼리 느림”이 아니라 입구에서 세션 폭주를 자르는 단순한 가드레일이 추가된 셈이다.


4. 세 기능을 같이 보면: 8.5.7은 "낭비가 새는 위치"를 더 잘 고른다

이번 릴리스의 세 기능을 따로 보면 산만해 보일 수 있다. 하지만 운영면에서 묶어 보면 분명한 그림이 나온다.

제어 대상이전 판단 기준8.5.7 이후운영자가 얻는 것
읽기 hotspotquery rate, byte throughput 위주CPU까지 포함한 Region 재배치CPU만 먼저 죽는 불균형을 더 빨리 교정
보조 인덱스전체 행 대상 full indexpredicate를 만족하는 행만 index인덱스 저장 공간과 DML 유지 비용 절감
연결 admission인스턴스 전체 max_connections 위주사용자별 per-instance capnoisy user를 입구에서 차단

즉, 8.5.7은 성능을 마술처럼 올리는 릴리스가 아니다. 대신 CPU, 인덱스, 연결 수라는 서로 다른 낭비를 각각 더 가까운 경계에서 자르게 하는 릴리스다. 이런 변화는 화려한 벤치마크보다 운영 런북을 더 많이 바꾼다.


도입 순서: 한 번에 다 켜지 말고, 세 층을 따로 검증한다

1) CPU-aware scheduling

2) Partial index

3) max_user_connections


어떤 팀이 먼저 써볼 만한가

다음과 같은 팀이라면 8.5.7의 가치가 바로 보인다.

반대로, 작은 단일 서비스에서 테이블도 작고 TiDB 인스턴스 수가 적다면 이번 릴리스의 체감은 제한적일 수 있다. 이 경우 partial index 하나만 먼저 써보는 편이 보통 가장 비용이 낮다.


Open question


References