Использование маршрутизации с зависимостью от данных для маршрутизации запроса в соответствующую базу данных

Применимо к: База данных SQL Azure

Маршрутизация с зависимостью от данных — это возможность использования данных в запросе для направления запроса к соответствующей базе данных. Это основная модель при работе с сегментированными базами данных. Контекст запроса также может использоваться для маршрутизации запроса, особенно если ключ сегментирования не является частью запроса. Каждый конкретный запрос или транзакция в приложении, которое использует зависящую от данных маршрутизацию, ограничены обращением к одной отдельной базе данных за раз. Для эластичных средств базы данных SQL Azure эта маршрутизация выполняется с помощью класса ShardMapManager (Java, .NET).

Приложение не должно отслеживать различные строки подключения или расположения базы данных, связанные с различными срезами данных в сегментированной среде. Вместо этого менеджер карты сегментов открывает подключения к нужным базам данных при необходимости, основываясь на данных карты сегментов и значении ключа сегментирования, который является целью запроса приложения. Обычно это ключ customer_id, tenant_id, date_key или другой конкретный идентификатор, являющийся основным параметром запроса к базе данных.

Это важно

Эластичные запросы в режиме диспетчера карт сегментов (горизонтальное секционирование), используя EXTERNAL DATA SOURCE тип SHARD_MAP_MANAGER, достигают конца поддержки 31 марта 2027 г. После этой даты существующие рабочие нагрузки будут продолжать функционировать, но больше не будут получать поддержку, а создание новых внешних источников данных типа SHARD_MAP_MANAGER больше не будет возможным. Сведения о параметрах миграции см. в руководстве по миграции из режима диспетчера сопоставления сегментов эластичных запросов.

Дополнительные сведения см. в статье Scaling Out SQL Server with Data Dependent Routing (Масштабирование SQL Server с помощью маршрутизации с зависимостью от данных).

Скачивание клиентской библиотеки

Скачать библиотеку можно из двух расположений:

Используйте ShardMapManager в приложении маршрутизации, зависящем от данных.

Приложения должны инициализировать ShardMapManager во время инициализации с помощью вызова фабрики GetSQLShardMapManager (Java, .NET). В этом примере инициализируются как ShardMapManager, так и конкретный ShardMap, содержащийся в нем. В этом примере показаны методы GetSqlShardMapManager и GetRangeShardMap (Java, .NET).

ShardMapManager smm = ShardMapManagerFactory.getSqlShardMapManager(connectionString, ShardMapManagerLoadPolicy.Lazy);
RangeShardMap<int> rangeShardMap = smm.getRangeShardMap(Configuration.getRangeShardMapName(), ShardKeyType.Int32);
ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(smmConnectionString, ShardMapManagerLoadPolicy.Lazy);
RangeShardMap<int> customerShardMap = smm.GetRangeShardMap<int>("customerMap"); 

Для получения карты сегментов используйте учетную запись с минимально возможными привилегиями.

Если приложение не работает с картой сегментов, учетные данные, используемые в методе фабрики, должны иметь разрешения только для чтения в базе данных глобального сопоставления сегментов. Обычно эти учетные данные отличаются от учетных данных, используемых в открытых подключениях к диспетчеру карты сегментов. См. также статью Учетные данные для доступа к клиентской библиотеке эластичной базы данных.

Вызовите метод OpenConnectionForKey.

Метод ShardMap.OpenConnectionForKey (Java, .NET) возвращает подключение, готовое для выдачи команд в соответствующую базу данных на основе значения key параметра. Информация о шардах кэшируется в приложении ShardMapManager, поэтому эти запросы обычно не включают обращение к базе данных Global Shard Map.

// Syntax:
public Connection openConnectionForKey(Object key, String connectionString, ConnectionOptions options)
// Syntax:
public SqlConnection OpenConnectionForKey<TKey>(TKey key, string connectionString, ConnectionOptions options)
  • Параметр key используется как ключ поиска в карте шардов, чтобы определить соответствующую базу данных для запроса.
  • Используется connectionString для передачи только учетных данных пользователя для требуемого подключения. Имя базы данных или имя сервера не включены в эту строку подключения , так как метод определяет базу данных и сервер с помощью ShardMap.
  • Значение connectionOptions (Java, .NET) должно быть задано ConnectionOptions.Validate, если это среда, где карты сегментов могут изменяться и строки могут перемещаться в другие базы данных в результате операций разделения или слияния. Эта проверка включает краткий запрос для сопоставления локальной карты сегментов в целевой базе данных (не на глобальной карте сегментов), прежде чем подключение предоставляется приложению.

В случае сбоя при проверке локальной карты сегментов (что означает неправильный кэш) диспетчер карты сегментов запрашивает глобальную карту сегментирования, чтобы получить новые правильные значения для поиска, обновления кэша и возобновления подключения к соответствующей базе данных.

Используйте ConnectionOptions.None только в том случае, если изменения сопоставления сегментов не ожидаются, пока приложение находится в сети. В этом случае можно предположить, что кэшированные значения всегда являются правильными, и дополнительный проверочный вызов в два конца к целевой базе данных можно безопасно пропустить. Это позволяет снизить объем трафика базы данных. connectionOptions также можно задать в файле конфигурации, чтобы указать, ожидаются ли изменения шардинга в течение определенного периода времени.

