Todos os produtos
Search
Central de documentação

ApsaraDB for HBase:Como projetar uma Rowkey

Última atualização: Jun 27, 2026

A rowkey é o identificador exclusivo de cada linha em uma tabela do HBase. Ela controla o armazenamento, o particionamento e o acesso aos dados. Projete as rowkeys com cuidado antes de gravar dados em grande escala.

Este tópico aborda cinco considerações de projeto, com compensações e exemplos para dados de log e transacionais.

Funcionamento das rowkeys

Métodos de consulta

O HBase oferece dois métodos de consulta, cada um com restrições diferentes no projeto da rowkey:

Método

Descrição

Restrição

GET

Busca uma única linha pela rowkey completa

Todos os campos que compõem a rowkey devem ser conhecidos

Scan

Lê um intervalo de linhas entre uma chave inicial e uma final

Apenas intervalos baseados em prefixo são suportados

Restrição de prefixo para scans: Um scan corresponde a linhas que começam com um determinado prefixo, mas não consulta por sufixo nem corresponde a valores no meio de uma rowkey. Por exemplo, se as rowkeys forem palavras de dicionário, um scan encontra todas as palavras iniciadas com pre, mas não localiza palavras terminadas em ing.

Para consultas inexistentes como scan de prefixo, adote uma das seguintes abordagens:

  • Crie uma tabela de índice com estrutura de chave invertida

  • Aplique um filtro no servidor para descartar linhas indesejadas

  • Use índices secundários

Unicidade da rowkey e versões

Linhas com a mesma rowkey funcionam como um único registro com múltiplas versões. Por padrão, a operação GET retorna a versão mais recente. As rowkeys devem ser exclusivas, exceto se você usar intencionalmente o Controle de Concorrência Multiversão (MVCC).

Trate a rowkey como uma chave primária de banco de dados. Ela pode ser um único campo ou uma composição de vários campos:

  • [user_id] — um registro por usuário

  • [user_id][order_id] — múltiplos registros por usuário

Considerações de projeto

Distribuição de dados: evite hot spots

O HBase distribui as linhas pelos servidores Region por intervalo de rowkey (ordem lexicográfica). Se muitas gravações compartilharem um prefixo comum — por exemplo, uma chave iniciada por timestamp como 2024-01-01T00:00:01 — todas as gravações vão para o mesmo servidor Region. Isso cria um hot spot que degrada o throughput de gravação e deixa outros servidores ociosos.

Distribua as gravações entre os servidores Region com uma das técnicas a seguir:

Salting com prefixo hash

Adicione os primeiros caracteres de um hash MD5 ao início da rowkey. Como o hash é determinístico, a mesma entrada sempre mapeia para o mesmo prefixo, mantendo as leituras eficientes.

[md5(user_id).subStr(0, 4)][user_id][order_id]

Compensação: as linhas do mesmo usuário ficam espalhadas por diferentes Regions. Para fazer scan de um intervalo referente a um único usuário, execute múltiplos GETs direcionados ou um scan com filtro.

Inversão da chave

Inverta o campo de prefixo de alta cardinalidade. Por exemplo, inverter um ID de usuário que incrementa ao longo do tempo randomiza os bytes iniciais.

[reverse(user_id)][order_id]

Compensação: a ordenação natural se perde; portanto, scans de intervalo no campo invertido perdem o sentido.

Bucketing com módulo

Atribua cada linha a um bucket usando uma operação de módulo e adicione o número do bucket como prefixo. Essa técnica é eficaz para dados de séries temporais em que os timestamps aumentam monotonicamente.

long bucket = timestamp % numBuckets;
[bucket][timestamp][hostname][log_event]

Compensação: para recuperar todos os dados de um intervalo de tempo, faça scan de todos os intervalos de numBuckets e mescle os resultados.

Adição de sufixo aleatório

Anexe um número aleatório para distribuir as gravações por várias linhas.

[user_id][order_id][random(100)]

Compensação: ler um registro específico exige conhecer o sufixo aleatório. Consultas pontuais tornam-se impraticáveis sem um índice.

Como escolher: Se precisar fazer scan nas linhas distribuídas (não apenas buscar registros individuais), prefira hashing em vez de sufixos aleatórios. O hashing é determinístico, permitindo rotear as leituras com eficiência.

Tamanho da rowkey: mantenha-a curta

