Ir para o conteúdoIr para navegação de página: página anterior [tecla de acesso p]/próxima página [tecla de acesso n]
documentation.suse.com / Documentação do SUSE Enterprise Storage 7 / Guia de Operações e Administração / Armazenando dados em um cluster / Gerenciamento de dados armazenados
Aplica-se a SUSE Enterprise Storage 7

17 Gerenciamento de dados armazenados

O algoritmo CRUSH determina como armazenar e recuperar dados calculando os locais de armazenamento de dados. O CRUSH permite que os clientes do Ceph se comuniquem diretamente com os OSDs, sem a necessidade de um servidor centralizado ou um controlador. Com um método de armazenamento e recuperação de dados determinado por algoritmo, o Ceph evita um ponto único de falha, gargalo no desempenho e limite físico à escalabilidade.

O CRUSH requer um mapa do cluster e usa o Mapa CRUSH para armazenar e recuperar dados de forma pseudo-aleatória nos OSDs com uma distribuição uniforme dos dados pelo cluster.

Os mapas CRUSH contêm uma lista de OSDs, uma lista de “compartimentos de memória” para agregar os dispositivos em locais físicos e uma lista de regras que orientam como o CRUSH deve replicar os dados nos pools de um cluster do Ceph. Ao refletir a organização física adjacente da instalação, o CRUSH pode moldar (e, portanto, resolver) fontes potenciais de falhas de dispositivos correlacionados. As fontes comuns incluem proximidade física, fonte de energia compartilhada e rede compartilhada. Ao codificar essas informações no mapa do cluster, as políticas de posicionamento do CRUSH podem separar réplicas de objetos em diferentes domínios de falha enquanto ainda mantêm a distribuição desejada. Por exemplo, para evitar a possibilidade de falhas simultâneas, convém usar diferentes prateleiras, racks, fontes de alimentação, controladoras e/ou locais físicos para os dispositivos nos quais as réplicas de dados são armazenadas.

Depois que você implantar um cluster do Ceph, um Mapa CRUSH padrão será gerado. Isso é bom para o seu ambiente de área de segurança do Ceph. No entanto, ao implantar um cluster de dados em grande escala, você deve considerar significativamente o desenvolvimento de um Mapa CRUSH personalizado, pois ele o ajudará a gerenciar o cluster do Ceph, melhorar o desempenho e garantir a segurança dos dados.

Por exemplo, se um OSD ficar inativo, um Mapa CRUSH poderá ajudá-lo a localizar o data center físico, a sala, a fileira e o rack do host com o OSD que falhou, caso seja necessário usar o suporte no local ou substituir o hardware.

Da mesma forma, o CRUSH pode ajudá-lo a identificar falhas mais rapidamente. Por exemplo, se todos os OSDs em determinado rack ficarem inativos ao mesmo tempo, a falha poderá estar associada ao comutador de rede ou à energia que abastece o rack, e não aos próprios OSDs.

Um Mapa CRUSH personalizado também pode ajudar você a identificar os locais físicos onde o Ceph armazena as cópias redundantes dos dados quando o(s) grupo(s) de posicionamento (consulte a Seção 17.4, “Grupos de posicionamento”) associado(s) ao host com falha está(ão) prejudicado(s).

Há três seções principais para um Mapa CRUSH.

  • Dispositivos OSD reresentam qualquer dispositivo de armazenamento de objetos correspondente a um daemon ceph-osd.

  • Compartimentos de memória representam uma agregação hierárquica de locais de armazenamento (por exemplo, fileiras, racks, hosts, etc.) e seus pesos atribuídos.

  • Conjuntos de regras representam o modo de seleção dos compartimentos de memória.

17.1 Dispositivos OSD

Para mapear os grupos de posicionamento para OSDs, o Mapa CRUSH requer uma lista de dispositivos OSD (o nome do daemon OSD). A lista de dispositivos aparece primeiro no Mapa CRUSH.

#devices
device NUM osd.OSD_NAME class CLASS_NAME

Por exemplo:

#devices
device 0 osd.0 class hdd
device 1 osd.1 class ssd
device 2 osd.2 class nvme
device 3 osd.3class ssd

Como regra geral, um daemon OSD é mapeado para um único disco.

17.1.1 Classes de dispositivo

A flexibilidade do Mapa CRUSH para controlar o posicionamento de dados é um dos pontos fortes do Ceph. É também uma das partes mais difíceis de gerenciamento do cluster. As classes de dispositivo automatizam as mudanças mais comuns nos Mapas CRUSH que o administrador antes precisava fazer manualmente.

17.1.1.1 Problema de gerenciamento do CRUSH

Os clusters do Ceph costumam ser criados com vários tipos de dispositivos de armazenamento: HDD, SSD, NVMe ou até classes combinadas dos elementos acima. Denominamos esses diferentes tipos de dispositivos de armazenamento como classes de dispositivo para evitar confusão entre a propriedade tipo dos compartimentos de memória do CRUSH (por exemplo, host, rack, linha. Consulte a Seção 17.2, “Compartimentos de memória” para obter mais detalhes). Os Ceph OSDs com SSDs são muito mais rápidos do que os com discos giratórios, o que os torna mais adequados a determinadas cargas de trabalho. O Ceph facilita a criação de pools RADOS para diferentes conjuntos de dados ou cargas de trabalho e a atribuição de regras CRUSH diferentes para controlar o posicionamento de dados para esses pools.

OSDs com classes de dispositivo combinadas
Figura 17.1: OSDs com classes de dispositivo combinadas

No entanto, a configuração de regras CRUSH para posicionar dados apenas em uma determinada classe de dispositivo é desgastante. As regras funcionam nos termos da hierarquia CRUSH, mas se os dispositivos forem combinados com os mesmos hosts ou racks (como na hierarquia da amostra acima), eles (por padrão) serão combinados e aparecerão nas mesmas subárvores da hierarquia. A separação manual deles em árvores separadas envolvia a criação de várias versões de cada nó intermediário para cada classe de dispositivo nas versões anteriores do SUSE Enterprise Storage.

17.1.1.2 Classes de dispositivo

Uma solução refinada que o Ceph oferece é adicionar uma propriedade denominada classe de dispositivo a cada OSD. Por padrão, os OSDs definirão automaticamente suas classes de dispositivo como “hdd”, “ssd” ou “nvme” com base nas propriedades de hardware expostas pelo kernel do Linux. Essas classes de dispositivo são relatadas em uma nova coluna da saída do comando ceph osd tree:

