Conector do Spark do Azure Cosmos DB: controle de taxa de transferência

APLICA-SE A: NoSQL

O conector do Spark permite que você se comunique com o Azure Cosmos DB usando o Apache Spark. Este artigo descreve como funciona o recurso de controle de taxa de transferência. Confira nossos Exemplos do Spark em GitHub para começar a usar o controle de taxa de transferência.

Este artigo documenta o uso de grupos de controle de taxa de transferência global no conector do Spark do Azure Cosmos DB, mas a funcionalidade também está disponível no SDK do Java. No SDK, é possível usar grupos globais e locais de controle de taxa de transferência para limitar o consumo de RU (unidade de solicitação) no contexto de uma única instância de conexão de cliente. Por exemplo, você pode aplicar essa abordagem a diferentes operações em um único microsserviço ou talvez a um único programa de carregamento de dados. Para obter mais informações, confira como usar o controle de taxa de transferência no SDK do Java.

Aviso

Não há suporte para o controle de taxa de transferência para o modo de gateway. Atualmente, para contas do Azure Cosmos DB sem servidor, a tentativa de usar targetThroughputThreshold para definir uma porcentagem resultará em falha. Você só pode fornecer um valor absoluto para a taxa de transferência/RU de destino usando spark.cosmos.throughputControl.targetThroughput.

Por que o controle de taxa de transferência é importante?

O controle de taxa de transferência ajuda a isolar as necessidades de desempenho de aplicativos executados em um contêiner. O controle de taxa de transferência limita a quantidade de RUs que um cliente Spark específico pode consumir.

Vários cenários avançados se beneficiam do controle de taxa de transferência no lado do cliente:

  • Operações e tarefas diferentes têm prioridades diferentes: pode ser necessário evitar que transações normais sejam limitadas por causa da ingestão de dados ou das atividades de cópia. Algumas operações ou tarefas não são sensíveis à latência e são mais tolerantes à limitação do que outras.
  • Fornecer equidade/isolamento para diferentes usuários ou locatários: um aplicativo geralmente tem muitos usuários. Alguns usuários podem enviar muitas solicitações, que consomem toda a taxa de transferência disponível e fazem com que outros sejam limitados.
  • Balanceamento de carga da taxa de transferência entre diferentes clientes do Azure Cosmos DB: em alguns casos de uso, é importante garantir que todos os clientes obtenham uma participação justa (igual) da taxa de transferência.

O controle de taxa de transferência permite a capacidade de limitação de taxa de RU de nível mais granular, conforme necessário.

Como funciona o controle de taxa de transferência?

Para configurar o controle de taxa de transferência para o conector do Spark, primeiro crie um contêiner que defina metadados de controle de taxa de transferência. A chave de partição é groupId e ttl está habilitada. Aqui, crie esse contêiner usando o Spark SQL e o chama de ThroughputControl:

    %sql
    CREATE TABLE IF NOT EXISTS cosmosCatalog.`database-v4`.ThroughputControl 
    USING cosmos.oltp
    OPTIONS(spark.cosmos.database = 'database-v4')
    TBLPROPERTIES(partitionKeyPath = '/groupId', autoScaleMaxThroughput = '4000', indexingPolicy = 'AllProperties', defaultTtlInSeconds = '-1');

O exemplo anterior cria um contêiner com escala automática. Se preferir o provisionamento padrão, você poderá substituir autoScaleMaxThroughput por manualThroughput.

Importante

A chave de partição deve ser definida como /groupId e ttl deve estar habilitada para que o recurso de controle de taxa de transferência funcione.

Na configuração do Spark de um aplicativo específico, você pode especificar parâmetros para a carga de trabalho. O exemplo a seguir define o controle de taxa de transferência como enabled. O exemplo define um parâmetro name de grupo de controle de taxa de transferência e um parâmetro targetThroughputThreshold. Você também define os parâmetros database e container nos quais o grupo de controle de taxa de transferência é mantido:

    "spark.cosmos.throughputControl.enabled" -> "true",
    "spark.cosmos.throughputControl.name" -> "SourceContainerThroughputControl",
    "spark.cosmos.throughputControl.targetThroughputThreshold" -> "0.95", 
    "spark.cosmos.throughputControl.globalControl.database" -> "database-v4", 
    "spark.cosmos.throughputControl.globalControl.container" -> "ThroughputControl"

