

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 스트림 리샤딩
<a name="kinesis-using-sdk-java-resharding"></a>

**중요**  
[UpdateShardCount](https://docs.aws.amazon.com/kinesis/latest/APIReference/API_UpdateShardCount.html) API를 사용하여 스트림을 리샤딩할 수 있습니다. 그렇지 않은 경우 여기에 설명된 대로 분할 및 병합을 계속 수행할 수 있습니다.

Amazon Kinesis Data Streams는 스트림을 통과하는 데이터 흐름 속도의 변화에 맞게 스트림의 샤드 수를 조정할 수 있는 **리샤딩을 지원합니다. 리샤딩은 고급 작업으로 간주됩니다. Kinesis Data Streams를 처음 사용하는 경우 Kinesis Data Streams의 다른 모든 측면을 숙지한 후 이 주제로 돌아오세요.

샤드 분할과 샤드 병합이라는 두 가지 유형의 리샤딩 작업이 있습니다. 샤드 분할에서는 단일 샤드를 샤드 두 개로 나눕니다. 샤드 병합에서는 샤드 두 개를 단일 샤드로 결합합니다. 리샤딩은 단일 작업으로 두 개를 초과하는 샤드로 분할할 수 없으며, 단일 작업으로 두 개를 초과하는 샤드를 병합할 수 없다는 의미에서 항상 *쌍으로* 이루어집니다. 리샤딩 작업이 실행되는 샤드 또는 샤드 쌍을 *상위* 샤드라고 합니다. 리샤딩 작업으로 인해 발생하는 샤드 또는 샤드 쌍을 *하위* 샤드라고 합니다.

분할로 인해 스트림에서 샤드 수가 증가하므로 스트림의 데이터 용량이 증가합니다. 샤드 수를 기준으로 요금이 부과되므로 분할하면 스트림의 비용이 증가합니다. 마찬가지로 병합하면 스트림의 샤드 수가 줄어들어 스트림의 데이터 용량과 비용이 감소합니다.

일반적으로 리샤딩은 생산자(넣기) 애플리케이션 및 소비자(가져오기) 애플리케이션과 구별되는 관리자 애플리케이션에 의해 수행됩니다. 이러한 관리자 애플리케이션은 Amazon CloudWatch에서 제공된 지표 또는 생산자와 소비자에서 수집된 지표에 따라 스트림의 전체 성능을 모니터링합니다. 또한 소비자 및 생산자는 일반적으로 리샤딩에 사용되는 API에 대한 액세스 권한이 필요하지 않으므로, 관리자 애플리케이션은 소비자 또는 생산자보다 광범위한 IAM 권한이 있어야 합니다. Kinesis Data Streams의 IAM 권한에 대한 자세한 내용은 [IAM을 사용하여 Amazon Kinesis Data Streams 리소스에 대한 액세스 제어](controlling-access.md) 섹션을 참조하세요.

리샤딩에 대한 자세한 내용은 [Kinesis Data Streams에서 열린 샤드 수를 변경하려면 어떻게 해야 합니까?](https://aws.amazon.com/premiumsupport/knowledge-center/kinesis-data-streams-open-shards/)를 참조하세요.

**Topics**
+ [리샤딩에 대한 전략 결정](kinesis-using-sdk-java-resharding-strategies.md)
+ [샤드 분할](kinesis-using-sdk-java-resharding-split.md)
+ [두 개의 샤드 병합](kinesis-using-sdk-java-resharding-merge.md)
+ [리샤딩 작업 완료](kinesis-using-sdk-java-after-resharding.md)

# 리샤딩에 대한 전략 결정
<a name="kinesis-using-sdk-java-resharding-strategies"></a>

Amazon Kinesis Data Streams의 리샤딩 목적은 데이터 흐름 속도의 변화에 따라 스트림을 조정할 수 있도록 하는 것입니다. 스트림의 용량(및 비용)을 늘리려면 샤드를 분할합니다. 스트림의 비용(및 용량)을 줄이려면 샤드를 병합합니다.

 리샤딩에 대한 한 가지 접근 방식은 스트림의 모든 샤드를 분할하는 것입니다. 이렇게 하면 스트림 용량이 2배가 됩니다. 그러나 이렇게 하면 실제로 필요한 용량보다 더 많은 추가 용량을 제공하므로 불필요한 비용이 발생합니다.

또한 지표를 사용하여 *핫* 또는 *콜드* 샤드, 즉 예상보다 더 많은 데이터 또는 더 적은 데이터를 받는 샤드를 결정할 수 있습니다. 그런 다음 선택적으로 핫 샤드를 분할하여 해당 샤드를 대상으로 지정하는 해시 키에 대한 용량을 늘릴 수 있습니다. 마찬가지로 콜드 샤드를 병합하여 사용하지 않은 용량을 유용하게 사용할 수 있습니다.

Kinesis Data Streams가 게시하는 Amazon CloudWatch 지표에서 스트림에 대한 몇 가지 성능 데이터를 얻을 수 있습니다. 그러나 스트림에 대한 고유한 측정치 중 일부를 수집할 수도 있습니다. 한 가지 접근 방법은 데이터 레코드에 대한 파티션 키에 의해 생성된 해시 키 값을 기록하는 것입니다. 스트림에 레코드를 추가할 때 파티션 키를 지정해야 함을 유의하십시오.

```
putRecordRequest.setPartitionKey( String.format( "myPartitionKey" ) );
```

Kinesis Data Streams는 [MD5](http://en.wikipedia.org/wiki/MD5)를 사용하여 파티션 키에서 해시 키를 계산합니다. 레코드에 대한 파티션 키를 지정하므로 MD5를 사용하여 해당 레코드에 대한 해시 키 값을 계산하고 기록할 수 있습니다.

또한 데이터 레코드가 할당된 샤드 ID도 기록할 수 있습니다. `getShardId` 메서드에 의해 반환된 `putRecordResults` 객체와 `putRecords` 메서드에 의해 반환된 `putRecordResult` 객체의 `putRecord` 메서드를 통해 샤드 ID를 사용할 수 있습니다.

```
String shardId = putRecordResult.getShardId();
```

샤드 ID와 해시 키 값을 사용하면 가장 많은 또는 가장 적은 트래픽을 받는 샤드 및 해시 키를 결정할 수 있습니다. 그런 다음 리샤딩을 사용하여 이러한 키에 적합하게 더 많은 또는 더 적은 용량을 제공할 수 있습니다.

# 샤드 분할
<a name="kinesis-using-sdk-java-resharding-split"></a>

Amazon Kinesis Data Streams에서 샤드를 분할하려면 해시 키 값을 상위 샤드에서 하위 샤드로 재배포하는 방법을 지정해야 합니다. 스트림에 데이터 레코드를 추가하면 해시 키 값에 따라 샤드에 할당됩니다. 해시 키 값은 스트림에 데이터 레코드를 추가할 때 데이터 레코드에 대해 지정하는 파티션 키의 [MD5](http://en.wikipedia.org/wiki/MD5) 해시입니다. 동일한 파티션 키가 있는 데이터 레코드에는 동일한 해시 키 값도 있습니다.

지정된 샤드에 대해 가능한 해시 키 값은 정렬된 연속적인 음수가 아닌 정수의 집합을 구성합니다. 가능한 해시 키 값의 범위는 다음에 의해 지정됩니다.

```
shard.getHashKeyRange().getStartingHashKey();
shard.getHashKeyRange().getEndingHashKey();
```

샤드를 분할할 때 이 범위의 값을 지정합니다. 해당 해시 키 값과 더 높은 모든 해시 키 값은 하위 샤드 중 하나로 배포됩니다. 더 낮은 모든 해시 키 값은 다른 하위 샤드로 배포됩니다.

다음 코드는 각 하위 샤드에서 해시 키를 고르게 재배포하고 기본적으로 상위 샤드를 절반으로 분할하는 샤드 분할 작업을 보여줍니다. 이는 상위 샤드를 분할할 수 있는 방법 중 하나일 뿐입니다. 예를 들어, 상위에서 키의 하위 3분의 1이 하위 샤드 하나로 이동하고, 키의 상위 3분의 2가 다른 하위 샤드로 이동하도록 샤드를 분할할 수 있습니다. 그러나 여러 애플리케이션의 경우 샤드를 절반으로 분할하는 것이 효과적인 방식입니다.

이 코드에서는 `myStreamName`이 스트림의 이름을 보유하고 객체 변수 `shard`가 분할할 샤드를 보유한다고 가정합니다. 먼저 새 `splitShardRequest` 객체를 인스턴스화하고 스트림 이름과 샤드 ID를 설정합니다.

```
SplitShardRequest splitShardRequest = new SplitShardRequest();
splitShardRequest.setStreamName(myStreamName);
splitShardRequest.setShardToSplit(shard.getShardId());
```

샤드에서 가장 낮은 값과 가장 높은 값의 절반으로 해시 키 값을 결정합니다. 이는 상위 샤드에서 해시 키의 상위 절반을 포함하는 하위 샤드에 대한 시작 해시 키 값입니다. `setNewStartingHashKey` 메서드에서 이 값을 지정합니다. 이 값만 지정하면 됩니다. Kinesis Data Streams가 분할에 의해 생성된 다른 하위 샤드에 이 값 미만의 해시 키를 자동으로 배포합니다. 마지막 단계는 Kinesis Data Streams 클라이언트에서 `splitShard` 메서드를 직접적으로 호출하는 것입니다.

```
BigInteger startingHashKey = new BigInteger(shard.getHashKeyRange().getStartingHashKey());
BigInteger endingHashKey   = new BigInteger(shard.getHashKeyRange().getEndingHashKey());
String newStartingHashKey  = startingHashKey.add(endingHashKey).divide(new BigInteger("2")).toString();

splitShardRequest.setNewStartingHashKey(newStartingHashKey);
client.splitShard(splitShardRequest);
```

이 절차 이후 첫 번째 단계는 [스트림이 다시 활성 상태가 될 때까지 대기](kinesis-using-sdk-java-after-resharding.md#kinesis-using-sdk-java-resharding-wait-until-active)에 표시됩니다.

# 두 개의 샤드 병합
<a name="kinesis-using-sdk-java-resharding-merge"></a>

 샤드 병합 작업은 지정된 샤드 두 개를 가져와 단일 샤드로 결합합니다. 병합 이후 단일 하위 샤드는 두 개의 상위 샤드가 포함하는 모든 해시 키 값에 대한 데이터를 받습니다.

**샤드 인접**  
두 개의 샤드를 병합하려면 샤드가 *인접*해야 합니다. 두 개의 샤드에 대한 해시 키 범위의 조합이 간격이 없는 연속적인 집합을 이룰 경우 두 개의 샤드는 인접했다고 간주됩니다. 예를 들어, 두 개의 샤드가 있으며 샤드 하나의 해시 키 범위가 276...381이고 다른 샤드 하나의 해시 키 범위가 382...454라고 가정하면, 이 두 개의 샤드를 해시 키 범위가 276...454인 단일 샤드로 병합할 수 있습니다.

또 다른 예를 들어, 두 개의 샤드가 있으며 샤드 하나의 해시 키 범위가 276...381이고 다른 샤드 하나의 해시 키 범위가 455...560이라고 가정하면, 이 두 개의 샤드 간에는 범위가 382..454인 하나 이상의 샤드가 있으므로 이 두 개의 샤드를 병합할 수 없습니다.

스트림의 모든 `OPEN` 샤드 세트(그룹)는 항상 MD5 해시 키 값의 전체 범위에 걸쳐 있습니다. `CLOSED`와 같은 샤드 상태에 대한 자세한 내용은 [리샤딩 후 데이터 라우팅, 데이터 지속성 및 샤드 상태 고려](kinesis-using-sdk-java-after-resharding.md#kinesis-using-sdk-java-resharding-data-routing) 섹션을 참조하세요.

병합을 위한 후보인 샤드를 식별하려면 `CLOSED` 상태의 모든 샤드를 필터링해야 합니다. `OPEN` 상태, 즉 `CLOSED` 상태가 아닌 샤드의 종료 시퀀스 번호는 `null`입니다. 다음을 사용하여 샤드에 대한 종료 시퀀스 번호를 테스트할 수 있습니다.

```
if( null == shard.getSequenceNumberRange().getEndingSequenceNumber() ) 
{
  // Shard is OPEN, so it is a possible candidate to be merged.
}
```

닫힌 샤드를 필터링한 후 각 샤드에 의해 지원되는 가장 높은 해시 키 값을 기준으로 남은 샤드를 정렬합니다. 다음을 사용하여 이 값을 검색할 수 있습니다.

```
shard.getHashKeyRange().getEndingHashKey();
```

 필터링되고 정렬된 목록에서 두 개의 샤드가 인접한 경우 해당 샤드를 병합할 수 있습니다.

**병합 작업에 대한 코드**  
 다음 코드는 두 개의 샤드를 병합합니다. 이 코드에서는 `myStreamName`이 스트림의 이름을 보유하고 객체 변수 `shard1` 및 `shard2`가 병합할 두 인접 샤드를 보유한다고 가정합니다.

병합 작업의 경우 먼저 새 `mergeShardsRequest` 객체를 인스턴스화합니다. `setStreamName` 메서드로 스트림 이름을 지정합니다. 그런 다음 `setShardToMerge` 및 `setAdjacentShardToMerge` 메서드를 사용하여 병합할 두 개의 샤드를 지정합니다. 마지막으로 Kinesis Data Streams 클라이언트에서 `mergeShards` 메서드를 직접적으로 호출하여 작업을 수행합니다.

```
MergeShardsRequest mergeShardsRequest = new MergeShardsRequest();
mergeShardsRequest.setStreamName(myStreamName);
mergeShardsRequest.setShardToMerge(shard1.getShardId());
mergeShardsRequest.setAdjacentShardToMerge(shard2.getShardId());
client.mergeShards(mergeShardsRequest);
```

이 절차 이후 첫 번째 단계는 [스트림이 다시 활성 상태가 될 때까지 대기](kinesis-using-sdk-java-after-resharding.md#kinesis-using-sdk-java-resharding-wait-until-active)에 표시됩니다.

# 리샤딩 작업 완료
<a name="kinesis-using-sdk-java-after-resharding"></a>

Amazon Kinesis Data Streams의 리샤딩 절차 이후 일반 레코드 처리를 재개하기 전에 다른 절차 및 고려 사항이 필요합니다. 다음 단원에서는 이에 대해 설명합니다.

**Topics**
+ [스트림이 다시 활성 상태가 될 때까지 대기](#kinesis-using-sdk-java-resharding-wait-until-active)
+ [리샤딩 후 데이터 라우팅, 데이터 지속성 및 샤드 상태 고려](#kinesis-using-sdk-java-resharding-data-routing)

## 스트림이 다시 활성 상태가 될 때까지 대기
<a name="kinesis-using-sdk-java-resharding-wait-until-active"></a>

`splitShard` 또는 `mergeShards`의 리샤딩 작업을 호출한 후 스트림이 다시 활성 상태가 될 때까지 기다려야 합니다. 사용할 코드는 [스트림 생성](kinesis-using-sdk-java-create-stream.md) 후 스트림이 활성화될 때까지 대기할 경우와 동일합니다. 코드는 다음과 같습니다.

```
DescribeStreamRequest describeStreamRequest = new DescribeStreamRequest();
describeStreamRequest.setStreamName( myStreamName );

long startTime = System.currentTimeMillis();
long endTime = startTime + ( 10 * 60 * 1000 );
while ( System.currentTimeMillis() < endTime ) 
{
  try {
    Thread.sleep(20 * 1000);
  } 
  catch ( Exception e ) {}
  
  try {
    DescribeStreamResult describeStreamResponse = client.describeStream( describeStreamRequest );
    String streamStatus = describeStreamResponse.getStreamDescription().getStreamStatus();
    if ( streamStatus.equals( "ACTIVE" ) ) {
      break;
    }
   //
    // sleep for one second
    //
    try {
      Thread.sleep( 1000 );
    }
    catch ( Exception e ) {}
  }
  catch ( ResourceNotFoundException e ) {}
}
if ( System.currentTimeMillis() >= endTime ) 
{
  throw new RuntimeException( "Stream " + myStreamName + " never went active" );
}
```

## 리샤딩 후 데이터 라우팅, 데이터 지속성 및 샤드 상태 고려
<a name="kinesis-using-sdk-java-resharding-data-routing"></a>

Kinesis Data Streams는 실시간 데이터 스트리밍 서비스입니다. 애플리케이션에서는 데이터가 스트림의 샤드를 통해 지속적으로 흐르고 있다고 가정해야 합니다. 리샤딩하면 상위 샤드로 이동하는 데이터 레코드가 데이터 레코드 파티션 키가 매핑되는 해시 키 값에 따라 하위 샤드로 이동하도록 다시 라우팅됩니다. 그러나 리샤딩 전에 상위 샤드에 있는 데이터 레코드는 해당 샤드에 유지됩니다. 리샤딩이 발생할 때 상위 샤드가 사라지지 않습니다. 리샤딩 전에 포함하는 데이터와 함께 유지됩니다. 상위 샤드의 데이터 레코드는 Kinesis Data Streams API의 [`getShardIterator` 및 `getRecords`](developing-consumers-with-sdk.md#kinesis-using-sdk-java-get-data) 작업을 사용하거나 Kinesis Client Library를 통해 액세스할 수 있습니다.

**참고**  
데이터 레코드가 스트림에 추가된 시점으로부터 현재 보존 기간까지 데이터 레코드에 액세스할 수 있습니다. 이는 해당 기간 동안 스트림의 샤드가 변경되는지 여부와 관계없이 마찬가지입니다. 스트림의 보존 기간에 대한 자세한 내용은 [데이터 보존 기간 변경](kinesis-extended-retention.md) 단원을 참조하십시오.

리샤딩 프로세스에서 상위 샤드가 `OPEN` 상태에서 `CLOSED` 상태로, `EXPIRED` 상태로 전환됩니다.
+  **OPEN**: 리샤딩 작업 전 상위 샤드는 `OPEN` 상태입니다. 즉, 데이터 레코드를 샤드에 추가하고 샤드에서 검색할 수 있습니다.
+  **CLOSED**: 리샤딩 작업 후 상위 샤드가 `CLOSED` 상태로 전환됩니다. 즉, 데이터 레코드가 더 이상 샤드에 추가되지 않습니다. 이 샤드에 추가된 데이터 레코드는 이제 하위 샤드에 대신 추가됩니다. 그러나 제한된 기간 동안 계속 샤드에서 데이터 레코드를 검색할 수 있습니다.
+  **EXPIRED**: 스트림의 보존 기간이 만료된 후 상위 샤드에 있는 모든 데이터 레코드가 만료되며 더 이상 액세스할 수 없습니다. 이때 샤드 자체는 `EXPIRED` 상태로 전환됩니다. 스트림에 샤드를 열거하기 위한 `getStreamDescription().getShards`를 호출하면 반환된 목록 샤드에 `EXPIRED` 샤드가 포함되지 않습니다. 스트림의 보존 기간에 대한 자세한 내용은 [데이터 보존 기간 변경](kinesis-extended-retention.md) 단원을 참조하십시오.

리샤딩이 발생하고 스트림이 다시 `ACTIVE` 상태가 된 후 즉시 하위 샤드에서 데이터를 읽기 시작할 수 있습니다. 그러나 리샤딩 후 남아 있는 상위 샤드는 리샤딩 전에 스트림에 추가되어 아직 읽지 않은 데이터를 계속 포함할 수 있습니다. 상위 샤드에서 모든 데이터를 읽기 전에 하위 샤드에서 데이터를 읽는 경우 데이터 레코드의 시퀀스 번호에 의해 지정된 순서가 아닌 다른 순서로 특정 해시 키에 대한 데이터를 읽을 수 있습니다. 따라서 데이터 순서가 중요하다고 간주하는 경우, 리샤딩 후 다 읽을 때까지 항상 상위 샤드에서 데이터를 계속 읽어야 합니다. 그런 다음 하위 샤드에서 데이터를 읽기 시작해야 합니다. `getRecordsResult.getNextShardIterator`가 `null`을 반환하면 상위 샤드에서 모든 데이터를 읽었음을 나타냅니다.