데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

풀어 주다: 2023-08-17 16:31:55
앞으로
1015명이 탐색했습니다.


1. 데이터 세분화

관계형 데이터베이스 자체는 시스템 병목 현상이 발생할 가능성이 높으며 단일 시스템의 저장 용량, 연결 수 및 처리 능력이 제한됩니다. 단일 테이블의 데이터 볼륨이 1000W 또는 100G에 도달하면 쿼리 차원 수가 많아 슬레이브 데이터베이스를 추가하고 인덱스를 최적화하더라도 많은 작업을 수행하면 성능이 여전히 심각하게 저하됩니다. 이때, Segmentation을 고려하는 것이 필요합니다. Segmentation의 목적은 데이터베이스에 대한 부담을 줄이고 쿼리 시간을 단축하는 것입니다.

1000W 또는 100G는 업계 기준 값이라고 할 수 있습니다. 세부 사항은 현재 시스템 하드웨어 시설, 테이블 구조 설계 및 기타 요인에 따라 다릅니다.

데이터베이스 배포의 핵심 내용은 데이터 분할(Sharding)과 분할 후 데이터의 위치 지정 및 통합에 지나지 않습니다. 데이터 세분화란 데이터를 여러 데이터베이스에 분산시켜 저장함으로써 단일 데이터베이스에 저장되는 데이터의 양을 줄이는 것입니다. 호스트 수를 늘려 단일 데이터베이스의 성능 문제를 완화함으로써 데이터베이스 운영 향상이라는 목적을 달성합니다. 성능.

데이터 분할은 분할 유형에 따라 수직(수직) 분할과 수평(수평) 분할의 두 가지 방법으로 나눌 수 있습니다.

1 수직(수직) 분할

수직 분할에는 두 가지 일반적인 유형이 있습니다. 수직 하위 라이브러리 및 수직 하위 테이블.

수직 샤딩은 비즈니스 결합을 기반으로 서로 다른 데이터베이스에 상관 관계가 낮은 서로 다른 테이블을 저장하는 것입니다. 이 접근 방식은 대규모 시스템을 비즈니스 분류에 따라 독립적으로 나누어지는 여러 개의 소규모 시스템으로 분할하는 것과 유사합니다. "마이크로서비스 거버넌스" 접근 방식과 유사하게 각 마이크로서비스는 별도의 데이터베이스를 사용합니다. 그림과 같이:

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

수직 테이블 분할은 데이터베이스의 "열"을 기반으로 합니다. 테이블에 필드가 많은 경우 새 확장 테이블을 만들고 자주 사용되지 않거나 필드 길이가 큰 필드를 확장 테이블로 분할할 수 있습니다. . 테이블. 필드가 많은 경우(예: 큰 테이블에 필드가 100개 이상인 경우) "큰 테이블을 작은 테이블로 분할"하는 것이 개발 및 유지 관리가 더 쉽고 페이지 간 문제도 방지할 수 있습니다. MySQL의 하위 계층은 다음과 같습니다. 너무 많은 공간을 차지하는 데이터 페이지를 통해 저장하면 페이지 교차가 발생하여 추가 성능 오버헤드가 발생합니다. 또한 데이터베이스는 행 단위로 메모리에 데이터를 로드하므로 테이블의 필드 길이가 짧아지고 액세스 빈도가 높아집니다. 감소하여 데이터베이스 성능이 향상됩니다.

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

수직 분할의 장점:

1. 비즈니스 시스템 수준에서 결합을 해결하고 비즈니스를 명확하게 합니다. 2. 마이크로서비스의 거버넌스와 유사하게 계층적 관리, 유지 관리 및 모니터링도 수행할 수 있습니다. 3. 동시성이 높은 시나리오에서 수직 분할은 IO, 데이터베이스 연결 및 단일 시스템 하드웨어 리소스의 병목 현상을 어느 정도 증가시킵니다

단점:

1. 2. 분산 트랜잭션 처리의 복잡성이 감소합니다. 3. 여전히 단일 테이블의 과도한 데이터 볼륨 문제가 있습니다. (수평 분할 필요)

2. 수평 분할이 필요합니다. (수평) 분할

애플리케이션이 어려울 때 수직 분할이 아무리 세밀하거나 분할 후 데이터 행 수가 많아도 단일 데이터베이스 읽기, 쓰기 및 저장 성능 병목 현상이 발생합니다. 이때 수평 분할이 필요합니다.

수평 샤딩은 데이터베이스 내 샤딩과 하위 데이터베이스 샤딩으로 구분됩니다. 테이블 내 데이터의 고유한 논리적 관계를 기반으로 동일한 테이블이 서로 다른 조건에 따라 여러 데이터베이스 또는 여러 테이블로 분산됩니다. 데이터의 일부가 포함되므로 단일 테이블의 데이터 양이 줄어들고 분산 효과가 나타납니다. 그림과 같이

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