No exemplo anterior, o parâmetro targetThroughputThreshold é definido como 0,95. A limitação de taxa ocorre (e as solicitações são repetidas) quando os clientes consomem mais de 95% (+/- 5-10%) da taxa de transferência alocada para o contêiner. Essa configuração é armazenada como um documento no contêiner de taxa de transferência, que se parece com este exemplo:

    {
        "id": "ZGF0YWJhc2UtdjQvY3VzdG9tZXIvU291cmNlQ29udGFpbmVyVGhyb3VnaHB1dENvbnRyb2w.info",
        "groupId": "database-v4/customer/SourceContainerThroughputControl.config",
        "targetThroughput": "",
        "targetThroughputThreshold": "0.95",
        "isDefault": true,
        "_rid": "EHcYAPolTiABAAAAAAAAAA==",
        "_self": "dbs/EHcYAA==/colls/EHcYAPolTiA=/docs/EHcYAPolTiABAAAAAAAAAA==/",
        "_etag": "\"2101ea83-0000-1100-0000-627503dd0000\"",
        "_attachments": "attachments/",
        "_ts": 1651835869
    }

O controle de taxa de transferência não faz o pré-cálculo de RU de cada operação. Em vez disso, ele controla os usos de RU após a operação com base no cabeçalho de resposta. Dessa forma, o controle de taxa de transferência baseia-se em uma aproximação e não garante que a quantidade de taxa de transferência esteja disponível para o grupo em um determinado momento.

Por esse motivo, se a RU configurada for tão baixa que uma única operação possa usá-la toda, o controle de taxa de transferência não poderá evitar que a RU ultrapasse o limite configurado. O controle de taxa de transferência funciona melhor quando o limite configurado é maior do que qualquer operação individual que um cliente no grupo de controle específico possa executar.

Ao ler por meio de consulta ou feed de alterações, você deve configurar o tamanho da página em spark.cosmos.read.maxItemCount (padrão 1000) para ser uma quantidade modesta. Dessa forma, o controle de taxa de transferência do cliente pode ser recalculado com maior frequência e refletido com mais precisão em qualquer momento específico. Ao usar o controle de taxa de transferência para um trabalho de gravação em massa, o número de documentos executados em uma única solicitação é automaticamente ajustado com base na taxa de limitação para permitir que o controle de taxa de transferência comece o mais cedo possível.

Aviso

O parâmetro targetThroughputThreshold é imutável. Se você alterar o valor do limite de taxa de transferência de destino, será criado um novo grupo de controle de taxa de transferência. (Se você usar a versão 4.10.0 ou posterior, ela poderá ter o mesmo nome.) Você precisa reiniciar todos os trabalhos do Spark que estão usando o grupo se quiser garantir que todos eles consumam o novo limite imediatamente. Caso contrário, eles atingirão o novo limite após a próxima reinicialização.

Para cada cliente Spark que usa o grupo de controle de taxa de transferência, um registro é criado no contêiner ThroughputControl, com um ttl de alguns segundos. Como resultado, os documentos desaparecerão rapidamente se um cliente Spark não estiver mais em execução ativamente. Veja um exemplo:

    {
        "id": "Zhjdieidjojdook3osk3okso3ksp3ospojsp92939j3299p3oj93pjp93jsps939pkp9ks39kp9339skp",
        "groupId": "database-v4/customer/SourceContainerThroughputControl.config",
        "_etag": "\"1782728-w98999w-ww9998w9-99990000\"",
        "ttl": 10,
        "initializeTime": "2022-06-26T02:24:40.054Z",
        "loadFactor": 0.97636377638898,
        "allocatedThroughput": 484.89444487847,
        "_rid": "EHcYAPolTiABAAAAAAAAAA==",
        "_self": "dbs/EHcYAA==/colls/EHcYAPolTiA=/docs/EHcYAPolTiABAAAAAAAAAA==/",
        "_etag": "\"2101ea83-0000-1100-0000-627503dd0000\"",
        "_attachments": "attachments/",
        "_ts": 1651835869
    }

Em cada registro de cliente, o atributo loadFactor representa a carga no cliente específico, em relação a outros clientes no grupo de controle de taxa de transferência. O atributo allocatedThroughput mostra quantas RUs estão alocadas atualmente para esse cliente. O conector do Spark ajusta a taxa de transferência alocada para cada cliente com base em sua carga. Dessa forma, cada cliente recebe uma parte da taxa de transferência disponível proporcional à sua carga. Todos os clientes juntos não consomem mais do que o total alocado para o grupo de controle de taxa de transferência ao qual pertencem.