Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(aws-rds): support Aurora Serverless v2 cluster and instances #22446

Closed

Conversation

pahud
Copy link
Contributor

@pahud pahud commented Oct 10, 2022

About this PR

Aurora Serverless v2 now supports AWS CloudFormation and CDK has included the L1 support. The cluster with serverless v2 support is created from (AWS::RDS::DBCluster) with some conditions and limitations:

  • When ServerlessV2ScalingConfiguration is enabled, the DBCluster will be created as a cluster with serverless v2 support so we can add serverless v2 writer and reader instances in this cluster.
  • Serverless v1 and v2 have different scaling spec.
  • Clusters with serverless v2 support can add either serverless instances or provisioned instances, which means when DBCluster is provisioned with v2 support, we should be able to add an arbitrary number of instances in it, either serverless or provisioned. The first one added would be the writer while others the readers.

This PR extends the DatabaseCluster construct so we can enable its serverless v2 support by specifying the new serverlessV2Scaling property. After the cluster is created, we can addServerlessInstance to add a serverless v2 instance or addInstance to add a provisioned instance into the serverless v2 enabled DBCluster.

This PR has tested a few scenarios in the integ.serverlessv2-cluster.ts including:

  • DBCluster with 1 master and 0 or more replica instances(we already can satisfy this with the existing DatabaseCluster L2)
  • DBCluster with 1 serverless v2 write instance only
  • DBCluster with 1 serverless v2 write and 1 or more serverless v2 read instances
  • DBCluster with 1 serverless v2 write and 1 or more provisioned read instances
  • DBCluster with 1 provisioned write and 1 or more serverless v2 read instances

call out

I am not sure if this would make breaking changes:

  • instances from of DatabaseClusterBaseProps can be 0 now. This allows the DBCluster to be provisioned as a cluster with serverless instances only.

Fixes: #20197


All Submissions:

Adding new Unconventional Dependencies:

  • This PR adds new unconventional dependencies following the process described here

New Features

  • Have you added the new feature to an integration test?
    • Did you use yarn integ to deploy the infrastructure and generate the snapshot (i.e. yarn integ without --dry-run)?

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@gitpod-io
Copy link

gitpod-io bot commented Oct 10, 2022

@github-actions github-actions bot added the p2 label Oct 10, 2022
@aws-cdk-automation aws-cdk-automation requested a review from a team October 10, 2022 16:20
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Oct 10, 2022
Copy link
Collaborator

@aws-cdk-automation aws-cdk-automation left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pull request linter has failed. See the aws-cdk-automation comment below for failure reasons. If you believe this pull request should receive an exemption, please comment and provide a justification.

packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-rds/lib/serverless-cluster.ts Outdated Show resolved Hide resolved
*
* @default - TBC
*/
readonly scalingV2?: ServerlessV2ScalingOptions;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That V2 suffix is a bit of an eye sore.

Is there no better way?

Can we perhaps set an enum on the ServerlessCluster class that specifies which version it is, and it then type narrows the interface? Or will it confuse JSII?

enum ServerlessClusterVersion {
  V1,
  V2,
}

interface ServerlessClusterNewProps {
  version: ServerlessClusterVersion
}

interface ServerlessClusterNewPropsV1 {
  version: ServerlessClusterVersion.V1
  scaling: V1Scaling
}