cephuser@adm > ceph osd tree
 ID CLASS WEIGHT   TYPE NAME      STATUS REWEIGHT PRI-AFF
 -1       83.17899 root default
 -4       23.86200     host cpach
 2   hdd  1.81898         osd.2      up  1.00000 1.00000
 3   hdd  1.81898         osd.3      up  1.00000 1.00000
 4   hdd  1.81898         osd.4      up  1.00000 1.00000
 5   hdd  1.81898         osd.5      up  1.00000 1.00000
 6   hdd  1.81898         osd.6      up  1.00000 1.00000
 7   hdd  1.81898         osd.7      up  1.00000 1.00000
 8   hdd  1.81898         osd.8      up  1.00000 1.00000
 15  hdd  1.81898         osd.15     up  1.00000 1.00000
 10  nvme 0.93100         osd.10     up  1.00000 1.00000
 0   ssd  0.93100         osd.0      up  1.00000 1.00000
 9   ssd  0.93100         osd.9      up  1.00000 1.00000

Se houver falha na detecção automática da classe de dispositivo; por exemplo, porque o driver do dispositivo não expõe apropriadamente as informações sobre o dispositivo usando o /sys/block, você poderá ajustar as classes de dispositivo pela linha de comando:

cephuser@adm > ceph osd crush rm-device-class osd.2 osd.3
done removing class of osd(s): 2,3
cephuser@adm > ceph osd crush set-device-class ssd osd.2 osd.3
set osd(s) 2,3 to class 'ssd'

17.1.1.3 Definindo regras de posicionamento CRUSH

As regras CRUSH podem restringir o posicionamento a uma classe de dispositivo específica. Por exemplo, é possível criar um pool replicado “rápido” que distribui os dados apenas entre os discos SSD executando o seguinte comando:

cephuser@adm > ceph osd crush rule create-replicated RULE_NAME ROOT FAILURE_DOMAIN_TYPE DEVICE_CLASS

Por exemplo:

cephuser@adm > ceph osd crush rule create-replicated fast default host ssd

Crie um pool denominado “fast_pool” e atribua-o à regra “fast” (rápido):

cephuser@adm > ceph osd pool create fast_pool 128 128 replicated fast

O processo para criar as regras de código de eliminação é um pouco diferente. Primeiramente, você cria um perfil de código de eliminação que inclui uma propriedade para sua classe de dispositivo desejada. Em seguida, usa esse perfil ao criar o pool codificado para eliminação:

cephuser@adm > ceph osd erasure-code-profile set myprofile \
 k=4 m=2 crush-device-class=ssd crush-failure-domain=host
cephuser@adm > ceph osd pool create mypool 64 erasure myprofile

Caso você precise editar manualmente o Mapa CRUSH para personalizar sua regra, a sintaxe foi estendida para permitir que a classe de dispositivo seja especificada. Por exemplo, a regra CRUSH gerada pelos comandos acima tem o seguinte formato:

rule ecpool {
  id 2
  type erasure
  min_size 3
  max_size 6
  step set_chooseleaf_tries 5
  step set_choose_tries 100
  step take default class ssd
  step chooseleaf indep 0 type host
  step emit
}

A diferença importante aqui é que o comando “take” inclui o sufixo “NOME_CLASSE da classe” adicional.

17.1.1.4 Comandos adicionais

Para listar as classes de dispositivo usadas em um mapa CRUSH, execute:

cephuser@adm > ceph osd crush class ls
[
  "hdd",
  "ssd"
]

Para listar as regras CRUSH existentes, execute:

cephuser@adm > ceph osd crush rule ls
replicated_rule
fast

Para ver os detalhes da regra CRUSH denominada “fast”, execute:

cephuser@adm > ceph osd crush rule dump fast
{
		"rule_id": 1,
		"rule_name": "fast",
		"ruleset": 1,
		"type": 1,
		"min_size": 1,
		"max_size": 10,
		"steps": [
						{
										"op": "take",
										"item": -21,
										"item_name": "default~ssd"
						},
						{
										"op": "chooseleaf_firstn",
										"num": 0,
										"type": "host"
						},
						{
										"op": "emit"
						}
		]
}

Para listar os OSDs que pertencem a uma classe “ssd”, execute:

cephuser@adm > ceph osd crush class ls-osd ssd
0
1

17.1.1.5 Migrando de uma regra SSD legada para classes de dispositivo

No SUSE Enterprise Storage anterior à versão 5, você precisava editar manualmente o Mapa CRUSH e manter uma hierarquia paralela para cada tipo de dispositivo especializado (como SSD) a fim de gravar regras que se aplicassem a esses dispositivos. A partir do SUSE Enterprise Storage 5, o recurso de classe de dispositivo permitiu que isso fosse feito de maneira transparente.

É possível transformar uma regra e hierarquia legadas nas novas regras com base em classe usando o comando crushtool. Há vários tipos de transformação possíveis:

crushtool --reclassify-root ROOT_NAME DEVICE_CLASS

Esse comando considera tudo o que está na hierarquia abaixo de ROOT_NAME e ajusta quaisquer regras que fazem referência à raiz por meio de

take ROOT_NAME

para

take ROOT_NAME class DEVICE_CLASS

Ele enumera novamente os compartimentos de memória para que os IDs antigos sejam usados na “árvore de sombra” da classe especificada. Como consequência, nenhum movimento de dados ocorre.

Exemplo 17.1: crushtool --reclassify-root

Considere a seguinte regra existente:

rule replicated_ruleset {
   id 0
   type replicated
   min_size 1
   max_size 10
   step take default
   step chooseleaf firstn 0 type rack
   step emit
}

Se você reclassificar a raiz “default” como a classe “hdd”, a regra se tornará

rule replicated_ruleset {
   id 0
   type replicated
   min_size 1
   max_size 10
   step take default class hdd
   step chooseleaf firstn 0 type rack
   step emit
}
crushtool --set-subtree-class BUCKET_NAME DEVICE_CLASS

Esse método marca cada dispositivo na subárvore com raiz em BUCKET_NAME com a classe de dispositivo especificada.

