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 representam 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 os 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.3 class 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.
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,3cephuser@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=hostcephuser@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
ouprefix%
. 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 etapastake
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 originalcephuser@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 adjustedPara 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 equivalentDicaSe 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 ( |
1 |
host |
O nome de um host que contém um ou mais OSDs. |
2 |
Chassi |
Identificador do chassi que contém o |
3 |
rack |
Um rack de computador. O padrão é |
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 |
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.
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
ouchooseleaf
. Quando definido comochoose
, 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
ouindep
. 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
oustep 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.
# 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.
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.
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:
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 #
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 Section 8.1.1.1, “Default PG and PGP counts”.
Ao criar um novo pool, você ainda pode escolher o valor de PG_NUM manualmente:
#
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 #
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 Section 8.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:
#
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:
#
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
:
#
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:
#
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:
#
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:
#
ceph pg map PG_ID
O Ceph retornará o mapa do grupo de posicionamento, o grupo de posicionamento e o status do OSD:
#
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:
#
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:
#
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:
#
ceph pg force-recovery PG_ID1 [PG_ID2 ... ]#
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:
#
ceph pg cancel-force-recovery PG_ID1 [PG_ID2 ... ]#
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:
Obtenha um Mapa CRUSH. Para obter o Mapa CRUSH para seu cluster, execute o seguinte:
cephuser@adm >
ceph osd getcrushmap -o compiled-crushmap-filenameO 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.Descompile um Mapa CRUSH. Para descompilar um Mapa CRUSH, execute o seguinte:
cephuser@adm >
crushtool -d compiled-crushmap-filename \ -o decompiled-crushmap-filenameO Ceph descompilará (
-d
) o Mapa CRUSH compilado e o gerará (-o
) com o nome de arquivo que você especificou.Edite pelo menos um dos parâmetros de Dispositivos, Compartimentos de Memória e Regras.
Compile um Mapa CRUSH. Para compilar um Mapa CRUSH, execute o seguinte:
cephuser@adm >
crushtool -c decompiled-crush-map-filename \ -o compiled-crush-map-filenameO Ceph armazenará um Mapa CRUSH compilado com o nome de arquivo que você especificou.
Defina um Mapa CRUSH. Para definir o Mapa CRUSH para o cluster, execute o seguinte:
cephuser@adm >
ceph osd setcrushmap -i compiled-crushmap-filenameO Ceph inserirá o Mapa CRUSH compilado do nome de arquivo que você especificou como o Mapa CRUSH para o cluster.
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.
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.
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
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.
ImportanteSe 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 decpus 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 deosd 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).