interface ServerlessClusterNewPropsV2 {
  version: ServerlessClusterVersion.V2
  scaling: V2Scaling
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @moltar

Let's make it a little bit clear.

What I am trying to propose is to reuse the ServerlessCluster to create either v1 or v2 clusters. As v1 and v2 have different scaling configuration logic and can't be shared, we would have both scaling interfaces for v1 and v2 in the ServerlessClusterProps if we have to reuse the ServerlessCluster construct for both scenarios. Your sample seems to create ServerlessClusterV2 just for v2 in addition to the existing ServerlessCluster just for v1. I am fine with that as this is opinionated. Is this something you prefer in the API design?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my example, I am following your proposal to reuse the same class too. I guess my point about that was not very clear.

I was proposing to use discriminating unions to type narrow the interface based on the version prop.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Union types don't work with jsii.

@moltar
Copy link
Contributor

moltar commented Oct 10, 2022

Also, from the docs: https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.how-it-works.html#aurora-serverless-v2.how-it-works.cluster_topology

For each of your Aurora DB clusters, you can choose any combination of Aurora Serverless v2 capacity, provisioned capacity, or both.

You can set up a cluster that contains both Aurora Serverless v2 and provisioned capacity, called a mixed-configuration cluster.

Has this mixed-configuration cluster type been tested?

I see only ServerlessCluster construct being touched. But ultimately, I think in V2, the cluster is not serverless, but instances can be serverless. Or am I misunderstanding it?

pahud and others added 3 commits October 10, 2022 12:55
Co-authored-by: Roman <491247+moltar@users.noreply.github.com>
Co-authored-by: Roman <491247+moltar@users.noreply.github.com>
Co-authored-by: Roman <491247+moltar@users.noreply.github.com>
@pahud
Copy link
Contributor Author

pahud commented Oct 10, 2022

Also, from the docs: https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.how-it-works.html#aurora-serverless-v2.how-it-works.cluster_topology

For each of your Aurora DB clusters, you can choose any combination of Aurora Serverless v2 capacity, provisioned capacity, or both.
You can set up a cluster that contains both Aurora Serverless v2 and provisioned capacity, called a mixed-configuration cluster.

Has this mixed-configuration cluster type been tested?

I see only ServerlessCluster construct being touched. But ultimately, I think in V2, the cluster is not serverless, but instances can be serverless. Or am I misunderstanding it?

ServerlessCluster construct was previously designed only for v1 and in v1 adding instances in the cluster is not allowed and not required. It is displayed as serverless cluster role with both reader and writer endpoints. When ServerlessCluster is created as v2 the cluster would be displayed as regional cluster in the console and accept eitherserverless or provisioned instances. I will test this scenario in my integ test and update README as well.

@moltar
Copy link
Contributor

moltar commented Oct 10, 2022

and in v1 adding instances in the cluster is not allowed and not required

Yeah, we've used v1 extensively. I am familiar with this limitation that's why I was asking.

It feels like maybe trying to fit a round peg in a square hole.

  • V1 provisioned the cluster and instance, without providing any control over it.
  • V2 is essentially going back to the traditional RDS cluster has_many instances model.

Meanwhile, we are trying to make ServerlessCluster class represent what it was not intended to do.

Wouldn't it make more sense to make the original cluster work with the v2 instances, and then have some convenience interface, perhaps, over it?

But I might be totally off base here, as I feel like I am still not fully understanding the problem space. So I am sorry, if what I am saying is noise.

@pahud
Copy link
Contributor Author

pahud commented Oct 10, 2022

Hi @moltar please check out this sample in which I created 1 x v1 cluster and 2 x v2 clusters mixed with "serverless" and "provisioned" instances.

In aurora serverless v2 cluster, the cluster itself is actually a "regional cluster" and you can add "serverless" or "provisioned" instances into the serverless v2 cluster. We could make all instances serverless, partially serverless or completely provisioned. 😄

It is interesting you literally can add all "provisioned" writer/readers instances in an "aurora serverless v2 cluster". I believe it's the primary feature v2 differentiates itself from v1 as v1 is 100% serverless.

image

check out my cdk code used to provision the 3 clusters here

@pahud
Copy link
Contributor Author

pahud commented Oct 10, 2022

Looking at the doc again, I think I was wrong. There is literally no "Aurora Serververless v2 cluster", only the old aurora cluster. We should be able to add any new "serverless v2 DB instances" or provisioned instances to any new or existing aurora clusters. I will update my PR shortly.

@moltar
Copy link
Contributor

moltar commented Oct 10, 2022

I don't think there was even a v1 Serverless Cluster technically. It was always just an AWS::RDS::DBCluster, and the ServerlessClass construct was a convenience wrapper around it.

I think with V1 the design limitation was that you were not able to add any instances to the cluster (even the first one), as it was created for you. So maybe that's why a separate class was created for it.

@pahud
Copy link
Contributor Author

pahud commented Oct 11, 2022

@moltar thanks for clearing it up. As the ServerlessCluster is for serverless v1 only, the DBCluster should satisfy the following cases:

  1. DBCluster with 1 master and 0 or more replica instances(we already can satisfy this with the DatabaseCluster L2)
  2. DBCluster with 1 serverless v2 write instance only
  3. DBCluster with 1 serverless v2 write and 1 or more serverless v2 read instances
  4. DBCluster with 1 serverless v2 write and 1 or more provisioned read instances
  5. DBCluster with 1 provisioned write and 1 or more serverless v2 read instances

Maybe we should extend the DatabaseCluster class to satisfy all above. With that being said,

  1. DatabaseCluster should allow 0 instances(for case 3).
  2. DatabaseCluster should add the ServerlessV2ScalingConfiguration support(for case 2-5).

wdyt?

@aws-cdk-automation aws-cdk-automation dismissed their stale review October 11, 2022 04:10

✅ Updated pull request passes all PRLinter validations. Dissmissing previous PRLinter review.

@moltar
Copy link
Contributor

moltar commented Oct 11, 2022

I don't know all of the permutations of cluster & instances. But I think overall it sounds good to me what you are suggesting.

I think standardizing on the DBCluster is the right move too, because v1 will be EOL anyways, and we could probably just put the entire ServerlessCluster class into @deprecated mode.

@moltar
Copy link
Contributor

moltar commented Oct 11, 2022

IMO, the entire DatabaseCluster is maybe just designed awkwardly, and does not follow the design principles of CDK.

In ideal world, what I would like to see is (and this is definitely outside of this PR scope):

new DatabaseCluster(scope, 'Cluster', {
  // ...

  instances: [
    new ProvisionedInstance(),
    new SeverlessInstance(),
  ]

  // ...
})

IMO, we don't need the instances prop. Just specify an empty array, and the cluster is launched without instances. And don't need the instanceProps prop also, as that seems to be just applying the config to the first instance.

And the convenience method shall not also care about what type of instance is being added. It should just accept an IInstance interface, which figures out under the hood.

cluster.addInstance(new ProvisionedInstance())
// OR
cluster.addInstance(new SeverlessInstance())

I have not studied all of the typings, so I am not sure if this is possible. But this feels like the CDK approach.

@pahud pahud marked this pull request as ready for review October 12, 2022 14:31
@Naumel Naumel added the @aws-cdk/aws-rds Related to Amazon Relational Database label Oct 13, 2022
Copy link
Contributor

@corymhall corymhall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we may want to think a little bit more about the user experience here. Previously DatabaseCluster created only provisioned instances and now it can create a mix of provisioned or serverlessV2. In your proposed API there are too many things that the user needs to keep track of.

  • If I start with a provisioned cluster and want to add a serverlessv2 instance can I just do addServerlessInstance? or do I also have to go back and add serverlessV2Scaling to the cluster props?
  • What is instanceProps used for if I set instances=0?
  • It is not straight forward to figure out if my writer is a serverlessv2 instance or not.
  • What happens if I change my writer from a provisioned to a serverlessV2 (or vice versa)

I think instead of starting from the existing DatabaseCluster construct, we should start from the ideal customer experience and work backwards from there. If it allows us to continue using the DatabaseCluster construct then great, but if we need to create a new construct DatabaseClusterV2 then that is ok too.

});

// adding a serverless writer
cluster.addServerlessInstance('instance1', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this adding a serverless v1 or v2 instance? I think we need to update all references to include V2 if it is referring to v2 (docs & API), otherwise I am not sure if it is referring to v1 or v2. You might know that I can't add a serverless v1 instance, but others might not.

Is it adding a writer because it is the first instance that we are adding?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it's a little bit confusing but the core concept is:

  1. You are not allowed to add any instances for Aurora Serverless v1 cluster.
  2. You can't add serverless v2 instances into a general cluster until it is serverless v2 enabled.
  3. there is no serverless v1 instance. In Aurora Serverless v1, instances are not required.

We could add a check in this method to check the eligibility. Only clusters with v2 enabled are allowed to addServerlessInstance. More details discussed in the comment below.

packages/@aws-cdk/aws-rds/lib/instance-engine.ts Outdated Show resolved Hide resolved
minCapacity: 0.5,
},
// do not create any provisioned instance in the cluster
instances: 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to create this cluster with a serverless v2 writer we have to set instances=0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes 😄