In-Database 샤딩은 단일 테이블의 과도한 데이터 볼륨 문제만 해결할 뿐, 테이블을 다른 머신의 라이브러리에 배포하지 않으므로 데이터 양을 줄이는 데 유용합니다. MySQL 데이터베이스에 대한 부담은 그다지 도움이 되지 않습니다. 여전히 동일한 물리적 시스템의 CPU, 메모리 및 네트워크 IO를 놓고 경쟁하는 경우 이는 하위 데이터베이스 및 하위 테이블로 해결되는 것이 가장 좋습니다.

수평 샤딩의 장점:

1. 단일 데이터베이스에서 과도한 데이터 볼륨과 높은 동시성으로 인한 성능 병목 현상이 없어 시스템 안정성과 로드 용량이 향상됩니다. 2. 애플리케이션 측 변환이 적습니다. 비즈니스 모듈을 분할해야 합니다

단점:

1. 샤드 간 트랜잭션 일관성을 보장하기 어렵습니다. 2. 데이터베이스 간 조인 쿼리 성능이 좋지 않습니다. 3. 데이터의 다중 확장이 어렵고 유지 관리량이 엄청납니다.

동일한 테이블은 여러 데이터베이스에 나타나면 각 라이브러리/테이블의 내용이 다릅니다. 몇 가지 일반적인 데이터 샤딩 규칙은 다음과 같습니다.

1. 값 범위에 따라 분할

시간 간격 또는 ID 간격에 따라. 예를 들어, 다른 달 또는 날짜의 데이터를 날짜별로 다른 라이브러리에 배포하고, userId가 1부터 9999까지인 레코드를 첫 번째 라이브러리에 할당하고, userId가 10000부터 20000까지인 레코드를 두 번째 라이브러리에 할당하는 식입니다. 어떤 의미에서는 일부 시스템에서 사용되는 "핫 및 콜드 데이터 분리", 덜 사용되는 일부 기록 데이터를 다른 라이브러리로 마이그레이션하고 비즈니스 기능에서 핫 데이터 쿼리만 제공하는 것도 유사한 관행입니다.

이것의 장점은 다음과 같습니다.

1. 단일 테이블의 크기를 제어할 수 있습니다. 2. 나중에 전체 샤딩된 클러스터를 확장하려면 노드만 추가하면 됩니다. 3. 범위 검색을 위해 샤드 필드를 사용할 때 연속 샤딩은 빠른 쿼리를 위해 샤드를 빠르게 찾아 샤드 간 쿼리 문제를 효과적으로 방지할 수 있습니다.

단점:

핫스팟 데이터가 성능 병목 현상을 발생시킵니다. 연속 샤딩에는 시간 필드별 샤딩과 같은 데이터 핫스팟이 있을 수 있습니다. 일부 샤드는 가장 최근 기간의 데이터를 저장하고 자주 읽고 쓸 수 있는 반면, 일부 샤드는 거의 쿼리되지 않는 기록 데이터를 저장합니다

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

2. 숫자 값을 기준으로 모듈로를 취합니다.

일반적으로 해시 모듈로 모드 분할 방법을 사용합니다. 예를 들어 Customer 테이블을 cusno 필드를 기준으로 4개의 라이브러리로 분할하고 나머지가 0인 라이브러리를 넣습니다. 첫 번째 라이브러리로 이동하여 나머지 1을 두 번째 라이브러리에 넣는 식으로 진행합니다. 이렇게 하면 동일한 사용자의 데이터가 동일한 데이터베이스에 분산되어 쿼리 조건에 cusno 필드가 포함된 경우 해당 데이터베이스를 명확하게 쿼리할 수 있습니다.

장점:

데이터 샤딩은 상대적으로 균일하며 핫스팟 및 동시 액세스 병목 현상이 발생하기 쉽지 않습니다.

단점:

1. 샤딩된 클러스터가 나중에 확장되면 이전 데이터를 마이그레이션해야 합니다(다음을 사용). 일관된 해시 알고리즘을 사용하면 이 문제를 더 잘 피할 수 있습니다. 2. 크로스 샤드 쿼리의 복잡한 문제에 직면하기 쉽습니다. 예를 들어 위의 예에서 자주 사용되는 쿼리 조건에 cusno가 포함되어 있지 않으면 데이터베이스를 찾을 수 없으므로 동시에 4개의 라이브러리에 쿼리를 시작한 다음 메모리의 데이터를 병합해야 합니다. , 최소 세트를 가져와서 애플리케이션에 반환하는 대신 라이브러리가 드래그가 되었습니다.

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