Normalmente, a --set-subtree-class é usada em conjunto com a opção ‑‑reclassify-root para garantir que todos os dispositivos nessa raiz sejam rotulados com a classe correta. No entanto, alguns desses dispositivos podem intencionalmente ter uma classe diferente e, portanto, você não deseja rotulá-los outra vez. Nesses casos, exclua a opção --set-subtree-class. Saiba que esse tipo de remapeamento não será perfeito, porque a regra anterior é distribuída pelos dispositivos das várias classes, mas as regras ajustadas serão mapeadas apenas para os dispositivos da classe especificada.

crushtool --reclassify-bucket MATCH_PATTERN DEVICE_CLASS DEFAULT_PATTERN

Esse método permite a fusão de uma hierarquia específica do tipo paralelo com a hierarquia normal. Por exemplo, muitos usuários têm Mapas CRUSH semelhantes aos seguintes:

Exemplo 17.2: crushtool --reclassify-bucket
host node1 {
   id -2           # do not change unnecessarily
   # weight 109.152
   alg straw
   hash 0  # rjenkins1
   item osd.0 weight 9.096
   item osd.1 weight 9.096
   item osd.2 weight 9.096
   item osd.3 weight 9.096
   item osd.4 weight 9.096
   item osd.5 weight 9.096
   [...]
}

host node1-ssd {
   id -10          # do not change unnecessarily
   # weight 2.000
   alg straw
   hash 0  # rjenkins1
   item osd.80 weight 2.000
   [...]
}

root default {
   id -1           # do not change unnecessarily
   alg straw
   hash 0  # rjenkins1
   item node1 weight 110.967
   [...]
}

root ssd {
   id -18          # do not change unnecessarily
   # weight 16.000
   alg straw
   hash 0  # rjenkins1
   item node1-ssd weight 2.000
   [...]
}

Essa função reclassifica cada compartimento de memória que corresponde a um determinado padrão. O padrão pode ter um formato parecido com %suffix ou prefix%. No exemplo acima, você usará o padrão %-ssd. Para cada compartimento de memória combinado, a parte restante do nome que corresponde ao curinga “%” especifica o compartimento de memória de base. Todos os dispositivos no compartimento de memória combinado são rotulados com a classe de dispositivo especificada e, em seguida, movidos para o compartimento de memória de base. Se o compartimento de memória de base não existe (por exemplo, se “node12-ssd” existe, mas “node12” não), ele é criado e vinculado abaixo do compartimento de memória pai padrão especificado. Os IDs de compartimentos de memória antigos são preservados nos novos compartimentos de memória de sombra para evitar a movimentação de dados. As regras com as etapas take que fazem referência a compartimentos de memória antigos são ajustadas.

crushtool --reclassify-bucket BUCKET_NAME DEVICE_CLASS BASE_BUCKET

É possível usar a opção --reclassify-bucket sem um curinga para mapear um único compartimento de memória. Como no exemplo anterior, em que desejamos que o compartimento de memória “ssd” seja mapeado para o compartimento de memória padrão.

O comando final para converter o mapa composto dos fragmentos acima é o seguinte:

cephuser@adm > ceph osd getcrushmap -o original
cephuser@adm > crushtool -i original --reclassify \
  --set-subtree-class default hdd \
  --reclassify-root default hdd \
  --reclassify-bucket %-ssd ssd default \
  --reclassify-bucket ssd ssd default \
  -o adjusted

Para verificar se a conversão está correta, há uma opção --compare que testa uma grande amostra de entradas no Mapa CRUSH e compara se o mesmo resultado é retornado. Essas entradas são controladas pelas mesmas opções aplicadas a --test. Para o exemplo acima, o comando é o seguinte:

cephuser@adm > crushtool -i original --compare adjusted
rule 0 had 0/10240 mismatched mappings (0)
rule 1 had 0/10240 mismatched mappings (0)
maps appear equivalent
Dica
Dica

Se houvesse diferenças, você veria a proporção das entradas que seriam mapeadas novamente entre parênteses.

Se você estiver satisfeito com o Mapa CRUSH ajustado, poderá aplicá-lo ao cluster:

cephuser@adm > ceph osd setcrushmap -i adjusted

17.1.1.6 Para obter mais informações

Encontre mais detalhes sobre os Mapas CRUSH na Seção 17.5, “Manipulação de mapa CRUSH”.

Encontre mais detalhes em geral sobre os pools do Ceph no Capítulo 18, Gerenciar pools de armazenamento.

Encontre mais detalhes sobre os pools codificados para eliminação no Capítulo 19, Pools codificados para eliminação.

17.2 Compartimentos de memória

Os mapas CRUSH contêm uma lista de OSDs, que podem ser organizados em uma estrutura de árvore de compartimentos de memória para agregar os dispositivos em locais físicos. Cada OSD abrange as folhas da árvore.

0

osd

Um dispositivo ou OSD específico (osd.1, osd.2, etc.).

1

host

O nome de um host que contém um ou mais OSDs.

2

Chassi

Identificador do chassi que contém o host no rack.

3

rack

Um rack de computador. O padrão é unknownrack.

4

row

Uma fileira em uma série de racks.

5

pdu

Abreviação de “Power Distribution Unit” (Unidade de Distribuição de Energia).

6

pod

Abreviação de “Point of Delivery” (Ponto de Entrega): neste contexto, um grupo de PDUs ou um grupo de fileiras de racks.

7

room

Uma sala com fileiras de racks.

8

centro de dados

Um centro de dados físico com uma ou mais salas.

9

region

Região geográfica global (por exemplo, NAM, LAM, EMEA, APAC, etc.).

10

usuário

O nó raiz da árvore de compartimentos de memória OSD (normalmente definido como default).

Dica
Dica

Você pode modificar os tipos existentes e criar seus próprios tipos de compartimento de memória.

As ferramentas de implantação do Ceph geram um Mapa CRUSH que contém um compartimento de memória para cada host e uma raiz denominada “default”, que é útil para o pool rbd padrão. Os tipos de compartimento de memória restantes oferecem um meio de armazenar informações sobre o local físico dos nós/compartimentos de memória, o que facilita bastante a administração do cluster em caso de mal funcionamento dos OSDs, dos hosts ou do hardware de rede e quando o administrador precisa acessar o hardware físico.