@pahud
Copy link
Contributor Author

pahud commented Oct 18, 2022

I think we may want to think a little bit more about the user experience here. Previously DatabaseCluster created only provisioned instances and now it can create a mix of provisioned or serverlessV2. In your proposed API there are too many things that the user needs to keep track of.

  • If I start with a provisioned cluster and want to add a serverlessv2 instance can I just do addServerlessInstance? or do I also have to go back and add serverlessV2Scaling to the cluster props?
  • What is instanceProps used for if I set instances=0?
  • It is not straight forward to figure out if my writer is a serverlessv2 instance or not.
  • What happens if I change my writer from a provisioned to a serverlessV2 (or vice versa)

I think instead of starting from the existing DatabaseCluster construct, we should start from the ideal customer experience and work backwards from there. If it allows us to continue using the DatabaseCluster construct then great, but if we should create a new construct DatabaseClusterV2 then that is ok too.

Yes I was struggling if we should use the existing DatabaseCluster for both common cluster and v2-enabled cluster or if we really need to create a new DatabaseClusterV2 for serverless v2 support.

Current API design is based on using the existing DatabaseCluster construct without potential breaking changes. In fact there is no so-called serverless v2 cluster but just serverless v2-enabled cluster. If we need to create a cluster with serverless writer and serverless reader(s), the first step is to create a DatabaseCluster with 0 instances and then add serverless instances into this cluster. Yes it's a little bit awkward but we do see similar design in aws-eks to create a cluster with 0 instances and then cluster.addNodegroupCapacity() or addAutoScalingGroupCapacity() as EKS Cluster construct allows us to create clusters with defined or empty capacity. So I think DatabaseCluster might have similar design like that.

The user experience could be like:

  1. Users are allowed to create a general cluster or serverlessv2-enabled cluster with the DatabaseCluster construct.

  2. For general clusters with writer and read replica(s), users can leave the instances property undefined(default is 2) or any other values supported for this scenario. We already can satisfy this with DatabaseCluster.

  3. For clusters with serverlessV2-enabled support, however, we have many possible and supported scenarios like:
    a. 1 serverless writer + 1 or more serverless reader(s)
    b. 1 serverless writer + 1 or more provisioned reader(s)
    c. 1 provisioned writer + 1 or more serverless reader(s)
    d. 1 provisioned writer + 1 or more provision reader(s)
    e. 1 provisioned writer + 1 or more provision reader(s) + 1 or more serverless reader(s)
    f. 1 serverless writer + 1 or more provision reader(s) + 1 or more serverless reader(s)

    To use the existing DatabaseCluster for case a, b and f we have to set instances to 0 as the first instance would be the writer and we can't create the serverless writer with current DatabaseCluster construct and that's where addServerlessInstance() comes in for those scenarios.

    For case c we should create the DatabaseCluster with instances: 1 so the first instance would be the provisioned writer instance and addServerlessInstance() to create the serverless reader.

    For case d we just specify instances: 2 for the serverlessV2-enabled cluster.

For case e we specify instances >=2 and then addServerlessInstance() to create additional reader(s).

To answer your questions above:

  • If I start with a provisioned cluster and want to add a serverlessv2 instance can I just do addServerlessInstance? or do I also have to go back and add serverlessV2Scaling to the cluster props?

If you create a cluster without serverlessv2 enabled, you can't addServerlessInstance() to it. We can check the eligibility in this method and throw to avoid that.

  • What is instanceProps used for if I set instances=0?