2. 하위 데이터베이스 및 하위 테이블로 인한 문제

하위 데이터베이스 및 하위 테이블은 단일 머신 및 단일 데이터베이스로 인한 성능 병목 현상과 압박을 효과적으로 제거할 수 있습니다. 네트워크 IO 및 하드웨어 돌파 리소스 병목 현상과 연결 수 또한 몇 가지 문제를 가져옵니다. 이러한 기술적 과제와 해당 솔루션은 아래에 설명되어 있습니다.

1. 트랜잭션 일관성 문제

분산 트랜잭션

업데이트된 콘텐츠가 동시에 다른 라이브러리에 배포되면 데이터베이스 간 트랜잭션 문제가 필연적으로 발생합니다. 크로스 샤드 트랜잭션도 분산 트랜잭션이므로 간단한 해결책은 없습니다. 일반적으로 이를 처리하는 데 "XA 프로토콜"과 "2단계 커밋"을 사용할 수 있습니다.

분산 트랜잭션은 데이터베이스 작업의 원자성을 최대한 보장할 수 있습니다. 그러나 트랜잭션을 제출할 때 여러 노드를 조정해야 하므로 트랜잭션 제출 시점이 지연되고 트랜잭션 실행 시간이 길어집니다. 이로 인해 트랜잭션이 공유 리소스에 액세스할 때 충돌이나 교착 상태가 발생할 가능성이 높아집니다. 데이터베이스 노드 수가 증가할수록 이러한 추세는 더욱 심각해질 것이며, 데이터베이스 수준에서 시스템의 수평적 확장에 걸림돌이 될 것입니다.

최종 일관성

성능 요구 사항은 높지만 일관성 요구 사항은 낮은 시스템의 경우 허용된 기간 내에 최종 일관성을 달성하는 한 시스템의 실시간 일관성이 필요하지 않은 경우가 많습니다. 보상을 사용할 수 있습니다. 트랜잭션 보상은 트랜잭션 실행 중 오류가 발생한 후 즉시 롤백하는 방식과 달리 사후 점검 및 개선 조치로, 일반적인 구현 방법으로는 데이터 조정 확인, 로그 기반 비교, 표준과의 정기적 비교 등이 있습니다. 데이터 소스 동기화 등. 거래 보상도 비즈니스 시스템과 연계하여 고려해야 합니다.

2. 크로스 노드 관련 쿼리 조인 문제

세그먼테이션 전에 시스템의 많은 목록과 세부 정보 페이지에 필요한 데이터를 SQL 조인을 통해 완성할 수 있습니다. 분할 후에는 데이터가 다른 노드에 분산될 수 있습니다. 이때 조인으로 인해 발생하는 문제는 성능을 고려하면 조인 쿼리를 사용하지 않는 것이 좋습니다.

이 문제를 해결하는 몇 가지 방법:

1) 전역 테이블

전역 테이블은 시스템의 모든 모듈이 순서대로 의존할 수 있는 일부 테이블인 "데이터 사전 테이블"로 간주될 수도 있습니다. 교차 데이터베이스 조인 쿼리를 방지하기 위해 각 데이터베이스에 이러한 유형의 테이블 복사본을 저장할 수 있습니다. 이러한 데이터는 일반적으로 거의 수정되지 않으므로 일관성 문제에 대해 걱정할 필요가 없습니다.

2) 필드 중복

시간 대신 공간을 사용하고 성능을 위해 조인 쿼리를 피하는 전형적인 안티 패러다임 디자인입니다. 예를 들어 주문 테이블이 userId를 저장할 때 userName의 중복 복사본도 저장하므로 주문 세부 정보를 쿼리할 때 "구매자 사용자 테이블"을 쿼리할 필요가 없습니다.

그러나 이 방법은 적용 가능한 시나리오가 제한되어 있으며 종속 필드가 거의 없는 상황에 더 적합합니다. 중복 필드의 데이터 일관성도 보장하기 어렵습니다. 위의 주문 테이블 예와 마찬가지로 구매자가 userName을 수정한 후 기록 주문에서 동시에 업데이트해야 합니까? 이는 실제 비즈니스 시나리오와 연계하여 고려해야 합니다.

3) 데이터 조립

시스템 수준에는 두 가지 쿼리가 있습니다. 첫 번째 쿼리의 결과는 연결된 데이터 ID를 찾는 데 중점을 두고, 연결된 데이터 ID를 얻기 위해 ID를 기반으로 두 번째 요청을 시작합니다. 데이터. 마지막으로, 획득된 데이터는 필드로 수집됩니다.

