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

Astra multi-tenancy - Shard Assignment #25

Open
wants to merge 15 commits into
base: airbnb-main
Choose a base branch
from

Conversation

zarna1parekh
Copy link
Collaborator

@zarna1parekh zarna1parekh commented Feb 25, 2025

Summary

Proposal doc

This PR implements 5 GRPC API calls in cluster manager.

Implementation to manage PartitionMetadata related information is also added. The PartitionMetadata tracks each partitions utilization and isShared status.

CreatePartition --> Creates a Partition in ASTRA zookeeper map.

curl \-XPOST \-H 'content-type: application/json; charset=utf-8; protocol=gRPC' http://localhost:8083'/slack.proto.astra.ManagerApiService/CreatePartition' \-d '{  
"partition_id": "1",
"utilization": 1000000,
"is_partition_shared": true
}'

{"partitionId":"1","utilization":"1000000","isPartitionShared":true}%

GetPartition --> Get Partition metadata information from zookeeper about a request partition ID

curl \-XPOST \-H 'content-type: application/json; charset=utf-8; protocol=gRPC' http://localhost:8083'/slack.proto.astra.ManagerApiService/GetPartition' \-d '{
"partition_id": "1"
}'

{"partitionId":"1","utilization":"1000000","isPartitionShared":true}%

CreateTenant --> Create a new Tenant in ASTRA. Find partitions which has capacity and assign to the new tenant programmatically.

curl \-XPOST \-H 'content-type: application/json; charset=utf-8; protocol=gRPC' http://localhost:8083'/slack.proto.astra.ManagerApiService/CreateTenant' \-d '{  
"name": "tenant1",
"owner": "[email protected]",
"service_name_pattern": "mimir",
"throughput_bytes": 1000000,
"require_dedicated_partitions": true
}'

{"name":"tenant1","owner":"[email protected]","throughputBytes":"1000000","partitionConfigs":[{"startTimeEpochMs":"1741305186731","endTimeEpochMs":"9223372036854775807","partitions":["1","10"],"usingDedicatedPartition":true}],"serviceNamePattern":"mimir"}%

RemoveTenant --> remove a tenant currently taking traffic from ASTRA. Indirectly, manages the partitions utilization also.

curl \-XPOST \-H 'content-type: application/json; charset=utf-8; protocol=gRPC' http://localhost:8083'/slack.proto.astra.ManagerApiService/RemoveTenant' \-d '{  
"name": "tenant1"
}'

{"status": "Removed tenant tenant1 successfully."}%

UpdateTenant --> update throughput and / or dedicated partition requirement for a tenant. Indirectly, manages the partitions utilization also.

curl \-XPOST \-H 'content-type: application/json; charset=utf-8; protocol=gRPC' http://localhost:8083'/slack.proto.astra.ManagerApiService/ReassignTenant' \-d '{  
"name": "tenant1",
"throughput_bytes": 2000000,
"require_dedicated_partitions": true
}'

{"name":"tenant1","owner":"[email protected]","throughputBytes":"2000000","partitionConfigs":[{"startTimeEpochMs":"1741305186731","endTimeEpochMs":"1741305421528","partitions":["2","3"]},{"startTimeEpochMs":"1741305421529","endTimeEpochMs":"9223372036854775807","partitions":["1","10"]}],"serviceNamePattern":"mimir"}%

Note: Currently, I have not incorporated per tenant schema validation when sharing partitions since we do not have per tenant schema implemented. Once, we have that in future, we will need to account for that also when assigning shared partitions.

Testing

  • Tested in local dev env by running various APIs.
  • Added testcases for new APIs and related methods.

Requirements

@zarna1parekh zarna1parekh changed the title [WIP] Astra multi-tenancy - Shard Assignment Astra multi-tenancy - Shard Assignment Mar 7, 2025
long startTimeEpochMs,
long endTimeEpochMs,
List<String> partitions,
boolean usingDedicatedPartition) {
Copy link

Choose a reason for hiding this comment

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

Why do we need usingDedicatedPartition field here? I think we can drop it.

import com.slack.astra.metadata.core.AstraMetadata;
import java.util.Objects;

/** PartitionMetadata Object to track the utilization and isPartitionShared in zookeeper */
Copy link

Choose a reason for hiding this comment

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

Please expand on the class doc. PartitionMetadata Object is used to track the utilization of a kafka partition in Zookeeper. isPartitionShared field is set when this partition is shared by multiple tenants. If false, this partition is used by a single tenant.

public class PartitionMetadata extends AstraMetadata {
public final String partitionId;
public final long utilization;
public final boolean isPartitionShared;
Copy link

Choose a reason for hiding this comment

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

minor nit but isSharedPartition may be more appropriate.

* @param requireDedicatedPartition - if dedicated partitions are required
* @return list of string of partition ids
*/
public List<String> findPartition(long requiredThroughput, boolean requireDedicatedPartition)
Copy link

Choose a reason for hiding this comment

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

The PartitionMetadataStore should only contain the logic related to ZK interactions. Move the business logic to calculate the partitions to the Cluster manager logic. Keep this class for updating ZK structs only.

public class PartitionMetadataStore extends AstraMetadataStore<PartitionMetadata> {
public static final String PARTITION_MAP_METADATA_STORE_ZK_PATH = "/partition_map";

public static final int PARTITION_CAPACITY = 5000000;
Copy link

Choose a reason for hiding this comment

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

Please add a TODO to make this a config.

int numberOfPartitions = getPartitionCount(requiredThroughput);

long perPartitionCapacity = requiredThroughput / numberOfPartitions;
// we want minimum of two partitions assigned to a tenant for redundancy purpose
Copy link

Choose a reason for hiding this comment

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

Please make the minimum number of partitions also configurable. Some use cases may need 3.

new PartitionMetadata(partitionMetadata.partitionId, perPartitionCapacity, false));
}
} else {
// add logic for shared partition here
Copy link

Choose a reason for hiding this comment

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

Also, this code can use a comment. Clean up comments?

return partitionIdsList;
}
}
Thread.sleep(500); // to handle local cache sync
Copy link

Choose a reason for hiding this comment

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

This sleep is an anti-pattern since it can take longer to update the ZK data. Can we re-write this code without using sleep? It may be better to limit the manager grpc such that there is one of these operations happening at a time, so we can change this utilization without the sleep.

}
}
Thread.sleep(500); // to handle local cache sync
// if we reached here means we did not find required number of partitions
Copy link

Choose a reason for hiding this comment

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

Should this comment be before return? Is List.of() better than collections.emptyList() here?

rpc CreatePartition(CreatePartitionRequest) returns (PartitionMetadata) {}

// GetPartition returns a single partition metadata by partition_id
rpc GetPartition(GetPartitionRequest) returns (PartitionMetadata) {}
Copy link

Choose a reason for hiding this comment

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

ListPartitions to return all partitions may be a better API here since user needs to know how many partitions there are. We can keep the GetPartition API also, but we can skip it in favor of ListPartitions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added a new GRPC API ListPartition

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants