Use follower databases

The follower database feature allows you to attach a database located in a different cluster to your Azure Data Explorer cluster. The follower database is attached in read-only mode, making it possible to view the data and run queries on the data that was ingested into the leader database. The follower database synchronizes changes in the leader databases. Because of the synchronization, there's a data lag of a few seconds to a few minutes in data availability. The length of the time lag depends on the overall size of the leader database metadata. The leader and follower databases use the same storage account to fetch the data. The storage is owned by the leader database. The follower database views the data without needing to ingest it. Since the attached database is a read-only database, the data, tables, and policies in the database can't be modified except for caching policy, principals, and permissions. Attached databases can't be deleted. They must be detached by the leader or follower and only then they can be deleted.

Attaching a database to a different cluster using the follower capability is used as the infrastructure to share data between organizations and teams. The feature is useful to segregate compute resources to protect a production environment from non-production use cases. Follower can also be used to associate the cost of Azure Data Explorer cluster to the party that runs queries on the data.

Which databases are followed?

  • A cluster can follow one database, several databases, or all databases of a leader cluster.
  • A single cluster can follow databases from multiple leader clusters.
  • A cluster can contain both follower databases and leader databases.
  • EngineV3 clusters can only follow EngineV3 clusters, similarly EngineV2 clusters can only follow V2 clusters.

Prerequisites

Attach a database

There are various methods you can use to attach a database. In this article, we discuss attaching a database using C#, Python, PowerShell, or an Azure Resource Manager template. To attach a database, you must have user, group, service principal, or managed identity with at least contributor role on the leader cluster and the follower cluster. Add or remove role assignments using Azure portal, PowerShell, Azure CLI, and ARM template. Learn more about Azure role-based access control (Azure RBAC) and the different roles.

Table level sharing

When attaching the database all tables, external tables and materialized views are followed as well. You can share specific tables/external tables/materialized views by configuring the 'TableLevelSharingProperties'.

'TableLevelSharingProperties' contains six arrays of strings: tablesToInclude, tablesToExclude, externalTablesToInclude, externalTablesToExclude, materializedViewsToInclude, and materializedViewsToExclude. The maximum number of entries in all arrays together is 100.

Note

Table level sharing is not supported when using '*' all databases notation.

Note

When materialized views are included, their source tables are included as well.

Examples

  1. Include all tables. No '*' is needed, since all tables are followed by default:

    tablesToInclude = []
    
  2. Include all tables with names that start with "Logs":

    tablesToInclude = ["Logs*"]
    
  3. Exclude all external tables:

    externalTablesToExclude = ["*"]
    
  4. Exclude all materialized views:

    materializedViewsToExclude=["*"]
    

Attach a database using C#

Prerequisite nuggets

C# example

var tenantId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";//Directory (tenant) ID
var clientId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";//Application ID
var clientSecret = "xxxxxxxxxxxxxx";//Client secret
var leaderSubscriptionId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";
var followerSubscriptionId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";

var serviceCreds = await ApplicationTokenProvider.LoginSilentAsync(tenantId, clientId, clientSecret);
var resourceManagementClient = new KustoManagementClient(serviceCreds){
    SubscriptionId = followerSubscriptionId
};

var followerResourceGroupName = "followerResouceGroup";
var leaderResourceGroup = "leaderResouceGroup";
var leaderClusterName = "leader";
var followerClusterName = "follower";
var attachedDatabaseConfigurationName = "uniqueNameForAttachedDatabaseConfiguration";
var databaseName = "db"; // Can be specific database name or * for all databases
var defaultPrincipalsModificationKind = "Union";
var location = "China East 2";


TableLevelSharingProperties tls;
if (databaseName == "*")
{
    // Table level sharing properties are not supported when using '*' all databases notation.
    tls = null;
}
else
{
    // Set up the table level sharing properties - the following is just an example.
    var tablesToInclude = new List<string>
    {
        "table1",
        "table2",
        "table3"
    };
    var externalTablesToExclude = new List<string>
    {
        "Logs*"
    };
    var tls = new TableLevelSharingProperties(tablesToInclude: tablesToInclude, externalTablesToExclude: externalTablesToExclude);
}


AttachedDatabaseConfiguration attachedDatabaseConfigurationProperties = new AttachedDatabaseConfiguration()
{
    ClusterResourceId = $"/subscriptions/{leaderSubscriptionId}/resourceGroups/{leaderResourceGroup}/providers/Microsoft.Kusto/Clusters/{leaderClusterName}",
    DatabaseName = databaseName,
    DefaultPrincipalsModificationKind = defaultPrincipalsModificationKind,
    Location = location,
    TableLevelSharingProperties = tls
};

var attachedDatabaseConfigurations = resourceManagementClient.AttachedDatabaseConfigurations.CreateOrUpdate(followerResourceGroupName, followerClusterName, attachedDatabaseConfigurationName, attachedDatabaseConfigurationProperties);

Verify that the database was successfully attached

To verify that the database was successfully attached, find your attached databases in the Azure portal. You can verify the databases were successfully attached in either the follower or leader clusters.