4) ER 샤딩

관계형 데이터베이스에서 먼저 테이블 간의 관계를 결정하고 관련 테이블 레코드를 동일한 샤드에 저장할 수 있다면 샤드 간 조인 문제를 피하는 것이 더 좋습니다. 1:1이나 1:n의 경우에는 대개 메인 테이블의 ID 기본키에 따라 분할됩니다. 아래 그림과 같이

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

이와 같이 Data Node1의 주문 주문 테이블과 orderdetail 주문 세부 정보 테이블은 orderId를 통한 쿼리와 부분적으로 연관될 수 있으며, Data Node2에서도 마찬가지입니다.

3. 크로스 노드 페이징, 정렬 및 기능 문제

여러 노드와 여러 데이터베이스에 걸쳐 쿼리할 때 페이징 제한, 정렬별 순서 등의 문제가 발생할 수 있습니다. 페이징은 지정된 필드에 따라 정렬되어야 합니다. 정렬 필드가 샤딩 필드인 경우 샤딩 규칙을 통해 지정된 샤드를 찾는 것이 더 쉽고, 정렬 필드가 샤딩 필드가 아닌 경우에는 더 복잡해집니다. 데이터는 먼저 다른 샤드 노드에서 정렬 및 반환되어야 하며, 그런 다음 다른 샤드에서 반환된 결과 집합을 다시 요약 및 정렬하여 최종적으로 사용자에게 반환해야 합니다. 사진에 표시된 대로:

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

위 사진은 첫 페이지의 데이터만 가져왔으며 성능에는 큰 영향을 미치지 않습니다. 그러나 획득한 페이지 수가 매우 많으면 각 샤드 노드의 데이터가 무작위일 수 있으므로 상황은 훨씬 더 복잡해집니다. 정렬의 정확성을 위해 모든 노드의 처음 N 페이지의 데이터를 정렬해야 합니다. 마지막으로 전체 정렬 작업을 수행하면 CPU와 메모리 리소스가 소모되므로 페이지 수가 많을수록 시스템 성능이 저하됩니다.

Max, Min, Sum, Count 등의 함수를 사용하여 계산할 경우 먼저 각 샤드에서 해당 함수를 실행한 다음 각 샤드의 결과 세트를 요약하고 다시 계산하면 마지막으로 결과가 반환됩니다. 그림과 같이:

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

4. 전역 기본 키 회피 문제

하위 데이터베이스와 하위 테이블 환경에서는 테이블의 데이터가 동시에 다른 데이터베이스에 존재하기 때문에 일반적인 자동- 기본 키 값의 증가는 쓸모가 없으며 특정 파티션 데이터베이스에서 생성된 ID는 전역적으로 고유하다고 보장할 수 없습니다. 따라서 데이터베이스 전체에서 기본 키가 중복되는 것을 방지하려면 전역 기본 키를 별도로 설계해야 합니다. 몇 가지 일반적인 기본 키 생성 전략이 있습니다.

1) UUID

UUID 표준 형식에는 32개의 16진수 숫자가 포함되어 있으며 5개의 세그먼트로 나누어지고 8-4-4-4-12 형식의 36개 문자가 포함됩니다. : 550e8400-e29b-41d4-a716-446655440000

UUID는 가장 간단한 솔루션인 기본 키로 로컬에서 생성되며 성능이 뛰어나고 네트워크 시간 소모가 없습니다. 하지만 단점도 분명합니다. UUID는 매우 길기 때문에 저장 공간을 많이 차지합니다. 또한 InnoDB에서는 기본 키로 인덱스를 생성하고 쿼리할 때 성능 문제가 발생합니다. UUID가 무질서하면 데이터 위치가 자주 변경되어 페이징이 발생합니다.

2) 데이터베이스와 결합하여 기본 키 ID 테이블 유지

데이터베이스에 시퀀스 테이블 생성:

CREATE TABLE `sequence` (    `id` bigint(20) unsigned NOT NULL auto_increment,    `stub` char(1) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `stub` (`stub`)  ) ENGINE=MyISAM;
로그인 후 복사

스텁 필드는 고유 인덱스로 설정됩니다. 시퀀스 테이블에서 동시에 여러 테이블에 사용할 수 있습니다. 시퀀스 테이블의 내용은 다음과 같습니다.

+-------------------+------+ | id                | stub |  +-------------------+------+ | 72157623227190423 |    a |  +-------------------+------+
로그인 후 복사

더 높은 성능을 위해 InnoDB 대신 MyISAM 스토리지 엔진을 사용합니다. MyISAM은 테이블 수준 잠금을 사용하고 테이블에 대한 읽기 및 쓰기는 직렬이므로 동시성 중에 동일한 ID 값을 두 번 읽는 것에 대해 걱정할 필요가 없습니다.

전역적으로 고유한 64비트 ID가 필요한 경우 다음을 실행하세요.

REPLACE INTO sequence (stub) VALUES ('a'); SELECT LAST_INSERT_ID();
로그인 후 복사

이 두 문은 연결 수준에 있습니다. 방금 삽입된 새 ID를 얻으려면 select lastinsertid()가 동일한 데이터베이스 연결 아래에 있어야 합니다.

삽입 대신 교체를 사용하면 지나치게 많은 수의 테이블 행을 방지하고 정기적인 청소가 필요하지 않다는 장점이 있습니다.

이 솔루션은 비교적 간단하지만 단점도 분명합니다. 단일 문제 지점이 있고 DB에 대한 의존도가 높기 때문에 DB가 비정상일 경우 전체 시스템을 사용할 수 없습니다. 마스터-슬레이브를 구성하면 가용성을 높일 수 있지만, 마스터 데이터베이스 장애 및 마스터-슬레이브 전환이 발생하는 경우 특수한 상황에서는 데이터 일관성을 보장하기 어렵습니다. 또한 성능 병목 현상은 단일 MySQL의 읽기 및 쓰기 성능으로 제한됩니다.

Flickr 팀에서 사용하는 기본 키 생성 전략은 위의 시퀀스 테이블 솔루션과 유사하지만 단일 지점 및 성능 병목 현상 문제를 더 잘 해결합니다.

이 솔루션의 전체적인 아이디어는 2개 이상의 글로벌 ID 생성 서버를 구축하고, 각 서버에 하나의 데이터베이스만 배포하며, 각 데이터베이스에는 현재 글로벌 ID를 기록하는 시퀀스 테이블이 있다는 것입니다. 표의 ID 증가 단계 크기는 라이브러리 수이며, 시작 값은 순서대로 시차를 두어 ID 생성을 각 데이터베이스에 해싱할 수 있습니다. 아래 그림과 같이:

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

ID는 두 개의 데이터베이스 서버에서 생성되며 서로 다른 auto_increment 값이 설정됩니다. 첫 번째 시퀀스의 시작 값은 1이고 각 단계마다 2씩 증가합니다. 다른 시퀀스의 시작 값은 2이며 각 단계마다 2씩 증가합니다. 결과적으로 첫 번째 스테이션에서 생성된 ID는 모두 홀수(1, 3, 5, 7...)이고, 두 번째 스테이션에서 생성된 ID는 모두 짝수(2, 4, 6, 8..)이다. .).

이 솔루션은 ID 생성 압력을 두 시스템에 균등하게 분배합니다. 또한 첫 번째 시스템에서 오류가 발생하면 자동으로 두 번째 시스템으로 전환하여 ID를 얻을 수 있습니다. 그러나 다음과 같은 단점이 있습니다. 시스템에 기계를 추가할 때 수평 확장이 더 복잡하며, ID를 얻을 때마다 DB를 읽고 써야 하며, 여전히 DB에 대한 부담이 매우 높으며 성능이 저하될 수 있습니다. 힙 머신에 의존해야만 개선될 수 있습니다.

Flickr의 솔루션을 기반으로 계속 최적화하고 배치 방법을 사용하여 데이터베이스의 쓰기 부담을 줄일 수 있습니다. 매번 다양한 ID 번호를 얻은 다음 사용 후 데이터베이스로 이동하여 이를 얻을 수 있습니다. 데이터베이스에 대한 압박. 아래 그림과 같이

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

여전히 두 개의 DB를 사용하여 가용성을 보장하며 현재 최대 ID만 데이터베이스에 저장됩니다. ID 생성 서비스는 매번 6개의 ID를 일괄적으로 가져오고 먼저 maxid를 5로 변경합니다. 애플리케이션이 ID 생성 서비스에 액세스하면 데이터베이스에 액세스할 필요가 없으며 ID 0~5가 숫자 세그먼트에서 순차적으로 전달됩니다. 은닉처. 해당 ID가 발급된 후 maxid를 11로 변경하면 다음번에는 ID 6~11까지 배포 가능합니다. 결과적으로 데이터베이스에 가해지는 부담은 원본의 1/6로 줄어듭니다.

3) Snowflake 분산 자체 증가 ID 알고리즘

Twitter의 눈송이 알고리즘은 분산 시스템이 64비트 긴 숫자를 생성하여 글로벌 ID를 생성해야 하는 필요성을 해결합니다. 구성 요소:

첫 번째 숫자는 사용되지 않습니다.