instanceProps will be used when we addServerlessInstance or addInstance() for the serverlessV2-enabled cluster to reference the vpc property from it.

  • It is not straight forward to figure out if my writer is a serverlessv2 instance or not.

For serverlessv2 writer(discussed in case a. b. and f. above) we have to set instances: 0 and explicitly addServerlessInstance() from the empty cluster to create our first instance as the serverless writer. In a mxi cluster of serverless and provisoned instances, to ensure the first instance is always serverless, users will be responsible to add dependency to make sure provisioned one is always created after the serverless one.

  • What happens if I change my writer from a provisioned to a serverlessV2 (or vice versa)

This is interesting. From CFN's perspective I believe this will trigger the update replacement described in this doc. CFN will create a new one before it "replaces" the old one, however, terminating the writer for replacement should result in a "failover" so your writer might immediately failover to the existing reader. I am not sure how CFN deals with that. Will give it a try and update here.

I hope this helps to make it a little bit clear. I agree we should consider the user experience and work backwards from it. I am totally fine with a new DatabaseClusterV2 construct just for serverlessV2-enabled clusters and provide addServerlessInstance and addInstance for it. What do you think?

Co-authored-by: Cory Hall <43035978+corymhall@users.noreply.github.com>
@pahud
Copy link
Contributor Author

pahud commented Oct 19, 2022

Hi @corymhall

Last night I implemented a new ServerlessV2DatabaseCluster as a different API design for this PR which makes everything more clean and easy to understand. While DatabaseCluster is untouched in this design, the new ServerlessV2DatabaseCluster construct looks like:

/**
 * Aurora serverless v2 cluster for MySQL with the mix of serverless and provisioned instances.
 */
// Aurora Serverless v2 cluster for MySQL
new rds.ServerlessV2DatabaseCluster(stack, 'cluster2', {
  engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_02_1 }),
  serverlessV2Scaling: {
    maxCapacity: 4,
    minCapacity: 0.5,
  },
  // 1 writer(serverless)
  writer: { engine: rds.DatabaseInstanceEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_02_1 }) },
  // 2 readers: 1 serverless and 1 provisioned.
  reader: [
    { engine: rds.DatabaseInstanceEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_02_1 }) },
    {
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.R5, ec2.InstanceSize.LARGE),
      engine: rds.DatabaseInstanceEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_02_1 }),
    },
  ],
  vpc,
  vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
  removalPolicy: cdk.RemovalPolicy.DESTROY,
});

Should we opt in a new construct like this for this PR?

@moltar
Copy link
Contributor

moltar commented Oct 19, 2022

IMO, the solution I have proposed is more idiomatic:

new DatabaseCluster(scope, 'Cluster', {
  // ...

  instances: [
    new ProvisionedInstance(),
    new SeverlessInstance(),
  ]

  // ...
})

If you want to have a specific reader writer instance, you can create classes for that:

new DatabaseCluster(scope, 'Cluster', {
  // ...

  instances: [
    new ReaderInstance(),
    new WriterInstance(),
  ]

  // ...
})

@pahud
Copy link
Contributor Author

pahud commented Oct 19, 2022

@moltar Yeah we can discuss more details about the design if we decide to opt in a new construct.

@pahud pahud requested a review from corymhall October 20, 2022 02:43
@corymhall
Copy link
Contributor

If you create a cluster without serverlessv2 enabled, you can't addServerlessInstance() to it. We can check the eligibility in this method and throw to avoid that.

If this is the case then I definitely think that we should go with a new construct. This means that there are 3 different types of clusters that you can create, ServerlessV1 cluster, traditional provisioned cluster, serverless v2 enabled cluster. But based on what I can see in the docs it looks like it is possible to add serverless v2 instances to an existing cluster.

Last night I implemented a new ServerlessV2DatabaseCluster as a different API design for this PR which makes everything more clean and easy to understand. While DatabaseCluster is untouched in this design, the new ServerlessV2DatabaseCluster construct looks like:

I think instead of ServerlessV2DatabaseCluster we should call it something like DatabaseClusterV2. Even though users can still create a provisioned cluster with DatabaseCluster it doesn't sound like there is a reason why you would want to instead of creating a serverlessV2 enabled cluster.

I have some outstanding questions that I think we need to answer before we can design the experience.

For clusters with serverlessV2-enabled support, however, we have many possible and supported scenarios like:

  1. These are possible scenarios, but I am curious what the actual use cases are. Why would I want to created a mixed use cluster? What are the benefits/drawbacks.

From the docs

The granularity of scaling in Aurora Serverless v2 helps you to match capacity closely to your database's needs. For a provisioned cluster, scaling up requires adding a whole new DB instance. For an Aurora Serverless v1 cluster, scaling up requires doubling the number of Aurora capacity units (ACUs) for the cluster, such as from 16 to 32 or 32 to 64. In contrast, Aurora Serverless v2 can add half an ACU when only a little more capacity is needed. It can add 0.5, 1, 1.5, 2, or additional half-ACUs based on the additional capacity needed to handle an increase in workload. And it can remove 0.5, 1, 1.5, 2, or additional half-ACUs when the workload decreases and that capacity is no longer needed.

Do I even need to create more than 1 serverless v2 instance (I think the answer is yes)?

You can modify existing DB instances from provisioned to Aurora Serverless v2 or from Aurora Serverless v2 to provisioned. You don't need to create a new cluster or a new DB instance in such cases.

I wonder how this works?

Suppose that you already have an Aurora application running on a provisioned cluster. You can check how the application would work with Aurora Serverless v2 by adding one or more Aurora Serverless v2 DB instances to the existing cluster as reader DB instances. You can check how often the reader DB instances scale up and down. You can use the Aurora failover mechanism to promote an Aurora Serverless v2 DB instance to be the writer and check how it handles the read/write workload. That way, you can switch over with minimal downtime and without changing the endpoint that your client applications use. For details on the procedure to convert existing clusters to Aurora Serverless v2, see

It looks like you can convert an existing cluster to serverless v2?

  1. If there are valid mixed use scenarios, then how do I account for things like failover? If there is a valid reason why I would want a serverlessv2 writer and a provisioned reader, what happens when I failover and the provisioned instance becomes my writer? Does it create a new serverlessv2 reader, or does it create a new provisioned reader?

Some of this is covered in scaling (i.e. promotion tiers).

@mrgrain
Copy link
Contributor

mrgrain commented Oct 21, 2022

@corymhall

These are possible scenarios, but I am curious what the actual use cases are. Why would I want to created a mixed use cluster? What are the benefits/drawbacks.

One typical reason will be cost. Aurora Serverless V2 is significantly more expensive than Provisioned On-Demand instances. In many scenarios a provisioned (and reserved) base capacity will be more economical.

@pahud
Copy link
Contributor Author

pahud commented Oct 21, 2022

@corymhall Love the discussion! Appreciated! Let's dive a little bit deeper and get things sorted.

If you create a cluster without serverlessv2 enabled, you can't addServerlessInstance() to it. We can check the eligibility in this method and throw to avoid that.

If this is the case then I definitely think that we should go with a new construct. This means that there are 3 different types of clusters that you can create, ServerlessV1 cluster, traditional provisioned cluster, serverless v2 enabled cluster. But based on what I can see in the docs it looks like it is possible to add serverless v2 instances to an existing cluster.

From CFN's perspective, there's only one AWS::RDS::DBCluster resource and we can create 3 types of clusters from it:

  1. general provisioned clusters with a writer and replica(s) - instance-based clusters w/o serverlessV1 or serverlessV2-enabled. From CFN's perspective, both ServerlessV2ScalingConfiguration and ScalingConfiguration should not be specified.
  2. serverless v1 clusters - no instances at all. Provisioned with ScalingConfiguration specified.
  3. serverless v2 clusters or clusters with serverless v2 support - mix with serverless and/or provisioned instance(s) writer and reader. Provisioned with ServerlessV2ScalingConfiguration specified.