В этом примере используется значение целочисленного ключа CustomerID, используя объект ShardMap, названный customerShardMap.

int customerId = 12345;
int productId = 4321;
// Looks up the key in the shard map and opens a connection to the shard
try (Connection conn = shardMap.openConnectionForKey(customerId, Configuration.getCredentialsConnectionString())) {
    // Create a simple command that will insert or update the customer information
    PreparedStatement ps = conn.prepareStatement("UPDATE Sales.Customer SET PersonID = ? WHERE CustomerID = ?");

    ps.setInt(1, productId);
    ps.setInt(2, customerId);
    ps.executeUpdate();
} catch (SQLException e) {
    e.printStackTrace();
}
int customerId = 12345;
int newPersonId = 4321;

// Connect to the shard for that customer ID. No need to call a SqlConnection
// constructor followed by the Open method.
using (SqlConnection conn = customerShardMap.OpenConnectionForKey(customerId, Configuration.GetCredentialsConnectionString(), ConnectionOptions.Validate))
{
    // Execute a simple command.
    SqlCommand cmd = conn.CreateCommand();
    cmd.CommandText = @"UPDATE Sales.Customer
                        SET PersonID = @newPersonID WHERE CustomerID = @customerID";

    cmd.Parameters.AddWithValue("@customerID", customerId);cmd.Parameters.AddWithValue("@newPersonID", newPersonId);
    cmd.ExecuteNonQuery();
}  

Метод OpenConnectionForKey возвращает новое уже открытое подключение к правильной базе данных. Подключения, используемые в этом случае, по-прежнему имеют все преимущества объединенных подключений.

Метод OpenConnectionForKeyAsync (Java, .NET) также доступен, если приложение использует асинхронное программирование.

Интеграция с временной обработкой ошибок

При разработке облачных приложений для доступа к данным рекомендуется убедиться, что временные сбои перехватываются приложением и что попытка выполнения операции осуществляется несколько раз, прежде чем возникнет сообщение об ошибке. Обработка временных сбоев в облачных приложениях рассматривается в статье "Transient Fault Handling" (Обработка временных сбоев) (Java, .NET).

Обработка временных сбоев может естественным образом сосуществовать с шаблоном маршрутизации с зависимостью от данных. Основным требованием является повтор всего запроса доступа к данным, включая блок using , с которым осуществляется подключение с маршрутизацией, зависящей от данных. Предыдущий пример можно переписать следующим образом.

Пример. Маршрутизация, зависящая от данных, с обработкой временных сбоев

int customerId = 12345;
int productId = 4321;
try {
    SqlDatabaseUtils.getSqlRetryPolicy().executeAction(() -> {
        // Looks up the key in the shard map and opens a connection to the shard
        try (Connection conn = shardMap.openConnectionForKey(customerId, Configuration.getCredentialsConnectionString())) {
            // Create a simple command that will insert or update the customer information
            PreparedStatement ps = conn.prepareStatement("UPDATE Sales.Customer SET PersonID = ? WHERE CustomerID = ?");

            ps.setInt(1, productId);
            ps.setInt(2, customerId);
            ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    });
} catch (Exception e) {
    throw new StoreException(e.getMessage(), e);
}
int customerId = 12345;
int newPersonId = 4321;

Configuration.SqlRetryPolicy.ExecuteAction(() -> {

    // Connect to the shard for a customer ID.
    using (SqlConnection conn = customerShardMap.OpenConnectionForKey(customerId, Configuration.GetCredentialsConnectionString(), ConnectionOptions.Validate))
    {
        // Execute a simple command
        SqlCommand cmd = conn.CreateCommand();

        cmd.CommandText = @"UPDATE Sales.Customer
                            SET PersonID = @newPersonID
                            WHERE CustomerID = @customerID";

        cmd.Parameters.AddWithValue("@customerID", customerId);
        cmd.Parameters.AddWithValue("@newPersonID", newPersonId);
        cmd.ExecuteNonQuery();

        Console.WriteLine("Update completed");
    }
});

Пакеты, необходимые для реализации обработки временных сбоев, автоматически загружаются при построении примера приложения эластичной базы данных.

Согласованность транзакций

Свойства транзакций сохраняются для всех операций, являющихся локальными для сегмента. Например, транзакции, осуществленные посредством маршрутизации, зависящей от данных, выполняются в области целевого сегмента для подключения. В данный момент нет возможности связывания нескольких подключений с транзакцией, поэтому невозможно гарантировать осуществление транзакций для операций, выполняемых через сегменты.

Следующий шаг

Еще не используете средства эластичных баз данных? Ознакомьтесь с нашим руководством по началу работы. Возникшие вопросы вы можете задать нам на странице вопросов Microsoft Q&A по Базе данных SQL. Что касается запросов новых функций, вы можете поделиться новыми идеями или проголосовать за существующие на форуме отзывов по Базе данных SQL.