다음 41비트는 밀리초 시간이고, 41비트의 길이는 69년의 시간을 나타낼 수 있습니다.

5자리 datacenterId, 5자리 WorkerId. 10비트 길이는 최대 1024개의 노드 배포를 지원합니다

마지막 12비트는 밀리초 이내의 계산이며, 12비트 계산 시퀀스 번호는 각 노드가 밀리초당 4096개의 ID 시퀀스를 생성하도록 지원합니다

데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?

장점은 밀리초 수가 높고 생성된 ID가 일반적으로 시간 추세에 따라 증가하며 타사 시스템에 의존하지 않으며 이론적으로 QPS가 약 409.6w입니다. /s(1000*2^12) 및 전체 배포 시스템에는 ID 충돌이 없으며 자체 비즈니스에 따라 비트를 유연하게 할당할 수 있습니다.

단점은 기계 시계에 크게 의존한다는 점입니다. 시계를 뒤로 설정하면 중복 ID가 생성될 수 있습니다.

요약하자면

데이터베이스와 Snowflake의 고유 ID 솔루션을 결합하면 업계의 보다 성숙한 솔루션인 Leaf - Meituan-Dianping의 분산 ID 생성 시스템을 참조할 수 있으며 고가용성, 재해 복구 및 분산 배포. 시계 및 기타 문제.

5. 데이터 마이그레이션 및 확장 문제

비즈니스가 빠르게 발전하고 성능 및 스토리지 병목 현상에 직면할 때 샤딩 설계를 고려해야 합니다. 이때 이력 데이터 마이그레이션 문제를 고려하는 것은 불가피합니다. 일반적인 접근 방식은 먼저 기록 데이터를 읽은 다음 지정된 샤딩 규칙에 따라 각 샤드 노드에 데이터를 쓰는 것입니다. 또한, 현재 데이터 볼륨과 QPS, 비즈니스 개발 속도를 기반으로 용량 계획을 수행하여 필요한 샤드 수를 대략적으로 계산해야 합니다(일반적으로 단일 테이블의 데이터 볼륨을 단일 샤드는 1000W를 초과하지 않습니다)

수치 범위 분석을 사용하는 경우 샤드의 경우 노드를 추가하기만 하면 확장할 수 있으며 샤드 데이터를 마이그레이션할 필요가 없습니다. 수치 모듈로 샤딩을 사용하는 경우 향후 확장 문제를 고려하는 것이 상대적으로 번거로울 것입니다.

3. 세분화를 고려해야 하는 경우

데이터 세분화를 고려해야 하는 경우에 대해 이야기해 보겠습니다.

1. 가능하면 분할하지 마세요.

모든 테이블을 분할할 필요는 없으며 주로 데이터 증가율에 따라 다릅니다. 세분화는 데이터 저장 및 쿼리를 수행하는 것 외에도 비즈니스의 요구 사항을 더 잘 실현하는 데 도움이 되는 중요한 작업 중 하나입니다.

"과도한 설계" 및 "조기 최적화"를 피하기 위해 꼭 필요한 경우가 아니면 하위 데이터베이스 및 하위 테이블의 트릭을 사용하지 마세요. 데이터베이스와 테이블을 분할하기 전에 단지 분할만을 위해 분할하지 마십시오. 하드웨어 업그레이드, 네트워크 업그레이드, 읽기 및 쓰기 분리, 인덱스 최적화 등 먼저 할 수 있는 일을 최선을 다해 수행하십시오. 데이터 양이 단일 테이블의 병목 현상에 도달하면 데이터베이스와 테이블을 샤딩하는 것을 고려하세요.

2. 데이터 양이 너무 많아 정상적인 운영 및 유지 관리가 비즈니스 액세스에 영향을 미칩니다.

여기서 언급된 운영 및 유지 관리는 다음을 의미합니다.

1) 데이터베이스 백업의 경우 단일 테이블이 너무 큰 경우 백업 및 네트워크 IO 중에는 많은 양의 디스크 IO가 필요합니다. 예를 들어, 1T의 데이터가 네트워크를 통해 전송되고 50MB를 차지한다면 전송을 완료하는 데 20,000초가 소요됩니다. 전체 프로세스의 위험은 상대적으로 높습니다.

2) 큰 테이블에 DDL 수정을 하면 MySQL은 전체 테이블을 잠그십시오. 이 기간 동안 비즈니스는 이 테이블에 액세스할 수 없으므로 큰 영향을 미칩니다. pt-online-schema-change를 사용하면 사용 중에 트리거와 섀도우 테이블이 생성되는데 이 역시 시간이 오래 걸린다. 이 작업 중에는 위험 시간으로 계산됩니다. 데이터 테이블을 분할하고 총 금액을 줄이면 이러한 위험을 줄이는 데 도움이 될 수 있습니다.