From my experiment with CDK, you can't just add a serverless v2 instance into a general cluster or v1-enabled cluster. You will receive an error message like ServerlessV2ScalingConfiguration is not enabled in the existing cluster. I don't think CFN will allow you in-place upgrade a general cluster to v2 or v1 to v2 by simply adding the ServerlessV2ScalingConfiguration optional prop in the construct because according to the doc, moving/upgrading from a provisioned cluster to v2 or v1 to v2 has some limitations and conditions to consider. I will call out this in the aws-rds README in this PR.

I have some outstanding questions that I think we need to answer before we can design the experience.

  1. These are possible scenarios, but I am curious what the actual use cases are. Why would I want to created a mixed use cluster? What are the benefits/drawbacks.

I'm probably not the best one to answer this question but AFAIK

  1. the provisioned one might be more economical compared to the serverless one. If customer use case is a predictable steady read workload with unpredictable write/update workload, a provisioned reader with a serverless writer might be a better option than the serverless writer+reader.
  2. Similarly, predictable intensive write/update with unpredictable read scenarios, provisioned writer + serverless reader may be a good choice.

Do I even need to create more than 1 serverless v2 instance (I think the answer is yes)?

As aurora serverless v2 is single-AZ based instance. Customers may opt in multi-AZ serverless readers, in which case they might need 2 or more serverless readers across multi-AZ. One of the advantages is the AZ-tolerance, another one is that when the primary serverless reader instance fails(everything fails 😄 ), it could immediate fail over to another serverless reader, instead of the writer.

You can modify existing DB instances from provisioned to Aurora Serverless v2 or from Aurora Serverless v2 to provisioned. You don't need to create a new cluster or a new DB instance in such cases.

I wonder how this works?

I probably need to look into that as it seems not possible from console.

Suppose that you already have an Aurora application running on a provisioned cluster. You can check how the application would work with Aurora Serverless v2 by adding one or more Aurora Serverless v2 DB instances to the existing cluster as reader DB instances. You can check how often the reader DB instances scale up and down. You can use the Aurora failover mechanism to promote an Aurora Serverless v2 DB instance to be the writer and check how it handles the read/write workload. That way, you can switch over with minimal downtime and without changing the endpoint that your client applications use. For details on the procedure to convert existing clusters to Aurora Serverless v2, see

It looks like you can convert an existing cluster to serverless v2?

yes, as discussed above, the provisioned cluster, serverless v1 cluster and the serverless v2 cluster are essentially the same AWS::RDS::DBCluster with different mutual-exclusive props.

  1. If there are valid mixed use scenarios, then how do I account for things like failover? If there is a valid reason why I would want a serverlessv2 writer and a provisioned reader, what happens when I failover and the provisioned instance becomes my writer? Does it create a new serverlessv2 reader, or does it create a new provisioned reader?

With a serverlessV2 writer and one provisioned reader:

  1. You risk single-AZ for both writer and reader. If the reader fails, I believe the read traffic will switch to the writer and a new reader might be start provisioning and switch back the read traffic when the new reader is ready.(I need test it though)
  2. if the serverless writer fails I believe the provisioned reader will be promoted as the provisioned writer with a little period of writing interruptions. I am not sure if the control plane will create a new serverless writer instance and switch back the write traffic.(will test it from console)

However, customers with very critical, steady and intensive read queries might consider multiple provisioned readers across multi-AZ for fault tolerance, which will not impact the writer when any single reader fails.

Nice discussion. Thanks for bringing this up.

Some of this is covered in scaling (i.e. promotion tiers).

@corymhall
Copy link
Contributor

corymhall commented Oct 21, 2022

These are possible scenarios, but I am curious what the actual use cases are. Why would I want to created a mixed use cluster? What are the benefits/drawbacks.

One typical reason will be cost. Aurora Serverless V2 is significantly more expensive than Provisioned On-Demand instances. In many scenarios a provisioned (and reserved) base capacity will be more economical.

