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.
O Mapa CRUSH personalizado também pode ajudá-lo a identificar os locais físicos onde o Ceph armazena as cópias redundantes de dados, quando o(s) grupo(s) de posicionamento associado(s) ao host com falha está(ão) prejudicado(s).
Há três seções principais para um Mapa CRUSH.
Dispositivos representam qualquer dispositivo de armazenamento de objetos, ou seja, o disco rígido 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.
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.name
Por exemplo:
#devices device 0 osd.0 device 1 osd.1 device 2 osd.2 device 3 osd.3
Como regra geral, um daemon OSD é mapeado para um único disco.
Os mapas CRUSH contêm uma lista de OSDs, que podem ser organizados em “compartimentos de memória” para agregar os dispositivos em locais físicos.
0 |
OSD |
Um daemon OSD (osd.1, osd.2, etc.). |
1 |
Host |
Um nome de host que contém um ou mais OSDs. |
2 |
Chassis |
Chassis que compõe o rack. |
3 |
Rack |
Um rack de computador. O padrão é |
4 |
Fileira |
Uma fileira em uma série de racks. |
5 |
Pdu |
Unidade de distribuição de energia. |
6 |
Pod | |
7 |
Sala |
Uma sala com racks e fileiras de hosts. |
8 |
Data center |
Um data center físico com salas. |
9 |
Região | |
10 |
Root |
Você pode remover esses tipos 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 um pool denominado “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, straw
) 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 | 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 straw hash 0 item osd.0 weight 1.00 item osd.1 weight 1.00 } row rack-1-row-1 { id -16 alg straw hash 0 item ceph-osd-server-1 weight 2.00 } rack rack-3 { id -15 alg straw 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 straw 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 straw 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 straw 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 straw hash 0 item server-room-1 weight 30.00 item server-room-2 weight 30.00 } pool data { id -10 alg straw hash 0 item dc-1 weight 60.00 item dc-2 weight 60.00 }
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 cada pool e um conjunto de regras atribuído a cada um dos pools padrão.
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 }
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
.
Você precisa aumentar o número do conjunto de regras do padrão 0 continuamente; do contrário, o monitor relacionado poderá falhar.
Uma string. Descreve uma regra para um disco rígido (replicado) ou um RAID. Essa opção é obrigatória. O padrão é replicado
.
Um número inteiro. Se um grupo de posicionamento 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
.
Um número inteiro. Se um grupo de posicionamento 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
.
Usa um nome de compartimento de memória 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 6.3.1, “Iteração pela árvore de nós”.
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 6.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
.
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
.
Para ativar uma ou mais regras com um número comum do conjunto de regras para um pool, defina o número do conjunto de regras para o pool.
É 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 6.1, “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 }
Uma regra CRUSH define substituições para nós ou OSDs com falha (consulte a Seção 6.3, “Conjuntos de regras”). A palavra-chave step
requer firstn
ou indep
como parâmetro. A Figura 6.2, “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 com codificação de eliminação. Nos pools com codificação de 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.
Verifique se uma regra que usa indep
foi definida para cada pool com codificação de eliminação.
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.
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:
root #
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.
Descompile um Mapa CRUSH. Para descompilar um Mapa CRUSH, execute o seguinte:
cephadm >
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.
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:
cephadm >
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.
Defina um Mapa CRUSH. Para definir o Mapa CRUSH para o cluster, execute o seguinte:
root #
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.
Para adicionar ou mover um OSD no Mapa CRUSH de um cluster em execução, faça o seguinte:
root #
ceph osd crush set id_or_name weight root=pool-name
bucket-type=bucket-name ...
Um número inteiro. O ID numérico do OSD. Essa opção é obrigatória.
Uma string. O nome completo do OSD. Essa opção é obrigatória.
Um duplo. O peso do CRUSH para o OSD. Essa opção é obrigatória.
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.
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.
root #
ceph osd crush set osd.0 1.0 root=data datacenter=dc1 room=room1 \
row=foo rack=bar host=foo-bar-1
Para ajustar o peso do CRUSH de um OSD no Mapa CRUSH de um cluster em execução, faça o seguinte:
root #
ceph osd crush reweight name weight
Uma string. O nome completo do OSD. Essa opção é obrigatória.
Um duplo. O peso do CRUSH para o OSD. Essa opção é obrigatória.
Para remover um OSD do Mapa CRUSH de um cluster em execução, faça o seguinte:
root #
ceph osd crush remove name
Uma string. O nome completo do OSD. Essa opção é obrigatória.
Para mover um compartimento de memória para outro local ou posição na hierarquia do mapa CRUSH, execute o seguinte:
root #
ceph osd crush move bucket-name bucket-type=bucket-name, ...
Uma string. O nome do compartimento de memória para mover/reposicionar. Essa opção é obrigatória.
Pares de chave/valor. Você pode especificar o local do compartimento de memória na hierarquia do CRUSH.
Além de gerar várias cópias dos objetos, o Ceph garante a integridade dos dados por meio da depuração dos 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 o 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, ela começa em 0 e termina em 24.
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. 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 a 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 em 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).
Convém configurar um cluster do Ceph de modo que cada nó tenha uma combinação de SSDs e HDDs, com um pool de armazenamento em SSDs rápidas e outro em HDDs mais lentas. Para isso, o Mapa CRUSH precisa ser editado.
O Mapa CRUSH padrão terá uma hierarquia simples, na qual a raiz padrão incluirá hosts e os hosts incluirão OSDs. Por exemplo:
root #
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
Isso não faz distinção entre tipos de disco. Para dividir os OSDs em SSDs e HDDs, precisamos criar uma segunda hierarquia no Mapa CRUSH:
root #
ceph osd crush add-bucket ssd root
Após criar a nova raiz para SSDs, precisaremos adicionar hosts a ela. Isso significa a criação de novas entradas de host. No entanto, como o mesmo nome de host não pode aparecer mais do que uma vez no Mapa CRUSH, nomes de host falsos são usados. Esses nomes de host falsos não precisam ser resolvidos por DNS. O CRUSH não leva em consideração quais são os nomes de host, ele apenas precisa criar as hierarquias certas. A única coisa que realmente precisa ser mudada para suportar nomes de host falsos é que você deve definir
osd crush update on start = false
no arquivo /srv/salt/ceph/configuration/files/ceph.conf.d/global.conf
e, em seguida, executar a Fase 3 do DeepSea para distribuir a mudança (consulte a Seção 1.11, “Arquivo ceph.conf
personalizado” para obter mais informações):
root@master #
salt-run state.orch ceph.stage.3
Do contrário, os OSDs que você mover serão depois redefinidos ao seu local original na raiz padrão, e o cluster não terá o comportamento esperado.
Depois que essa configuração for mudada, adicione os novos hosts falsos à raiz da SSD:
root #
ceph osd crush add-bucket node1-ssd hostroot #
ceph osd crush move node1-ssd root=ssdroot #
ceph osd crush add-bucket node2-ssd hostroot #
ceph osd crush move node2-ssd root=ssdroot #
ceph osd crush add-bucket node3-ssd hostroot #
ceph osd crush move node3-ssd root=ssd
Por fim, para cada OSD de SSD, mova o OSD para a raiz da SSD. Neste exemplo, consideramos que osd.0, osd.1 e osd.2 estão fisicamente hospedados em SSDs:
root #
ceph osd crush add osd.0 1 root=ssdroot #
ceph osd crush set osd.0 1 root=ssd host=node1-ssdroot #
ceph osd crush add osd.1 1 root=ssdroot #
ceph osd crush set osd.1 1 root=ssd host=node2-ssdroot #
ceph osd crush add osd.2 1 root=ssdroot #
ceph osd crush set osd.2 1 root=ssd host=node3-ssd
A hierarquia do CRUSH deve ter esta aparência:
root #
ceph osd tree
ID WEIGHT TYPE NAME UP/DOWN REWEIGHT PRIMARY-AFFINITY
-5 3.00000 root ssd
-6 1.00000 host node1-ssd
0 1.00000 osd.0 up 1.00000 1.00000
-7 1.00000 host node2-ssd
1 1.00000 osd.1 up 1.00000 1.00000
-8 1.00000 host node3-ssd
2 1.00000 osd.2 up 1.00000 1.00000
-1 0.11096 root default
-2 0.03699 host node1
3 0.01849 osd.3 up 1.00000 1.00000
6 0.01849 osd.6 up 1.00000 1.00000
-3 0.03699 host node2
4 0.01849 osd.4 up 1.00000 1.00000
7 0.01849 osd.7 up 1.00000 1.00000
-4 0.03699 host node3
5 0.01849 osd.5 up 1.00000 1.00000
8 0.01849 osd.8 up 1.00000 1.00000
Agora, crie uma regra CRUSH direcionada à raiz da SSD:
root #
ceph osd crush rule create-simple ssd_replicated_ruleset ssd host
O replicated_ruleset
padrão original (com ID 0) será direcionado às HDDs. O novo ssd_replicated_ruleset
(com ID 1) será direcionado às SSDs.
Quaisquer pools existentes ainda usarão as HDDs, pois elas estão na hierarquia padrão no Mapa CRUSH. Um novo pool pode ser criado para usar apenas as SSDs:
root #
ceph osd pool create ssd-pool 64 64root #
ceph osd pool set ssd-pool crush_rule ssd_replicated_ruleset