3)大表会经常访问与更新,就更有可能出现锁等待。将数据切分,用空间换时间,变相降低访问压力

3、随着业务发展,需要对某些字段垂直拆分

举个例子,假如项目一开始设计的用户表如下:

id   bigint #用户的IDname varchar #用户的名字last_login_time datetime #最近登录时间personal_info text #私人信息.....  #其他信息字段
로그인 후 복사

在项目初始阶段,这种设计是满足简单的业务需求的,也方便快速迭代开发。而当业务快速发展时,用户量从10w激增到10亿,用户非常的活跃,每次登录会更新 lastloginname 字段,使得 user 表被不断update,压力很大。而其他字段:id, name, personalinfo 是不变的或很少更新的,此时在业务角度,就要将 lastlogintime 拆分出去,新建一个 usertime 表。

personalinfo 属性是更新和查询频率较低的,并且text字段占据了太多的空间。这时候,就要对此垂直拆分出 userext 表了。

4、数据量快速增长

随着业务的快速发展,单表中的数据量会持续增长,当性能接近瓶颈时,就需要考虑水平切分,做分库分表了。此时一定要选择合适的切分规则,提前预估好数据容量

5、安全性和可用性

鸡蛋不要放在一个篮子里。在业务层面上垂直切分,将不相关的业务的数据库分隔,因为每个业务的数据量、访问量都不同,不能因为一个业务把数据库搞挂而牵连到其他业务。利用水平切分,当一个数据库出现问题时,不会影响到100%的用户,每个库只承担业务的一部分数据,这样整体的可用性就能提高。

四. 案例分析

1、用户中心业务场景

用户中心是一个非常常见的业务,主要提供用户注册、登录、查询/修改等功能,其核心表为:

User(uid, login_name, passwd, sex, age, nickname)
uid为用户ID,  主键login_name, passwd, sex, age, nickname,  用户属性
로그인 후 복사

任何脱离业务的架构设计都是耍流氓,在进行分库分表前,需要对业务场景需求进行梳理:

用户侧:前台访问,访问量较大,需要保证高可用和高一致性。主要有两类需求:

1. 사용자 로그인: login_name/phone/email을 통해 사용자 정보 조회, 요청의 1%가 이 유형에 속함 2. 사용자 정보 조회: 로그인 후 uid를 통해 사용자 정보 조회, 요청의 99%가 이 유형에 속함작업 side : 백엔드 액세스, 운영 요구 사항 지원, 연령, 성별, 로그인 시간, 등록 시간 등에 따라 페이징 쿼리를 수행합니다. 이는 액세스량이 적고 가용성 및 일관성에 대한 요구 사항이 낮은 내부 시스템입니다.

2. 수평 분할 방법

데이터의 양이 점점 많아지면 데이터베이스를 수평으로 분할해야 합니다. 위에서 설명한 분할 방법에는 "수치 모듈로 기준"이 있습니다. ".

"숫자 범위에 따라": 기본 키 uid를 기준으로 uid 범위에 따라 데이터를 여러 데이터베이스에 수평으로 나눕니다. 예를 들어 user-db1은 uid 범위가 0~1000w인 데이터를 저장하고 user-db2는 uid 범위가 1000w~2000wuid인 데이터를 저장합니다.

장점 : 확장이 간단하고, 용량이 부족하면 DB를 새로 추가하면 됩니다.

단점은 : 요청량이 고르지 않다는 것입니다. 일반적으로 새로 등록된 사용자가 더 활동적이므로 새로운 user-db2가 user-db1보다 로드가 높아져 서버 사용률이 불균형하게 됩니다

"에 따르면 숫자 값 모듈 ": 기본 키 uid도 분할 기준으로 사용되며 데이터는 uid 모듈로 값을 기준으로 여러 데이터베이스로 수평으로 분할됩니다. 예를 들어, user-db1은 uid 데이터 모듈로 1을 저장하고, user-db2는 uid 데이터 모듈로 0을 저장합니다.

장점은 : 데이터량과 요청량이 고르게 분포되어 있다.

단점은 : 용량이 부족할 경우 새로운 DB를 추가하려면 재해시가 필요하다. 데이터의 원활한 마이그레이션을 고려해야 합니다.

3. Non-uid 쿼리 방법

수평 분할 후 uid별 쿼리 요구를 잘 충족할 수 있으며 특정 데이터베이스로 직접 라우팅될 수 있습니다. login_name과 같이 UID가 아닌 쿼리의 경우 어떤 라이브러리에 액세스해야 하는지 알 수 없으며, 이 경우 모든 라이브러리를 순회해야 하므로 성능이 많이 저하됩니다.