Um compartimento de memória tem um tipo, um nome exclusivo (string), um ID único indicado por um número inteiro negativo, um peso relativo à capacidade total do(s) item(ns), o algoritmo do compartimento de memória (por padrão, straw2) e o hash (por padrão, 0, refletindo o Hash CRUSH rjenkins1). Um compartimento de memória pode ter um ou mais itens. Os itens podem ser constituídos de outros compartimentos de memória ou OSDs. Os itens podem ter um peso que reflete o peso relativo do item.

[bucket-type] [bucket-name] {
  id [a unique negative numeric ID]
  weight [the relative capacity/capability of the item(s)]
  alg [the bucket type: uniform | list | tree | straw2 | straw ]
  hash [the hash type: 0 by default]
  item [item-name] weight [weight]
}

O exemplo a seguir ilustra como você pode usar compartimentos de memória para agregar um pool e locais físicos, como data center, sala, rack e fileira.

host ceph-osd-server-1 {
        id -17
        alg straw2
        hash 0
        item osd.0 weight 0.546
        item osd.1 weight 0.546
}

row rack-1-row-1 {
        id -16
        alg straw2
        hash 0
        item ceph-osd-server-1 weight 2.00
}

rack rack-3 {
        id -15
        alg straw2
        hash 0
        item rack-3-row-1 weight 2.00
        item rack-3-row-2 weight 2.00
        item rack-3-row-3 weight 2.00
        item rack-3-row-4 weight 2.00
        item rack-3-row-5 weight 2.00
}

rack rack-2 {
        id -14
        alg straw2
        hash 0
        item rack-2-row-1 weight 2.00
        item rack-2-row-2 weight 2.00
        item rack-2-row-3 weight 2.00
        item rack-2-row-4 weight 2.00
        item rack-2-row-5 weight 2.00
}

rack rack-1 {
        id -13
        alg straw2
        hash 0
        item rack-1-row-1 weight 2.00
        item rack-1-row-2 weight 2.00
        item rack-1-row-3 weight 2.00
        item rack-1-row-4 weight 2.00
        item rack-1-row-5 weight 2.00
}

room server-room-1 {
        id -12
        alg straw2
        hash 0
        item rack-1 weight 10.00
        item rack-2 weight 10.00
        item rack-3 weight 10.00
}

datacenter dc-1 {
        id -11
        alg straw2
        hash 0
        item server-room-1 weight 30.00
        item server-room-2 weight 30.00
}

root data {
        id -10
        alg straw2
        hash 0
        item dc-1 weight 60.00
        item dc-2 weight 60.00
}

17.3 Conjuntos de regras

Os mapas CRUSH suportam a noção de “regras CRUSH”, que determinam o posicionamento dos dados em um pool. Para clusters grandes, convém criar muitos pools, em que cada um pode ter seu próprio conjunto de regras CRUSH e suas próprias regras. O Mapa CRUSH padrão tem uma regra para a raiz padrão. Se você deseja mais raízes e regras, precisa criá-las no futuro, ou elas serão criadas automaticamente quando novos pools forem criados.

Nota
Nota

Na maioria dos casos, você não precisará modificar as regras padrão. Quando você cria um novo pool, o conjunto de regras padrão dele é 0.

Uma regra apresenta o seguinte formato:

rule rulename {

        ruleset ruleset
        type type
        min_size min-size
        max_size max-size
        step step

}
ruleset

Um número inteiro. Classifica uma regra como pertencente a um conjunto de regras. Ativado quando o conjunto de regras é definido em um pool. Essa opção é obrigatória. O padrão é 0.

type

Uma string. Descreve uma regra para um pool com codificação "replicado" ou "de eliminação". Essa opção é obrigatória. O padrão é replicado.

min_size

Um número inteiro. Se um grupo de pools gerar menos réplicas do que esse número, o CRUSH NÃO selecionará essa regra. Essa opção é obrigatória. O padrão é 2.

max_size

Um número inteiro. Se um grupo de pools gerar mais réplicas do que esse número, o CRUSH NÃO selecionará essa regra. Essa opção é obrigatória. O padrão é 10.

step take bucket

Usa um compartimento de memória especificado por um nome e inicia a iteração descendente na árvore. Essa opção é obrigatória. Para obter uma explicação sobre iteração na árvore, consulte a Seção 17.3.1, “Iterando a árvore de nós”.

step targetmodenum type bucket-type

target pode ser choose ou chooseleaf. Quando definido como choose, um número de compartimentos de memória é selecionado. chooseleaf seleciona diretamente os OSDs (nós folha) da subárvore de cada compartimento de memória no conjunto de compartimentos de memória.

mode pode ser firstn ou indep. Consulte a Seção 17.3.2, “firstn e indep.

Seleciona o número de compartimentos de memória de determinado tipo. Em que N é o número de opções disponíveis, se num > 0 && < N, escolha essa mesma quantidade de compartimentos de memória; se num < 0, isso significa N - num e, se num == 0, escolha N compartimentos de memória (todos disponíveis). Segue step take ou step choose.

step emit

Gera o valor atual e esvazia a pilha. Normalmente usado no fim de uma regra, mas também pode ser usado para estruturar árvores diferentes na mesma regra. Segue step choose.

17.3.1 Iterando a árvore de nós

É possível ver a estrutura definida com os compartimentos de memória como uma árvore de nós. Os compartimentos de memória são os nós, e os OSDs são as folhas da árvore.

As regras no Mapa CRUSH definem como os OSDs são selecionados dessa árvore. Uma regra começa com um nó e, em seguida, faz a iteração descendente pela árvore para retornar um conjunto de OSDs. Não é possível definir qual ramificação precisa ser selecionada. Em vez disso, o algoritmo CRUSH garante que o conjunto de OSDs atende aos requisitos de replicação e distribui os dados igualmente.

Com step take bucket, a iteração pela árvore de nós começa no compartimento de memória especificado (sem tipo de compartimento de memória). Se os OSDs de todas as ramificações na árvore tiverem que ser retornados, o compartimento de memória deverá ser a raiz. Do contrário, as etapas a seguir apenas fará a iteração na subárvore.

Após step take, uma ou mais entradas step choose vêm a seguir na definição da regra. Cada step choose escolhe um número definido de nós (ou ramificações) do nó superior selecionado anteriormente.

No fim, os OSDs selecionados são retornados com step emit.

step chooseleaf é uma prática função que seleciona os OSDs diretamente das ramificações do compartimento de memória especificado.

A Figura 17.2, “Exemplo de árvore” mostra um exemplo de como o step é usado para iterar em uma árvore. As setas e os números laranjas correspondem a example1a e example1b, e os azuis correspondem a example2 nas definições de regra a seguir.

Exemplo de árvore
Figura 17.2: Exemplo de árvore
# orange arrows
rule example1a {
        ruleset 0
        type replicated
        min_size 2
        max_size 10
        # orange (1)
        step take rack1
        # orange (2)
        step choose firstn 0 host
        # orange (3)
        step choose firstn 1 osd
        step emit
}

rule example1b {
        ruleset 0
        type replicated
        min_size 2
        max_size 10
        # orange (1)
        step take rack1
        # orange (2) + (3)
        step chooseleaf firstn 0 host
        step emit
}

# blue arrows
rule example2 {
        ruleset 0
        type replicated
        min_size 2
        max_size 10
        # blue (1)
        step take room1
        # blue (2)
        step chooseleaf firstn 0 rack
        step emit
}

17.3.2 firstn e indep

Uma regra CRUSH define substituições para nós ou OSDs com falha (consulte a Seção 17.3, “Conjuntos de regras”). A palavra-chave step requer firstn ou indep como parâmetro. A Figura 17.3, “Métodos de substituição de nó” apresenta um exemplo.

O firstn adiciona nós de substituição ao fim da lista de nós ativos. No caso de um nó com falha, os seguintes nós saudáveis são deslocados para a esquerda para preencher a lacuna do nó com falha. Esse é o método padrão desejado para pools replicados, porque um nó secundário já tem todos os dados e, portanto, pode assumir as tarefas do nó principal imediatamente.

O indep seleciona nós de substituição fixos para cada nó ativo. A substituição de um nó com falha não muda a ordem dos nós restantes. Esse é o método desejado para pools codificados para eliminação. Nos pools codificados para eliminação, os dados armazenados em um nó dependem da posição dele na seleção do nó. Quando a ordem dos nós muda, todos os dados nos nós afetados precisam ser realocados.

Métodos de substituição de nó
Figura 17.3: Métodos de substituição de nó

17.4 Grupos de posicionamento

O Ceph mapeia objetos para grupos de posicionamento (PGs, placement groups). Os grupos de posicionamento são fragmentos de um pool de objetos lógicos que armazenam os objetos como um grupo em OSDs. Os grupos de posicionamento reduzem a quantidade de metadados por objeto quando o Ceph armazena os dados em OSDs. Um número maior de grupos de posicionamento, por exemplo, 100 por OSD, proporciona um melhor equilíbrio.

17.4.1 Usando grupos de posicionamento

Um grupo de posicionamento (PG) agrega objetos em um pool. O principal motivo é que o monitoramento do posicionamento de objetos e dos metadados por objeto é caro em termos de capacidade de computação. Por exemplo, um sistema com milhões de objetos não pode monitorar o posicionamento de cada um dos seus objetos diretamente.

Grupos de posicionamento em um pool
Figura 17.4: Grupos de posicionamento em um pool

O cliente Ceph calculará a que grupo de posicionamento um objeto pertencerá. Ele faz isso por meio de hashing do ID do objeto e da aplicação de uma operação com base no número de PGs no pool definido e no ID do pool.

O conteúdo do objeto em um grupo de posicionamento é armazenado em um conjunto de OSDs. Por exemplo, em um pool replicado de tamanho dois, cada grupo de posicionamento armazenará objetos em dois OSDs:

Grupos de posicionamento e OSDs
Figura 17.5: Grupos de posicionamento e OSDs

Se o OSD nº 2 falhar, outro OSD será atribuído ao grupo de posicionamento nº 1 e será preenchido com cópias de todos os objetos no OSD nº 1. Se o tamanho do pool for mudado de dois para três, um OSD adicional será atribuído ao grupo de posicionamento e receberá cópias de todos os objetos no grupo de posicionamento.

Os grupos de posicionamento não têm a propriedade do OSD, eles o compartilham com outros grupos de posicionamento do mesmo pool ou até de outros pools. Se o OSD nº 2 falhar, o grupo de posicionamento nº 2 também precisará restaurar cópias dos objetos usando o OSD nº 3.

Quando o número de grupos de posicionamento aumentar, os novos grupos de posicionamento receberão os OSDs. O resultado da função CRUSH também mudará, e alguns objetos dos antigos grupos de posicionamento serão copiados para os novos grupos de posicionamento e removidos dos antigos.

17.4.2 Determinando o valor de PG_NUM

Nota
Nota

A partir do Ceph Nautilus (v14.x), você pode usar o módulo pg_autoscaler do Ceph Manager para dimensionar automaticamente os PGs, conforme necessário. Para habilitar esse recurso, consulte o Seção 6.1.1.1, “Default PG and PGP counts”.

Ao criar um novo pool, você ainda pode escolher o valor de PG_NUM manualmente:

root # ceph osd pool create POOL_NAME PG_NUM

Não é possível calcular o PG_NUM automaticamente. Veja a seguir alguns valores mais usados, dependendo do número de OSDs no cluster:

Menos do que 5 OSDs:

Defina PG_NUM como 128.

Entre 5 e 10 OSDs:

Defina PG_NUM como 512.

Entre 10 e 50 OSDs:

Defina PG_NUM como 1024.

Conforme o número de OSDs aumenta, a escolha do valor certo para PG_NUM torna-se mais importante. O PG_NUM afeta altamente o comportamento do cluster e também a durabilidade dos dados em caso de falha no OSD.

17.4.2.1 Calculando os grupos de posicionamento para mais do que 50 OSDs

Se você tem menos do que 50 OSDs, use a pré-seleção descrita na Seção 17.4.2, “Determinando o valor de PG_NUM. Se você tem mais do que 50 OSDs, recomendamos aproximadamente de 50 a 100 grupos de posicionamento por OSD para equilibrar o uso de recursos, a durabilidade e a distribuição dos dados. Para um único pool de objetos, você pode usar a seguinte fórmula para obter uma linha de base:

total PGs = (OSDs * 100) / POOL_SIZE

Em que POOL_SIZE é o número de réplicas para os pools replicados ou a soma de “k”+“m” para os pools codificados para eliminação, conforme retornado pelo comando ceph osd erasure-code-profile get. Você deve arredondar o resultado para cima até a potência mais próxima de 2. O arredondamento é recomendado para que o algoritmo CRUSH equilibre igualmente o número de objetos entre os grupos de posicionamento.

Como exemplo, para um cluster com 200 OSDs e tamanho de pool de 3 réplicas, você estima o número de PGs da seguinte maneira:

          (200 * 100) / 3 = 6667

A potência mais próxima de 2 é 8192.

Ao usar vários pools de dados para armazenar objetos, você precisa garantir o equilíbrio entre o número de grupos de posicionamento por pool e o número de grupos de posicionamento por OSD. Você precisa atingir um número total razoável de grupos de posicionamento que ofereça variação suficientemente baixa por OSD sem sobrecarregar os recursos do sistema nem tornar o processo de emparelhamento muito lento.

Por exemplo, um cluster de 10 pools, cada um com 512 grupos de posicionamento em 10 OSDs, representa um total de 5.120 grupos de posicionamento distribuídos por 10 OSDs, ou seja, 512 grupos de posicionamento por OSD. Esse tipo de configuração não usa muitos recursos. No entanto, se 1.000 grupos foram criados com 512 grupos de posicionamento cada, os OSDs processam aproximadamente 50.000 grupos de posicionamento cada, e isso requer muito mais recursos e tempo de emparelhamento.

17.4.3 Definindo o número de grupos de posicionamento

Nota
Nota

A partir do Ceph Nautilus (v14.x), você pode usar o módulo pg_autoscaler do Ceph Manager para dimensionar automaticamente os PGs, conforme necessário. Para habilitar esse recurso, consulte Seção 6.1.1.1, “Default PG and PGP counts”.

Se você ainda precisa especificar o número de grupos de posicionamento em um pool manualmente, é necessário especificá-los no momento da criação do pool (consulte a Seção 18.1, “Criando um pool”). Após definir os grupos de posicionamento para um pool, você poderá aumentar o número de grupos de posicionamento executando o seguinte comando:

root # ceph osd pool set POOL_NAME pg_num PG_NUM

Após aumentar o número de grupos de posicionamento, você também precisará aumentar esse número para o posicionamento (PGP_NUM) antes que o cluster seja redistribuído. O PGP_NUM será o número de grupos de posicionamento que serão considerados para o posicionamento pelo algoritmo CRUSH. O aumento do PG_NUM divide os grupos de posicionamento, mas os dados não serão migrados para os grupos de posicionamento mais recentes até que PGP_NUM seja aumentado. O PGP_NUM deve ser igual ao PG_NUM. Para aumentar o número de grupos para o posicionamento, execute o seguinte:

root # ceph osd pool set POOL_NAME pgp_num PGP_NUM

17.4.4 Encontrando o número de grupos de posicionamento

Para encontrar o número de grupos de posicionamento em um pool, execute o seguinte comando get:

root # ceph osd pool get POOL_NAME pg_num

17.4.5 Encontrando as estatísticas de PG de um cluster

Para encontrar as estatísticas dos grupos de posicionamento em seu cluster, execute o seguinte comando:

root # ceph pg dump [--format FORMAT]

Os formatos válidos são “plain” (padrão) e “json”.

17.4.6 Encontrando as estatísticas de PGs travados

Para encontrar as estatísticas de todos os grupos de posicionamento travados em um determinado estado, execute o seguinte:

root # ceph pg dump_stuck STATE \
 [--format FORMAT] [--threshold THRESHOLD]

O STATE é um dos seguintes: “inactive” (PGs não podem processar leituras ou gravações porque estão aguardando por um OSD com os dados mais atualizados), “unclean” (PGs contêm objetos que não foram replicados o número desejado de vezes), “stale” (PGs em estado desconhecido: os OSDs que os hospedam não foram relatados ao cluster do monitor no intervalo especificado pela opção mon_osd_report_timeout), “undersized” ou “degraded”.

Os formatos válidos são “plain” (padrão) e “json”.

O limite define o número mínimo de segundos que o grupo de posicionamento permanece travado antes de incluí-lo nas estatísticas retornadas (por padrão, 300 segundos).

17.4.7 Pesquisando o mapa de um grupo de posicionamento

Para pesquisar o mapa de um determinado grupo de posicionamento, execute o seguinte:

root # ceph pg map PG_ID

O Ceph retornará o mapa do grupo de posicionamento, o grupo de posicionamento e o status do OSD:

root # ceph pg map 1.6c
osdmap e13 pg 1.6c (1.6c) -> up [1,0] acting [1,0]

17.4.8 Recuperando as estatísticas de grupos de posicionamento

Para recuperar as estatísticas de um determinado grupo de posicionamento, execute o seguinte:

root # ceph pg PG_ID query

17.4.9 Depurando um grupo de posicionamento

Para depurar (Seção 17.6, “Depurando grupos de posicionamento”) um grupo de posicionamento, execute o seguinte:

root # ceph pg scrub PG_ID

O Ceph verifica os nós primários e de réplica, gera um catálogo de todos os objetos no grupo de posicionamento e os compara para garantir que nenhum objeto esteja ausente ou seja incompatível e que seu conteúdo seja consistente. Supondo que todas as réplicas sejam correspondentes, uma varredura semântica final garante que todos os metadados de objetos relacionados a instantâneo sejam consistentes. Os erros são relatados por meio de registros.

17.4.10 Priorizando o provisionamento e a recuperação de grupos de posicionamento

Você pode enfrentar uma situação em que vários grupos de posicionamento exigem recuperação e/ou provisionamento, enquanto alguns grupos armazenam dados mais importantes do que outros. Por exemplo, alguns PGs podem armazenar dados para imagens usadas por máquinas em execução, e outros PGs podem ser usados por máquinas inativas ou dados menos relevantes. Nesse caso, você pode priorizar a recuperação desses grupos para que o desempenho e a disponibilidade dos dados armazenados neles sejam restaurados com mais antecedência. Para marcar grupos de posicionamento específicos como priorizados durante o provisionamento ou a recuperação, execute o seguinte:

root # ceph pg force-recovery PG_ID1 [PG_ID2 ... ]
root # ceph pg force-backfill PG_ID1 [PG_ID2 ... ]

Isso fará com que o Ceph realize a recuperação ou o provisionamento dos grupos de posicionamento especificados primeiro, antes dos outros grupos de posicionamento. Esse procedimento não interrompe os provisionamentos ou a recuperação que está em andamento, mas faz com que os PGs especificados sejam processados o mais rápido possível. Se você mudar de ideia ou priorizar grupos errados, cancele a priorização:

root # ceph pg cancel-force-recovery PG_ID1 [PG_ID2 ... ]
root # ceph pg cancel-force-backfill PG_ID1 [PG_ID2 ... ]

Os comandos cancel-* removem o flag “force” dos PGs para que sejam processados na ordem padrão. Mais uma vez, isso não afeta os grupos de posicionamento que estão sendo processados, apenas aqueles que ainda estão na fila. O flag “force” será limpo automaticamente após a recuperação ou o provisionamento do grupo.

17.4.11 Revertendo objetos perdidos

Se o cluster perdeu um ou mais objetos, e você decidiu parar de procurar os dados perdidos, precisará marcar os objetos não encontrados como "perdidos".

Se os objetos ainda continuarem perdidos depois de ter consultado todos os locais possíveis, você talvez tenha de desistir deles. Isso é possível considerando as combinações incomuns de falhas que permitem que o cluster reconheça as gravações que foram realizadas antes de serem recuperadas.

Atualmente, a única opção suportada é "revert", que voltará para uma versão anterior do objeto ou o esquecerá completamente, no caso de um novo objeto. Para marcar os objetos “não encontrados” como “perdidos”, execute o seguinte:

  cephuser@adm > ceph pg PG_ID mark_unfound_lost revert|delete

17.4.12 Habilitando o dimensionador automático de PG

Os grupos de posicionamento (PGs, Placement Groups) são um detalhe interno de implementação de como o Ceph distribui os dados. Ao habilitar o pg-autoscaling, você pode permitir que o cluster crie ou ajuste os PGs automaticamente com base no modo como o cluster é usado.

Cada pool no sistema tem uma propriedade pg_autoscale_mode que pode ser definida como off, on ou warn:

O dimensionador automático é configurado por pool e pode ser executado em três modos:

off

Desabilite o dimensionamento automático para este pool. O administrador é quem escolhe um número apropriado de PGs para cada pool.

on

Habilite os ajustes automatizados da contagem de PGs para o pool especificado.

aviso

Emita alertas de saúde quando a contagem de PGs precisar ser ajustada.

Para definir o modo de dimensionamento automático para os pools existentes:

cephuser@adm > ceph osd pool set POOL_NAME pg_autoscale_mode mode

Você também pode configurar o pg_autoscale_mode padrão que será aplicado a qualquer pool criado no futuro com:

cephuser@adm > ceph config set global osd_pool_default_pg_autoscale_mode MODE

Você pode ver cada pool, sua utilização relativa e quaisquer mudanças sugeridas na contagem de PGs com este comando:

cephuser@adm > ceph osd pool autoscale-status

17.5 Manipulação de mapa CRUSH

Esta seção apresenta os modos de manipulação do Mapa CRUSH básico. Por exemplo, editar um Mapa CRUSH, mudar parâmetros do Mapa CRUSH e adicionar/mover/remover um OSD.

17.5.1 Editando um mapa CRUSH

Para editar um mapa CRUSH existente, faça o seguinte:

  1. Obtenha um Mapa CRUSH. Para obter o Mapa CRUSH para seu cluster, execute o seguinte:

    cephuser@adm > ceph osd getcrushmap -o compiled-crushmap-filename

    O Ceph gerará (-o) um Mapa CRUSH compilado com o nome de arquivo que você especificou. Como o Mapa CRUSH está em um formato compilado, você deve descompilá-lo antes que você possa editá-lo.

  2. Descompile um Mapa CRUSH. Para descompilar um Mapa CRUSH, execute o seguinte:

    cephuser@adm > crushtool -d compiled-crushmap-filename \
     -o decompiled-crushmap-filename

    O Ceph descompilará (-d) o Mapa CRUSH compilado e o gerará (-o) com o nome de arquivo que você especificou.

  3. Edite pelo menos um dos parâmetros de Dispositivos, Compartimentos de Memória e Regras.

  4. Compile um Mapa CRUSH. Para compilar um Mapa CRUSH, execute o seguinte:

    cephuser@adm > crushtool -c decompiled-crush-map-filename \
     -o compiled-crush-map-filename

    O Ceph armazenará um Mapa CRUSH compilado com o nome de arquivo que você especificou.

  5. Defina um Mapa CRUSH. Para definir o Mapa CRUSH para o cluster, execute o seguinte:

    cephuser@adm > ceph osd setcrushmap -i compiled-crushmap-filename

    O Ceph inserirá o Mapa CRUSH compilado do nome de arquivo que você especificou como o Mapa CRUSH para o cluster.

Dica
Dica: Usar o sistema de controle de versão

Use um sistema de controle de versão, como git ou svn, para os arquivos de Mapa CRUSH exportados e modificados. Isso simplifica um possível rollback.

Dica
Dica: Testar o novo mapa CRUSH

Teste o novo Mapa CRUSH ajustado usando o comando crushtool --test e compare com o estado antes da aplicação do novo Mapa CRUSH. Você pode achar útil os seguintes switches de comando: --show-statistics, --show-mappings, --show-bad-mappings, --show-utilization, --show-utilization-all, --show-choose-tries

17.5.2 Adicionando ou movendo um OSD

Para adicionar ou mover um OSD no Mapa CRUSH de um cluster em execução, faça o seguinte:

cephuser@adm > ceph osd crush set id_or_name weight root=pool-name
bucket-type=bucket-name ...
id

Um número inteiro. O ID numérico do OSD. Essa opção é obrigatória.

name

Uma string. O nome completo do OSD. Essa opção é obrigatória.

weight

Um duplo. O peso do CRUSH para o OSD. Essa opção é obrigatória.

usuário

Um par de chave/valor. Por padrão, a hierarquia do CRUSH contém o pool padrão como raiz. Essa opção é obrigatória.

bucket-type

Pares de chave/valor. Você pode especificar o local do OSD na hierarquia do CRUSH.

O exemplo a seguir adiciona osd.0 à hierarquia ou move o OSD de um local anterior.

cephuser@adm > ceph osd crush set osd.0 1.0 root=data datacenter=dc1 room=room1 \
row=foo rack=bar host=foo-bar-1

17.5.3 Diferença entre ceph osd reweight e ceph osd crush reweight

Há dois comandos similares que mudam o “peso” de um Ceph OSD. O contexto do uso deles é diferente e pode causar confusão.

