Regiões¶
O Provisa oferece duas primitivas para posicionar dados: uma região e a atribuição de região, ou seja, criar uma região e atribuir uma tabela a ela. Nenhuma das duas é, por si só, uma política. O uso que você faz delas se divide em três grupos:
- Desempenho. A latência até quem lê, quão recente é a cópia, e a adequação do motor: onde fica o seu data center, que tipo de armazenamento ele lê, quanta CPU e memória ele tem.
- Custo. Onde o trabalho roda e sobre o quê: hardware próprio ou nuvem, um motor grande ou um pequeno, e o que custa mover dados entre lugares (egress).
- Soberania. Quem controla os dados e para onde eles podem ir: as regras de residência da lei (onde dados pessoais podem ser processados e onde podem ser armazenados) e as linhas de controle próprias de uma organização, como uma unidade de negócio ou uma subsidiária que mantém seus dados e sua infraestrutura sob o próprio controle.
A mecânica é a mesma para os três. Só mudam as regras que você escreve por cima.
Uma região é um motor com seus armazenamentos em um lugar¶
Uma região é um lugar onde o Provisa trabalha e guarda o que o trabalho deixa. Cada região tem seu próprio motor e seus próprios armazenamentos. (REQ-1922) [tool-verified: provisa/core/regions.py OrgRegion, STORE_ROLES]
| Armazenamento | O que guarda |
|---|---|
engine |
O motor de federação que executa instruções nesta região |
replicas |
Réplicas das tabelas atribuídas aqui e das tabelas sem região que esta região copia |
views |
As cópias de visões materializadas desta região |
cache |
Respostas em cache |
state |
Estado de construção e de atualização |
record |
O registro de cada requisição atendida aqui |
Um único modelo governa todas as regiões. Fontes, tabelas, relacionamentos, funções, regras de linha e de coluna, visões e configurações de frescor são declaradas uma vez, em um armazenamento de modelo, e todas as regiões servem esse mesmo modelo, de modo que as definições não podem divergir entre regiões. Uma mudança chega a cada região pelo mesmo carimbo, e cada região então converge para ela. (REQ-1914, REQ-1922)
A plataforma declara as regiões físicas em que seus nós rodam, com o endereço em que cada região responde. O modelo de cada organização escolhe quais dessas regiões usa e nomeia seu próprio armazenamento para cada papel em cada região. Um nó inicia em uma região com provisa run --region <id> e atende essa região para cada organização que a escolhe. Com regiões declaradas, um nó iniciado sem --region se recusa a iniciar e lista as regiões que poderia atender. (REQ-1922) [tool-verified: provisa/cli.py --region; provisa/core/regions.py validate_regions]
platform:
regions:
- { id: eu, address: "https://eu.provisa.example" }
- { id: us, address: "https://us.provisa.example" }
stores:
- { id: eu_engine, url: "${secret:eu-trino-url}", kind: trino }
- { id: us_engine, url: "${secret:us-trino-url}", kind: trino }
- { id: eu_data, url: "${secret:eu-pg-url}" }
- { id: us_data, url: "${secret:us-pg-url}" }
- { id: eu_cache, url: "${secret:eu-redis-url}" }
- { id: us_cache, url: "${secret:us-redis-url}" }
regions:
- { id: eu, engine: eu_engine, replicas: eu_data, views: eu_data, cache: eu_cache, state: eu_data, record: eu_data }
- { id: us, engine: us_engine, replicas: us_data, views: us_data, cache: us_cache, state: us_data, record: us_data }
PlatformRegion, StoreConfig and OrgRegion in provisa/core/regions.py]
Ao ser carregada, a configuração é recusada, com o motivo nomeado, se as regiões não se encaixam. Uma região precisa nomear um armazenamento declarado para cada papel. Seus replicas e views precisam ser o mesmo armazenamento, e seu armazenamento de motor precisa nomear um kind de motor. Com mais de uma região de plataforma, um arquivo de motor embutido é recusado, porque as outras regiões não conseguem alcançá-lo. [tool-verified: require_one_materialize_store, require_engine_kind, require_reachable_engine]
Várias regiões podem compartilhar uma instância de banco de dados, um Redis ou um bucket de armazenamento de objetos. Tudo o que uma região guarda leva a região no nome, então seus armazenamentos não colidem. (REQ-1922)
Uma implantação que não declara regiões tem uma região implícita e não mostra região em lugar nenhum. Não há campo de região nem opção --region, e uma configuração que nomeia uma região é recusada. (REQ-1922)
Atribuição de região: uma tabela nomeia sua região de origem¶
Uma tabela pode nomear uma das regiões da sua organização como região de origem. Essa é a única região que constrói e atualiza sua réplica, e a única que pode mantê-la quente. Todas as outras regiões leem a tabela a partir da réplica da região de origem, no local, no endereço que o modelo dá. As regras de linha e de coluna de quem lê entram nessa instrução, então a filtragem acontece na região de origem e só atravessa o que quem lê pode ver. (REQ-1921) [tool-verified: provisa/core/regions.py module docstring]
- Nenhuma outra região lê a fonte da tabela; elas leem só a réplica da região de origem. Uma fonte que você replica para protegê-la de carga continua protegida.
- Se a réplica não foi construída ou a região de origem não está acessível, a requisição é recusada, nomeando a região de origem. A fonte não é lida ao vivo em seu lugar.
- Uma tabela atribuída que não é replicada, com
replicateNever ou uma configuração que ainda não pediu uma cópia, é lida ao vivo da sua fonte por todas as regiões, como qualquer tabela não replicada. - A contagem quente de uma tabela é só o tráfego da sua região de origem. (REQ-239)
- Uma visão materializada também pode nomear uma região. Ela é então construída só ali, e todas as outras regiões leem essa cópia, exatamente como para uma tabela atribuída.
Uma região que lê a réplica de outra precisa de um motor capaz de lê-la: duckdb, motherduck, pg, trino ou trino-byo. O armazenamento replicas da região de origem precisa ser um servidor PostgreSQL. A configuração nomeia ambos quando não se encaixam. [tool-verified: require_readable_elsewhere; REGION_READERS in provisa/core/engine_kinds.py]
Uma fonte também pode nomear uma região, mas essa região só preenche o formulário quando você registra uma nova tabela da fonte. Ela não decide nada sobre onde os dados ficam, e mudá-la depois não move nenhuma tabela. (REQ-1921)
Tabelas sem região são copiadas onde são lidas¶
Uma tabela que não nomeia região pode ser copiada em todas as regiões. Quando sua configuração replicate pede uma cópia, a região a que quem lê se conectou constrói uma no próprio armazenamento. Uma visão materializada que não nomeia região é construída em todas as regiões, cada cópia no armazenamento de visões daquela região. (REQ-1921)
Acrescentar uma região significa, portanto, mais cópias e mais trabalho de atualização. Nunca significa mais governança. Um modelo governa todas as cópias, e as mesmas regras de linha e de coluna valem em todas as regiões. A construção de uma visão em uma região é governada como o administrador da organização agindo naquela região, então a cópia de cada região contém o que pode ser guardado ali. (REQ-1921, REQ-1922)
Três motivos para usar regiões¶
Desempenho¶
Regiões usadas só por desempenho não declaram regras entre regiões. As tabelas, as funções e as regras são as que você escreveria para uma única região, e a atribuição de região decide onde o trabalho acontece:
- Latência. Quem lê se conecta à região próxima, cujo motor, cache e cópias são locais para essa pessoa.
- Frescor. Uma tabela atribuída onde ela muda é atualizada ali, perto da sua fonte.
- Adequação do motor. Cada região roda seu próprio motor, então você pode ajustar um motor a um lugar: o data center em que ele fica, o armazenamento que ele lê, e a CPU e a memória que ele tem.
Exemplo: duas regiões idênticas. Declare east e west em dois data centers, cada uma com o mesmo tipo de motor e os mesmos tipos de armazenamento, e não atribua nenhuma tabela. Cada região atende quem lê mais perto dela: constrói as próprias cópias do que leem e guarda as respostas em cache. As duas podem ficar atrás de um balanceador de carga e dividir a carga. Há um único cronograma de atualização, o do modelo, e as duas regiões começam a atualizar suas cópias por ele, mas seus motores podem não terminar no mesmo tempo. Em um dado momento, então, não há garantia de que as duas estejam no mesmo estado, e quem lê e passa de uma região para a outra pode ver dados de frescor diferente. O Provisa não move um cliente para a outra região quando uma para; para onde um cliente vai é decisão do balanceador de carga. [inferred: no failover or cross-region redirect exists in provisa/; clients connect to a region by its address, and each region builds and refreshes only its own copies, on the model's one schedule (REQ-1922)]
Custo¶
Regiões de custo também não declaram regras entre regiões. Elas levam o trabalho para onde é mais barato rodá-lo:
- Hardware próprio e nuvem. Mantenha uma região no local, em hardware que você já tem, para as tabelas e os leitores que estão ali, e rode outra região na nuvem para o resto.
- Tamanho do motor. Rode um motor grande em uma região para trabalho pesado ocasional e um pequeno em outra para as leituras do dia a dia. Quem lê escolhe a região pelo endereço.
- Egress. Quem lê em outras regiões recebe só as linhas filtradas da réplica de uma tabela atribuída, e uma tabela grande atribuída a uma região não é copiada em todas as regiões.
Soberania¶
Regiões usadas por soberania declaram, sim, regras entre regiões, seja o motivo a lei ou a organização: uma subsidiária que atribui suas tabelas à própria região as faz processar e armazenar na própria infraestrutura, e decide por meio dessas regras o que o resto do grupo lê. São regras comuns de linha e de coluna, escritas sobre atributos que dizem onde está quem lê, ou o nó que faz o trabalho:
current_setting('provisa.region')é a região do nó que responde à requisição, quando a plataforma declara regiões. Um filtro de linha escrito sobre ele mantém as linhas de uma região naquela região. (REQ-1922) [tool-verified:provisa/core/request_context.pysession_vars_for]- O atributo
regionde um membro faz com que ele detenha as funções derivadasregioneregion__<value>, então uma entrada de máscara ou de concessão pode nomearanalyst+region__eu. O trabalho em segundo plano do próprio nó carrega sua região da mesma forma. (REQ-2057) Veja Funções: concedidas, derivadas e meta.
Junto com a atribuição, essas regras decidem o que atravessa uma fronteira. Os dados pessoais de uma tabela atribuída são armazenados e processados na sua região de origem, e quem lê em outro lugar recebe só o que suas regras permitem, filtrado na origem. Uma visão sem região construída em cada região contém o que um administrador daquela região pode ver, então a cópia de uma região pode incluir linhas que a cópia de outra região deixa de fora. (REQ-1921)
Quem pode atribuir uma tabela¶
Definir, mudar ou remover a região de uma tabela, de uma fonte ou de uma visão materializada move dados através de uma fronteira. Exige o direito data_residency além de ser dono do objeto pelo seu domínio. A concessão nomeia os valores que cobre: as regiões da organização e "sem região". Mover um objeto entre duas regiões exige uma concessão que cubra as duas. Um salvamento fora da concessão é recusado, nomeando o valor não coberto. (REQ-1921)
O direito existe só quando a plataforma declara regiões. A propriedade do domínio continua decidindo quem pode editar todo o resto do objeto. Uma região não confere direito próprio; uma organização que quer que as tabelas de uma região sejam administradas pelas pessoas daquela região dá a elas domínios próprios. (REQ-1921)
Uma tabela ou visão também pode ser posta em rascunho: fora de serviço e oferecida a nenhum leitor. Uma tabela registrada pela administração começa como rascunho. Seu responsável a pré-visualiza só nos nós da região que ela nomeia (uma que não nomeia nenhuma, onde o responsável está), e a cópia que essa pré-visualização grava é mantida nessa região para a liberação da tabela. Uma cópia que outra região tenha dela, de antes de sua região ser definida ou mudada, é retirada e removida como numa tabela publicada. Uma mudança entre regiões pode passar pelo rascunho, de modo que a tabela não é servida em lugar nenhum no intervalo: o lado da primeira região põe em rascunho, e o titular da segunda região assume o objeto definindo a sua região. (REQ-1921)
Veja também a demo de duas regiões.