As rowkeys são armazenadas junto com cada valor de coluna no HBase. Uma rowkey longa multiplica a sobrecarga de armazenamento em cada coluna de cada linha. Mantenha as rowkeys o mais curtas possível:

  • Substitua strings por tipos numéricos. Um long ocupa 8 bytes; a string "2015122410" ocupa 10 bytes, e uma string MD5 ocupa 32 bytes. Use Long(2015122410) em vez de "2015122410".

  • Use códigos em vez de nomes completos. Por exemplo, use tb em vez de "Taobao".

Clareza nos limites dos campos: evite correspondências parciais

Quando uma rowkey combina vários campos sem delimitadores, um intervalo de scan pode retornar linhas extras. Por exemplo, se a rowkey for [column1][column2][column3] e você fizer scan de host1 até host2, a linha host12... também cairá nesse intervalo.

Duas abordagens evitam esse problema:

Fixed-length padding: Preencha cada campo até uma largura fixa para tornar os limites inequívocos.

[rpad(column1, 'x', 20)][column2]

Delimiter: Separe os campos com um caractere delimitador.

[column1][_][column2]

O preenchimento de tamanho fixo é mais eficiente para scans. Os delimitadores facilitam a leitura.

Ordem decrescente: use timestamps invertidos

Por padrão, os scans do HBase retornam linhas em ordem crescente de chave. Se precisar das entradas mais recentes primeiro, escolha uma das duas opções:

Opção 1: API de scan reverso (scan.setReverse(true))

Mais simples de implementar, mas os scans reversos têm desempenho inferior aos scans diretos. Utilize esta opção quando a ordem decrescente for um requisito ocasional.

Opção 2: Timestamp invertido na rowkey

Armazene Long.MAX_VALUE - timestamp em vez do timestamp original. Isso inverte a ordem de classificação natural, fazendo com que as entradas mais novas apareçam primeiro em um scan direto.

timestamp = Long.MAX_VALUE - timestamp;
[hostname][log_event][timestamp]

Utilize esta opção quando a ordem decrescente for o padrão de acesso principal e o desempenho do scan for crítico.

Exemplos de projeto

O projeto adequado da rowkey depende dos seus padrões de acesso principais. O mesmo conjunto de dados pode exigir um projeto diferente dependendo da forma de consulta. Os exemplos abaixo mostram como os padrões de acesso orientam as decisões de projeto.

Dados de log e de séries temporais

Os elementos de dados são: hostname, log_event, timestamp.

Padrão de acesso

Projeto da rowkey

Observações

Consultar uma métrica de um host em um intervalo de tempo

[hostname][log_event][timestamp]

Eficiente para scans de intervalo por host. Pode criar hot spots se um único host dominar as gravações

Consultar os registros mais recentes de um host

[hostname][log_event][Long.MAX_VALUE - timestamp]

O timestamp invertido coloca as entradas mais recentes primeiro em um scan direto

Distribuir gravações uniformemente ao longo do tempo (grandes volumes de dados ou nenhum host dominante)

[bucket][timestamp][hostname][log_event] onde bucket = timestamp % numBuckets

Requer scan de todos os intervalos de buckets para agregar resultados de um intervalo de tempo

Como escolher: Comece com [hostname][log_event][timestamp] se as consultas de intervalo por host forem o caso de uso principal. Mude para o padrão de bucket se surgirem hot spots de gravação ou se as consultas de intervalo de tempo abrangerem muitos hosts.

Dados transacionais

Uma transação envolve três funções: comprador, vendedor e número do pedido. Diferentes padrões de acesso exigem diferentes projetos de rowkey e, frequentemente, múltiplas tabelas.

Padrão de acesso

Tabela

Projeto da rowkey

Consultar pedidos de um vendedor em um intervalo de tempo

Tabela de vendedores

[seller_id][timestamp][order_number]

Consultar pedidos de um comprador em um intervalo de tempo

Tabela de compradores

[buyer_id][timestamp][order_number]

Buscar um pedido pelo número do pedido

Tabela de índice

[order_number]

Projete todas as três tabelas para cobrir os três padrões de acesso. Use a tabela de índice para buscar o order_number e, em seguida, consulte a tabela de compradores ou vendedores com esse valor.

Próximos passos

  • Visão geral do modelo de dados do HBase

  • Índices secundários no HBase

  • Ajuste de desempenho para tabelas do HBase