Application Auto Scalingのcustom-resourceによるKinesis Data Streamsのオートスケール設定
awsApplication Auto Scalingは、Auto Scaling groupによるEC2のオートスケールのようなことを他のリソースでも行えるようにするサービスで、 DynamoDBのキャパシティやECSのServiceなどコンソール上から設定できるものだけではなく、自前のAPIでハンドリングすることで任意のリソースをこの仕組みに乗せることができる。これを用いてKinesis Data Streamsのオートスケールを行う手法を紹介しているのが次の記事。
Scale Amazon Kinesis Data Streams with AWS Application Auto Scaling | AWS Big Data Blog
サンプルテンプレートの設定項目を見ていく。
ScalableTarget
ServiceNamespaceでdynamodbやecsといった名前空間を、ScalableDimensionでdynamodb:table:ReadCapacityUnitsやecs:service:DesiredCountといった増減する値を指定する。
ResourceIdにはScalableDimensionのResourceTypeに応じた対象を指定するわけだが、
custom-resourceの場合は状態を確認したり更新するためのAPIのURLを指定するようだ。
ドキュメントにはOutputValueの値と書いてあるが、特に関係ないように見える。
Roleにはcloudwatch:Describe/Put/DeleteAlarmsおよびexecute-api:Invoke*の権限を与える。
KinesisAutoScaling:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn: LambdaScaler
Properties:
MaxCapacity: 8
MinCapacity: 1
ResourceId: !Sub https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/prod/scalableTargetDimensions/${MyKinesisStream}
RoleARN: !Sub ${CustomApplicationAutoScalingServiceRole.Arn}
ScalableDimension: 'custom-resource:ResourceType:Property'
ServiceNamespace: custom-resource
ScalingPolicy
AdjustmentTypeとScalingAdjsutmentの値によって増減値を設定する。
AdjustmentTypeにはChangeInCapacity | ExactCapacity | PercentChangeInCapacityのいずれかを指定する。
AutoScalingPolicyOut:
Type : "AWS::ApplicationAutoScaling::ScalingPolicy"
DependsOn: KinesisAutoScaling
Properties:
PolicyName: KinesisScaleOut
PolicyType: StepScaling
ResourceId: !Sub https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/prod/scalableTargetDimensions/${MyKinesisStream}
ScalableDimension: "custom-resource:ResourceType:Property"
ServiceNamespace: custom-resource
StepScalingPolicyConfiguration:
AdjustmentType: ChangeInCapacity
Cooldown: 600
MetricAggregationType: Average
StepAdjustments:
- MetricIntervalLowerBound: 0
ScalingAdjustment: 1
CloudWatch AlarmのActionにこのPolicyを指定して、メトリクスが閾値に達したときに通知されるようにする。
この例ではストリームのIncomingRecordsを見ている。
もしパーティションキーが乱数でなかったり、各シャードに対応するハッシュキーのレンジが均等でなかったりして、
ホットシャードが発生する可能性があるなら、
拡張メトリクスを有効にすると得られるシャードレベルの値を基にしても良いかもしれない。
CWAlarmOut:
Type: AWS::CloudWatch::Alarm
DependsOn: MyKinesisStream
Properties:
AlarmName: !Ref CloudWatchAlarmNameOut
AlarmDescription: 'incomingRecord exceeds threshold'
MetricName: 'IncomingRecords'
Namespace: 'AWS/Kinesis'
Dimensions:
- Name: StreamName
Value: !Ref MyKinesisStream
Statistic: 'Sum'
Period: 60
EvaluationPeriods: 1
Threshold: 1000
ComparisonOperator: 'GreaterThanThreshold'
AlarmActions:
- !Ref AutoScalingPolicyOut
API
通知が飛ぶとApplication Auto ScalingがResource IDに指定したAPIをGETで呼び出すので、次のフォーマットで状態を返す。
returningJson = {
"actualCapacity": float(actualCapacity),
"desiredCapacity": float(desiredCapacity),
"dimensionName": resourceName,
"resourceName": resourceName,
"scalableTargetDimensionId": resourceName,
"scalingStatus": scalingStatus,
"version": "MyVersion"
}
スケールが必要な場合はPATCHでdesiredCapacityが渡ってくるので、この値になるようにUpdateShardCountし、アラームの閾値を更新する。
UpdateShardCountも内部ではSplit/MergeShardが行われるので倍や半分といった値にすると速く変更できる。
"body": "{\"desiredCapacity\":3.0}"
併せてコンシューマーの数も調整する。 また、KDSのリシャーディング回数や変更幅の制限については別に考慮する必要がある。