사용자 측에서는 "uid가 아닌 속성에서 uid로의 매핑 관계 설정" 솔루션을 채택할 수 있고, 운영 측에서는 "프런트엔드와 백엔드 분리" 솔루션을 채택할 수 있습니다.

3.1 비-uid 속성에서 uid로 매핑 관계 설정

1) 매핑 관계

예: loginname은 데이터베이스에 직접 위치할 수 없으며 login_name→uid的映射关系 인덱스 테이블에 저장할 수 있습니다. 또는 캐시. loginname에 접근할 때 먼저 매핑 테이블을 통해 login_name에 해당하는 uid를 쿼리한 후 uid를 통해 특정 라이브러리를 찾습니다.

매핑 테이블은 열이 2개뿐이므로 많은 양의 데이터를 담을 수 있습니다. 데이터 양이 너무 많으면 매핑 테이블을 가로로 분할할 수도 있습니다. 이러한 유형의 kv 형식 인덱스 구조는 캐시를 사용하여 쿼리 성능을 최적화할 수 있으며 매핑 관계는 자주 변경되지 않으며 캐시 적중률이 매우 높습니다.

2) Gene method

Breaking gene: 라이브러리를 uid를 통해 8개의 라이브러리로 나누고 uid%8을 사용하여 라우팅을 수행하면 이때 uid의 마지막 3비트가 이 User 데이터 행이 어디에 속하는지 결정합니다. 어떤 라이브러리가 들어있으면 이 3비트는 하위 라이브러리 유전자로 간주될 수 있습니다.

위의 매핑 관계 방법에는 매핑 테이블의 추가 저장이 필요합니다. UID가 아닌 필드로 쿼리할 경우 추가 데이터베이스 또는 캐시 액세스가 필요합니다. 중복된 저장 및 쿼리를 제거하려면 f 함수를 사용하여 로그인 이름 유전자를 uid의 하위 라이브러리 유전자로 사용할 수 있습니다. uid 생성 시 위에서 설명한 분산 고유 ID 생성 방식을 참조하고 마지막 3비트 값 = f(loginname)을 더합니다. loginname을 쿼리할 때 특정 라이브러리를 찾으려면 f(loginname)%8 값만 계산하면 됩니다. 그러나 이를 위해서는 사전에 용량 계획이 필요합니다. 즉, 향후 몇 년 동안 데이터 볼륨을 몇 개의 데이터베이스로 나누어야 하는지 예측하고 특정 비트 수의 데이터베이스 유전자를 예약해야 합니다. 3.2. 프론트 데스크와 백 데스크의 분리에 관한 질문.

작업 측면에서는 일괄 페이징과 다양한 조건을 포함하는 쿼리가 많습니다. 이러한 쿼리는 많은 양의 계산이 필요하고, 많은 양의 데이터를 반환하며, 데이터베이스의 높은 성능을 소모합니다. 이때 동일한 배치의 서비스나 데이터베이스를 사용자 측에서 공유하는 경우 적은 수의 백그라운드 요청이 많은 양의 데이터베이스 리소스를 점유하여 사용자 측 액세스 성능 저하 또는 시간 초과가 발생할 수 있습니다.
이러한 비즈니스에는 "프런트엔드와 백엔드 분리" 솔루션을 채택하는 것이 가장 좋습니다. 운영측의 백엔드 비즈니스는 프런트엔드 비즈니스와의 결합을 해결하기 위해 독립적인 서비스와 DB를 추출합니다. 체계. 운영측에서는 가용성과 일관성에 대한 요구사항이 높지 않기 때문에 실시간 라이브러리에 접근하지 않고 binlog를 통해 비동기적으로 데이터를 운영 라이브러리에 동기화하여 접근하는 것이 가능하다. 데이터의 양이 많은 경우 ES 검색 엔진이나 Hive를 사용하여 백그라운드에서 복잡한 쿼리 방법을 충족할 수도 있습니다.

5. 하위 데이터베이스 및 하위 테이블 미들웨어 지원

거인의 어깨에 서는 것은 많은 노력을 절약할 수 있습니다. 현재 하위 데이터베이스 및 하위에 대한 비교적 성숙한 오픈 소스 솔루션이 있습니다. -테이블:

  • sharding-jdbc(Dangdang)
  • TSharding(Mogujie)
  • Atlas(Qihoo 360)
  • Cobar(Alibaba)
  • My CAT(Cobar 기반)
  • Oceanus( 58.com)
  • Vitess(구글)

위 내용은 데이터베이스는 데이터베이스와 테이블로 구분됩니다. 나누는 방법?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:Java后端技术全栈
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