Yep! I think my point in bringing this up was that I think our design should take these specific scenarios into consideration. For example, If I really want to (or even have to) have a provisioned instance as my writer, then I also need a provisioned instance as a reader in the 0 promotion tier and any serverlessv2 instances should be in lower promotion tiers. If we make this hard for the user to do then we could make it easy for users to shoot themselves in the foot (e.g. Only a provisioned writer can handle the production load and they failover to a serverless v2 instance and prod goes down :( ). Previously you could only create a cluster with a single type of instance so these types of considerations didn't really matter.

Also, what if I want to create different endpoints? It seems like the API needs to account for users needing more control over the individual instances they create in the cluster.

From my experiment with CDK, you can't just add a serverless v2 instance into a general cluster or v1-enabled cluster. You will receive an error message like ServerlessV2ScalingConfiguration is not enabled in the existing cluster. I don't think CFN will allow you in-place upgrade a general cluster to v2 or v1 to v2 by simply adding the ServerlessV2ScalingConfiguration optional prop in the construct because according to the doc, moving/upgrading from a provisioned cluster to v2 or v1 to v2 has some limitations and conditions to consider. I will call out this in the aws-rds README in this PR.

My point in bringing this up is that we should take the upgrade experience into consideration. If it is possible to upgrade an existing cluster, then maybe we don't want to require the user to use a new construct since that would prevent them from upgrading their cluster. If it is not possible then they have to create a new cluster anyway.

Copy link
Contributor

@corymhall corymhall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this feature might be a good candidate for an RFC.

@pahud
Copy link
Contributor Author

pahud commented Oct 21, 2022

Some important findings today:

  1. You actually can add serverless v2 instances into an existing cluster provisioned by the existing rds.DatabaseCluster construct w/o the ServerlessV2ScalingConfiguration specified.
// create a ordinary provisioned cluster
new rds.DatabaseCluster(stack, 'general-cluster', {
  // make sure you use serverless v2 compatible DatabaseClusterEngine
  engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_02_1 }),
  instanceProps: {
    vpc,
    vpcSubnets,
  },
  subnetGroup,
});

// OK now you are allowed to add a serverless v2 reader into this cluster from console.

This indicates that you are not literally convert the original cluster into a serverless v2 cluster. They are exactly the same cluster. To add a serverless v2 reader into an existing cluster, just make sure the existing cluster is configured with v2-compatible engine(mysql 8, postgres 13 and 14), which is a known condition described in the doc.

In this case, ServerlessV2ScalingConfiguration is not strictly required for a cluster to add serverless v2 instances. And users previously created their provisioned cluster with the existing rds.DatabaseCluster construct with v2-compatible cluster engine should be allowed to add serverless v2 instances in their existing clusters.

  1. In the DBCluster with v2 compatible cluster engine, you are allowed to in-place "convert" the existing instances from provisioned writer/reader to serverless writer/reader or vice versa. On instance modification, the instance enters the "Modifying" status in the console. I am not sure if the traffic will be switched off but obviously it can be in-place converted between provisioned and serverless instances. Amazing!

If we consider the existing clusters created with the rds.DatabaseCluster construct, we should allow them to:

  1. add a serverless v2 reader in addition to the existing provisioned writer and reader with CDK in the existing cluster.
  2. convert the existing provisioned writer/reader to serverless v2.
  3. enable the ServerlessV2ScalingConfiguration for the cluster.

Apart from above, we should allow them to create a new cluster with both serverless v2 writer and reader(s).

Sounds like we should extend the existing DatabaseCluster construct instead?

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: 4c05723
  • Result: FAILED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@rix0rrr rix0rrr self-assigned this Nov 9, 2022
@corymhall
Copy link
Contributor

I'm going to go ahead and close this for now since we are going the RFC route.

@corymhall corymhall closed this Nov 30, 2022
@ThuF
Copy link

ThuF commented Jan 26, 2023

@corymhall, @pahud, What's happening with the support for Aurora Serverless v2 construct?

@valentinsavenko
Copy link

where could we check the progress of this RFC route @corymhall?

I would really prefer to not have to go with the DbCluster workaround, instead of proper serverless v2 resource.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-rds Related to Amazon Relational Database contribution/core This is a PR that came from AWS. p2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(rds): support for Aurora Serverless V2
10 participants