Check your follower cluster

  1. Navigate to the follower cluster and select Databases

  2. Search for new Read-only databases in the database list.

    Read-only follower database.

Check your leader cluster

  1. Navigate to the leader cluster and select Databases

  2. Check that the relevant databases are marked as SHARED WITH OTHERS > Yes

    Read and write attached databases.

Detach the follower database

Note

To detach a database from the follower or leader side, you must have user, group, service principal, or managed identity with at least contributor role on the cluster from which you are detaching the database. In the example below, we use service principal.

Detach the attached follower database from the follower cluster using C#**

The follower cluster can detach any attached follower database as follows:

var tenantId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";//Directory (tenant) ID
var clientId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";//Application ID
var clientSecret = "xxxxxxxxxxxxxx";//Client secret
var leaderSubscriptionId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";
var followerSubscriptionId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";

var serviceCreds = await ApplicationTokenProvider.LoginSilentAsync(tenantId, clientId, clientSecret);
var resourceManagementClient = new KustoManagementClient(serviceCreds){
    SubscriptionId = followerSubscriptionId
};

var followerResourceGroupName = "testrg";
//The cluster and database that are created as part of the prerequisites
var followerClusterName = "follower";
var attachedDatabaseConfigurationsName = "uniqueName";

resourceManagementClient.AttachedDatabaseConfigurations.Delete(followerResourceGroupName, followerClusterName, attachedDatabaseConfigurationsName);

Detach the attached follower database from the leader cluster using C#

The leader cluster can detach any attached database as follows:

var tenantId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";//Directory (tenant) ID
var clientId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";//Application ID
var clientSecret = "xxxxxxxxxxxxxx";//Client secret
var leaderSubscriptionId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";
var followerSubscriptionId = "xxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx";

var serviceCreds = await ApplicationTokenProvider.LoginSilentAsync(tenantId, clientId, clientSecret);
var resourceManagementClient = new KustoManagementClient(serviceCreds){
    SubscriptionId = leaderSubscriptionId
};

var leaderResourceGroupName = "testrg";
var followerResourceGroupName = "followerResouceGroup";
var leaderClusterName = "leader";
var followerClusterName = "follower";
//The cluster and database that are created as part of the Prerequisites
var followerDatabaseDefinition = new FollowerDatabaseDefinition()
    {
        AttachedDatabaseConfigurationName = "uniqueName",
        ClusterResourceId = $"/subscriptions/{followerSubscriptionId}/resourceGroups/{followerResourceGroupName}/providers/Microsoft.Kusto/Clusters/{followerClusterName}"
    };

resourceManagementClient.Clusters.DetachFollowerDatabases(leaderResourceGroupName, leaderClusterName, followerDatabaseDefinition);

Manage principals, permissions, and caching policy

Manage principals

When attaching a database, specify the "default principals modification kind". The default is to combine the override authorized principals with the leader database collection of authorized principals

Kind Description
Union The attached database principals will always include the original database principals plus other new principals added to the follower database.
Replace No inheritance of principals from the original database. New principals must be created for the attached database.
None The attached database principals include only the principals of the original database with no other principals.

For more information about using control commands to configure the authorized principals, see Control commands for managing a follower cluster.

Manage permissions

Managing read-only database permission is the same as for all database types. See manage permissions in the Azure portal.

Configure caching policy

The follower database administrator can modify the caching policy of the attached database or any of its tables on the hosting cluster. The default is to combine the source database in the leader cluster database and table-level caching policies with the policies defined in the database and table-level override policies. You can, for example, have a 30 day caching policy on the leader database for running monthly reporting and a three day caching policy on the follower database to query only the recent data for troubleshooting. For more information about using control commands to configure the caching policy on the follower database or table, see Control commands for managing a follower cluster.

Notes

  • If there are conflicts between databases of leader/follower clusters, when all databases are followed by the follower cluster, they're resolved as follows:
    • A database named DB created on the follower cluster takes precedence over a database with the same name that was created on the leader cluster. That's why database DB in the follower cluster needs to be removed or renamed for the follower cluster to include the leader's database DB.
    • A database named DB followed from two or more leader clusters will be arbitrarily chosen from one of the leader clusters, and won't be followed more than once.
  • Commands for showing cluster activity log and history run on a follower cluster will show the activity and history on the follower cluster, and their result sets won't include those results of the leader cluster or clusters.
    • For example: a .show queries command run on the follower cluster will only show queries run on databases followed by follower cluster, and not queries run against the same database in the leader cluster.

Limitations

  • The follower and the leader clusters must be in the same region.
  • If Streaming ingestion is used on a database that is being followed, the follower cluster should be enabled for Streaming Ingestion to allow following of streaming ingestion data.
  • Data encryption using customer managed keys isn't supported on both leader and follower clusters.
  • You can't delete a database that is attached to a different cluster before detaching it.
  • You can't delete a cluster that has a database attached to a different cluster before detaching it.
  • Table level sharing properties aren't supported when following all database.

Next steps