17.5.3.1 ceph osd reweight

Uso:

cephuser@adm > ceph osd reweight OSD_NAME NEW_WEIGHT

O ceph osd reweight define um peso de substituição no Ceph OSD. Esse valor está na faixa de 0 a 1 e força o CRUSH a reposicionar os dados que, de outra forma, residiriam nesta unidade. Ele não muda os pesos atribuídos aos compartimentos de memória acima do OSD e é uma medida corretiva em caso de não funcionamento ou mau funcionamento da distribuição normal do CRUSH. Por exemplo, se um dos OSDs estiver em 90% e os outros estiverem em 40%, você poderá reduzir esse peso para tentar compensá-lo.

Nota
Nota: O peso do OSD é temporário

Observe que a configuração ceph osd reweight não é persistente. Quando um OSD é marcado para ser removido, seu peso é definido como 0. Quando ele é marcado para ser incluído novamente, o peso é modificado para 1.

17.5.3.2 ceph osd crush reweight

Uso:

cephuser@adm > ceph osd crush reweight OSD_NAME NEW_WEIGHT

ceph osd crush reweight define o peso de CRUSH do OSD. Esse peso é um valor arbitrário; normalmente, o tamanho do disco em TB, e controla a quantidade de dados que o sistema tenta alocar para o OSD.

17.5.4 Removendo um OSD

Para remover um OSD do Mapa CRUSH de um cluster em execução, faça o seguinte:

cephuser@adm > ceph osd crush remove OSD_NAME

17.5.5 Adicionando um compartimento de memória

Para adicionar um compartimento de memória ao Mapa CRUSH de um cluster em execução, use o comando ceph osd crush add-bucket:

cephuser@adm > ceph osd crush add-bucket BUCKET_NAME BUCKET_TYPE

17.5.6 Movendo um compartimento de memória

Para mover um compartimento de memória para outro local ou posição na hierarquia do Mapa CRUSH, execute o seguinte:

cephuser@adm > ceph osd crush move BUCKET_NAME BUCKET_TYPE=BUCKET_NAME [...]

Por exemplo:

cephuser@adm > ceph osd crush move bucket1 datacenter=dc1 room=room1 row=foo rack=bar host=foo-bar-1

17.5.7 Removendo um compartimento de memória

Para remover um compartimento de memória da hierarquia do Mapa CRUSH, execute o seguinte:

cephuser@adm > ceph osd crush remove BUCKET_NAME
Nota
Nota: Apenas compartimento de memória vazio

Um compartimento de memória deve estar vazio antes de removê-lo da hierarquia do CRUSH.

17.6 Depurando grupos de posicionamento

Além de fazer várias cópias dos objetos, o Ceph garante a integridade dos dados depurando os grupos de posicionamento (há mais informações sobre grupos de posicionamento no Seção 1.3.2, “Grupos de posicionamento”). A depuração do Ceph equivale à execução do fsck na camada de armazenamento de objetos. Para cada grupo de posicionamento, o Ceph gera um catálogo de todos os objetos e compara cada objeto principal e suas réplicas para garantir que nenhum objeto esteja ausente ou seja incompatível. A depuração diária simples verifica o tamanho e os atributos dos objetos, enquanto a depuração semanal profunda lê os dados e usa checksums para garantir a integridade dos dados.

A depuração é importante para manter a integridade dos dados, mas ela pode reduzir o desempenho. Você pode ajustar as seguintes configurações para aumentar ou diminuir as operações de depuração:

osd max scrubs

O número máximo de operações de depuração simultâneas para um Ceph OSD. O padrão é 1.

osd scrub begin hour, osd scrub end hour

As horas do dia (0 a 24) que definem o intervalo para a execução da depuração. Por padrão, esse valor começa em 0 e termina em 24.

Importante
Importante

Se o intervalo de depuração do grupo de posicionamento exceder a configuração osd scrub max interval, a depuração será executada independentemente do intervalo definido para ela.

osd scrub during recovery

Permite depurações durante a recuperação. Ao defini-la como “false”, a programação de novas depurações é desabilitada durante uma recuperação ativa. As depurações que já estão em execução continuam. Essa opção é útil para reduzir a carga em clusters ocupados. O padrão é “true”.

osd scrub thread timeout

O tempo máximo em segundos antes que um thread de depuração esgote o tempo de espera. O padrão é 60.

osd scrub finalize thread timeout

O tempo máximo em segundos antes que um thread de finalização da depuração esgote o tempo de espera. O padrão é 60*10.

osd scrub load threshold

A carga máxima normalizada. O Ceph não efetuará a depuração quando a carga do sistema (conforme definido pela proporção de getloadavg()/número de cpus online) for superior a esse número. O padrão é 0.5.

osd scrub min interval

O intervalo mínimo em segundos para depuração do Ceph OSD quando a carga do cluster do Ceph está baixa. O padrão é 60*60*24 (uma vez por dia).

osd scrub max interval

O intervalo máximo em segundos para depuração do Ceph OSD, independentemente da carga do cluster. O padrão é 7*60*60*24 (uma vez por semana).

osd scrub chunk min

O número mínimo de pacotes de armazenamento de objetos para depurar durante uma única operação. O Ceph bloqueia as gravações em um único pacote durante uma depuração. O padrão é 5.

osd scrub chunk max

O número máximo de pacotes de armazenamento de objetos para depurar durante uma única operação. O padrão é 25.

osd scrub sleep

O tempo no modo adormecido antes da depuração do próximo grupo de pacotes. O aumento desse valor desacelera toda a operação de depuração, enquanto as operações de cliente são menos afetadas. O padrão é 0.

osd deep scrub interval

O intervalo da depuração “profunda” (com leitura completa de todos os dados). A opção osd scrub load threshold não afeta essa configuração. O padrão é 60*60*24*7 (uma vez por semana).

osd scrub interval randomize ratio

Adicione um atraso aleatório ao valor osd scrub min interval ao programar a próxima tarefa de depuração para um grupo de posicionamento. O atraso é um valor aleatório menor do que o resultado de osd scrub min interval * osd scrub interval randomized ratio. Portanto, a configuração padrão distribui as depurações quase aleatoriamente dentro do período permitido de [1, 1,5] * osd scrub min interval. O padrão é 0.5.

osd deep scrub stride

Tamanho da leitura ao efetuar uma depuração profunda. O padrão é 524288 (512 KB).