Como o armazenamento do S3 DataLine funciona



Olá Habr!

Não é segredo que grandes quantidades de dados estão envolvidas no trabalho de aplicativos modernos e seu fluxo está em constante crescimento. Esses dados precisam ser armazenados e processados, geralmente em um grande número de máquinas, e isso não é uma tarefa fácil. Para resolvê-lo, existem armazenamentos de objetos na nuvem. Geralmente eles são uma implementação da tecnologia de armazenamento definido por software.

No início de 2018, lançamos (e lançamos!) Nosso próprio armazenamento 100% compatível com S3, baseado no Cloudian HyperStore. Como se viu, a rede tem muito poucas publicações em russo sobre o próprio Cloudian e muito menos sobre a aplicação real dessa solução.

Hoje, com base na experiência do DataLine, vou falar sobre a arquitetura e a estrutura interna do software Cloudian, incluindo a implementação do Cloudian SDS com base em várias soluções arquitetônicas Apache Cassandra. Separadamente, consideramos o mais interessante em qualquer armazenamento SDS - a lógica de garantir tolerância a falhas e distribuição de objetos.

Se você estiver construindo seu armazenamento S3 ou estiver ocupado mantendo-o, este artigo será útil para você.

Antes de tudo, explicarei por que nossa escolha caiu no Cloudian. É simples: existem muito poucas opções dignas nesse nicho. Por exemplo, alguns anos atrás, quando estávamos pensando em construir, havia apenas três opções:

  • Gateway CEHP + RADOS;
  • Minio
  • Cloudian HyperStore.

Para nós, como provedor de serviços, os fatores decisivos foram: um alto nível de correspondência entre a API de armazenamento e o Amazon S3 original, a disponibilidade do faturamento interno, a escalabilidade com suporte multirregionalidade e a presença de uma terceira linha de suporte ao fornecedor. Cloudian tem tudo isso.

E sim, o mais (certamente!) O mais importante é que o DataLine e o Cloudian têm cores corporativas semelhantes. Você deve admitir que não conseguimos resistir a tanta beleza.



Infelizmente, o Cloudian não é o software mais comum e praticamente não há informações sobre ele no RuNet. Hoje vamos corrigir essa injustiça e conversar com você sobre os recursos da arquitetura HyperStore, examinar seus componentes mais importantes e lidar com as principais nuances da arquitetura. Vamos começar com o mais básico, a saber: o que é o Cloudian sob o capô?

Como o armazenamento Cloudian HyperStore funciona


Vamos dar uma olhada no diagrama e ver como a solução Cloudian funciona.


O principal esquema de armazenamento de componentes.

Como podemos ver, o sistema consiste em vários componentes principais:

  • Cloudian Management Control - console de gerenciamento ;
  • Serviço Administrativo - módulo de administração interna ;
  • Serviço S3 - o módulo responsável pelo suporte ao protocolo S3 ;
  • Serviço HyperStore - o serviço de armazenamento real ;
  • Apache Cassandra - um repositório centralizado de dados de serviço ;
  • Redis - para os dados lidos com mais frequência .

De maior interesse para nós será o trabalho dos principais serviços, S3 Service e HyperStore Service, e consideraremos cuidadosamente o trabalho deles. Mas, primeiro, faz sentido descobrir como a distribuição dos serviços no cluster é organizada e qual é a tolerância a falhas e a confiabilidade do armazenamento de dados desta solução como um todo.




Por serviços comuns no diagrama acima, entendemos os serviços S3, HyperStore, CMC e Apache Cassandra . À primeira vista, tudo é bonito e arrumado. Porém, após uma análise mais detalhada, verifica-se que apenas uma falha de um nó é efetivamente resolvida. E a perda simultânea de dois nós ao mesmo tempo pode ser fatal para a disponibilidade do cluster - o Redis QoS (no nó 2) possui apenas 1 escravo (no nó 3). A mesma imagem com o risco de perder o gerenciamento de cluster - o Puppet Server é apenas em dois nós (1 e 2). No entanto, a probabilidade de falha de dois nós ao mesmo tempo é muito baixa e você pode conviver com ele.

No entanto, para aumentar a confiabilidade do armazenamento, usamos 4 nós no DataLine em vez dos três mínimos. A seguinte distribuição de recursos é obtida:



Mais uma nuance chama sua atenção imediatamente - as credenciais Redis não são colocadas em todos os nós (como poderia ser assumido no esquema oficial acima), mas apenas em três deles. Nesse caso, as credenciais Redis são usadas para todas as solicitações recebidas. Acontece que, devido à necessidade de ir para os Redis de outra pessoa, há algum desequilíbrio no desempenho do quarto nó.

Para nós, isso ainda não é significativo. Durante o teste de estresse, não foram observados desvios significativos na velocidade de resposta dos nós, mas em grandes grupos de dezenas de nós em funcionamento, faz sentido corrigir essa nuance.

É assim que o esquema de migração em 6 nós se parece:



O diagrama mostra como a migração de serviço é implementada no evento de uma falha do nó. Somente a falha de um servidor de cada função é levada em consideração. Se ambos os servidores caírem, será necessária intervenção manual.

Aqui também o negócio não ficou isento de sutilezas. A migração de função usa o Puppet. Portanto, se você o perder ou acidentalmente quebrá-lo, o failover automático pode não funcionar. Pelo mesmo motivo, você não deve editar manualmente o manifesto do Puppet interno. Isso não é totalmente seguro, as alterações podem ser repentinamente desgastadas, pois os manifestos são editados usando o painel de administração do cluster.

Do ponto de vista da segurança dos dados, tudo é muito mais interessante. Os metadados do objeto são armazenados no Apache Cassandra e cada registro é replicado para 3 de 4 nós. O fator de replicação 3 também é usado para armazenar dados, mas você pode configurar um maior. Isso garante a segurança dos dados, mesmo em caso de falha simultânea de 2 dos 4 nós. E se você tiver tempo para reequilibrar o cluster, não poderá perder nada com um nó restante. O principal é ter espaço suficiente.



É o que acontece quando dois nós falham. O diagrama mostra claramente que, mesmo nessa situação, os dados permanecem seguros

Ao mesmo tempo, a disponibilidade de dados e armazenamento dependerá da estratégia de garantir consistência. Para dados, metadados, leitura e gravação, eles são configurados separadamente.

As opções válidas são pelo menos um nó, quorum ou todos os nós.
Essa configuração determina quantos nós devem confirmar a gravação / leitura para que a solicitação seja considerada bem-sucedida. Usamos o quorum como um compromisso razoável entre o tempo necessário para processar uma solicitação e a confiabilidade da escrita / inconsistência da leitura. Ou seja, dos três nós envolvidos na operação, para uma operação sem erros, basta obter uma resposta consistente de 2. Portanto, para manter-se à tona no caso de falha de mais de um nó, você precisará mudar para uma única estratégia de gravação / leitura.

Processamento de consultas no Cloudian


Abaixo, consideraremos dois esquemas para processar solicitações recebidas no Cloudian HyperStore, PUT e GET. Essa é a principal tarefa do S3 Service e HyperStore.

Vamos começar como a solicitação de gravação é processada:



Certamente, você observou que cada solicitação gera muitas verificações e recuperações de dados, pelo menos seis ocorrências de componente para componente. É a partir daqui que os atrasos na gravação e o alto consumo de tempo da CPU aparecem quando se trabalha com arquivos pequenos.

Arquivos grandes são transmitidos por pedaços. Pedaços separados não são considerados pedidos separados e algumas verificações não são realizadas.

O nó que recebeu a solicitação inicial determina ainda de maneira independente onde e o que gravar, mesmo que não seja gravado diretamente nele. Isso permite ocultar a organização interna do cluster do cliente final e usar balanceadores de carga externos. Tudo isso afeta positivamente a facilidade de manutenção e a tolerância a falhas do armazenamento.



Como você pode ver, a lógica de leitura não é muito diferente da escrita. Nele, é observada a mesma alta sensibilidade do desempenho para o tamanho dos objetos processados. Portanto, devido a economias significativas no trabalho com metadados, é muito mais fácil extrair um objeto picado do que muitos objetos separados do mesmo volume total.

Armazenamento e duplicação de dados


Como você pode ver nos diagramas acima, o Cloudian suporta vários esquemas de armazenamento e duplicação de dados:

Replicação - usando a replicação, é possível manter um número personalizado de cópias de cada objeto de dados no sistema e armazenar cada cópia em nós diferentes. Por exemplo, usando a replicação 3X, 3 cópias de cada objeto são criadas e cada cópia “fica” em seu próprio nó.

Codificação de apagamento - Com a codificação de apagamento, cada objeto é codificado em uma quantidade personalizada (conhecida como número K) de fragmentos de dados mais uma quantidade personalizada de código de redundância (número M). Cada fragmento K + M de um objeto é único e cada fragmento é armazenado em seu próprio nó. Um objeto pode ser decodificado usando qualquer K fragmento. Em outras palavras, o objeto permanece legível, mesmo se os nós M estiverem inacessíveis.

Por exemplo, na codificação de apagamento, de acordo com a fórmula 4 + 2 (4 fragmentos de dados mais 2 fragmentos de código de redundância), cada objeto é dividido em 6 fragmentos exclusivos armazenados em seis nós diferentes, e esse objeto pode ser restaurado e lido se houver 4 de 6 fragmentos disponíveis .

A vantagem do Erasure Coding, em comparação com a replicação, é economizar espaço, embora ao custo de um aumento significativo na carga do processador, piorando a velocidade de resposta e a necessidade de procedimentos em segundo plano para controlar a consistência dos objetos. De qualquer forma, os metadados são armazenados separadamente dos dados (no Apache Cassandra), o que aumenta a flexibilidade e a confiabilidade da solução.

Brevemente sobre outras funções do HyperStore


Como escrevi no começo deste artigo, várias ferramentas úteis são incorporadas ao HyperStore. Entre eles estão:

  • Faturamento flexível com suporte para alterar o preço de um recurso, dependendo do volume e plano tarifário;
  • Monitoramento incorporado
  • A capacidade de limitar o uso de recursos para usuários e grupos de usuários;
  • Configurações de QoS e procedimentos internos para equilibrar o uso de recursos entre nós, bem como procedimentos regulares para rebalancear entre nós e discos nos nós ou ao inserir novos nós em um cluster.

No entanto, o Cloudian HyperStore ainda não é perfeito. Por exemplo, por algum motivo, você não pode transferir uma conta existente para outro grupo ou atribuir vários grupos a um registro. Não é possível gerar relatórios de cobrança intermediários - você receberá todos os relatórios somente após o encerramento do período do relatório. Portanto, nem clientes nem podemos descobrir quanto a conta cresceu em tempo real.

Lógica Cloudian HyperStore


Agora vamos nos aprofundar ainda mais e examinar o mais interessante em qualquer armazenamento SDS - a lógica da distribuição de objetos por nós. No caso do armazenamento Cloudian, os metadados são armazenados separadamente dos próprios dados. Para metadados, o Cassandra é usado, para dados, a solução proprietária HyperStore.

Infelizmente, até o momento não há tradução oficial da documentação do Cloudian para o russo na Internet; portanto, postarei minha tradução das partes mais interessantes desta documentação.

O papel do Apache Cassandra no HyperStore


No HyperStore, o Cassandra é usado para armazenar metadados do objeto, informações da conta do usuário e dados de uso do serviço. Em uma implantação típica em cada HyperStore, os dados do Cassandra são armazenados na mesma unidade do sistema operacional. O sistema também suporta dados do Cassandra em uma unidade dedicada em cada nó. Os dados do Cassandra não são armazenados nos discos de dados do HyperStore. Quando os vNodes são atribuídos ao host, eles são distribuídos apenas para os nós de armazenamento HyperStore. vNodes não são alocados para a unidade em que os dados do Cassandra estão armazenados.
Dentro do cluster, os metadados no Cassandra são replicados de acordo com a política (estratégia) do seu repositório. O Cassandra Data Replication usa vNodes desta maneira:

  • Ao criar um novo objeto Cassandra (chave primária e seus valores correspondentes), ele é um hash e o hash é usado para associar o objeto a um vNode específico. O sistema verifica a qual host esse vNode está atribuído e, em seguida, a primeira réplica do objeto Cassandra é armazenada na unidade Cassandra nesse host.
  • Por exemplo, suponha que um host receba 96 vNodes distribuídos em vários discos de dados HyperStore. Os objetos Cassandra cujos valores de hash se enquadram nos intervalos de token de qualquer um desses 96 vNodes serão gravados na unidade Cassandra neste host.
  • Réplicas adicionais do objeto Cassandra (o número de réplicas depende da sua configuração) são associadas aos vNodes com o seguinte número de sequência e armazenadas no nó ao qual esses vNodes são atribuídos, desde que os vNodes sejam ignorados, se necessário, para que cada réplica do objeto Cassandra seja armazenada em outro máquina host.

Como o armazenamento HyperStore funciona


O posicionamento e a replicação dos objetos S3 em um cluster HyperStore são baseados em um esquema de armazenamento em cache consistente que usa espaço de token inteiro no intervalo de 0 a 2 127 -1. Os tokens inteiros são atribuídos aos nós do HyperStore. Para cada objeto S3, um hash é calculado à medida que é carregado no armazenamento. O objeto é armazenado no nó ao qual foi atribuído o valor mais baixo do token, maior ou igual ao valor do hash do objeto. A replicação também é implementada armazenando o objeto nos nós aos quais os tokens foram atribuídos, que possuem um valor mínimo.

Em um armazenamento baseado em hash consistente "clássico", um token é atribuído a um nó físico. O sistema Cloudian HyperStore usa e estende a funcionalidade do “nó virtual” (vNode) introduzido no Cassandra na versão 1.2 - um grande número de tokens é designado a cada host físico (máximo de 256). De fato, o cluster de armazenamento consiste em um número muito grande de "nós virtuais" com um grande número de nós virtuais (tokens) em cada host físico.

O sistema HyperStore atribui um conjunto separado de tokens (nós virtuais) a cada disco em cada host físico. Cada disco no host é responsável por seu próprio conjunto de réplicas de objetos. Uma falha no disco afeta apenas réplicas de objetos que estão nele. Outras unidades no host continuarão a operar e executar suas responsabilidades de armazenamento de dados.

Damos um exemplo e consideramos um cluster de 6 hosts HyperStore, cada um com 4 discos de armazenamento S3. Suponha que 32 tokens sejam atribuídos a cada host físico e haja um espaço de token simplificado de 0 a 960, e o valor de 192 tokens neste sistema (6 hosts de 32 tokens cada) seja 0, 5, 10, 15, 20 e assim por diante até 955.

O diagrama abaixo mostra uma possível distribuição de tokens por todo o cluster. 32 tokens de cada host são distribuídos igualmente por 4 discos (8 tokens por disco) e os próprios tokens são distribuídos aleatoriamente pelo cluster.



Agora, suponha que você configurou o HyperStore para replicar 3X objetos S3. Vamos concordar que o objeto S3 é carregado no sistema e o algoritmo de hash aplicado a seu nome nos fornece o valor de 322 hash (neste espaço de hash simplificado). O diagrama abaixo mostra como três instâncias ou réplicas de um objeto serão armazenadas em um cluster:

  • Com seu valor de hash de nome 322, a primeira réplica do objeto é armazenada no token 325, porque esse é o menor valor do token que é maior ou igual ao valor do hash do objeto. 325 tokens (destacados em vermelho no diagrama) são atribuídos à hyperstore2: Disk2. Assim, a primeira réplica do objeto é armazenada lá.

  • A segunda réplica é armazenada no disco ao qual está atribuído o próximo token (330, destacado em laranja), ou seja, na hyperstore4: Disk2.
  • A terceira réplica é salva no disco, ao qual é atribuído o próximo token após 330 - 335 (amarelo), na hyperstore3: Disk3.


Acrescentarei um comentário: do ponto de vista prático, essa otimização (a distribuição de tokens não apenas entre nós físicos, mas também entre discos individuais) é necessária não apenas para garantir a acessibilidade, mas também para garantir a distribuição uniforme de dados entre os discos. Nesse caso, a matriz RAID não é usada, toda a lógica da alocação de dados nos discos é controlada pelo próprio HyperStore. Por um lado, é conveniente e controlado; se um disco for perdido, tudo será reequilibrado por si próprio. Por outro lado, eu pessoalmente confio em mais bons controladores RAID - afinal, sua lógica foi otimizada por muitos anos. Mas essas são todas as minhas preferências pessoais, sobre batentes e problemas reais, que nunca pegamos no HyperStore, se seguirmos as recomendações do fornecedor ao instalar o software em servidores físicos. Mas a tentativa de usar virtualização e discos virtuais em cima da mesma lua no sistema de armazenamento falhou. Ao sobrecarregar o sistema de armazenamento durante o teste de carga, o HyperStore enlouqueceu e dispersou os dados de maneira totalmente desigual, obstruindo alguns discos e não tocando em outros.

Conduzir dispositivo dentro de um cluster


Lembre-se de que cada host possui 32 tokens, e os tokens de cada host são distribuídos igualmente entre seus discos. Vamos dar uma olhada em hyperstore2: Disk2 (no diagrama abaixo). Vemos que os tokens 325, 425, 370 e assim por diante são atribuídos a este disco.

Como o cluster está configurado para replicação 3X, o seguinte será armazenado na hyperstore2: Disco2:

De acordo com o token de disco 325:
  • As primeiras réplicas de objetos com um valor de hash de 320 (exclusivamente) a 325 (inclusive);
  • Segundas réplicas de objetos com um valor de hash de 315 (exclusivamente) a 320 (inclusive);
  • Terceiras réplicas de objetos com um valor de hash de 310 (exclusivamente) a 315 (inclusive).

De acordo com o token de disco 425:
  • As primeiras réplicas de objetos com um valor de hash de 420 (exclusivamente) a 425 (inclusive);
  • Segundas réplicas de objetos com um valor de hash de 415 (exclusivamente) a 420 (inclusive);
  • Terceiras réplicas de objetos com um valor de hash de 410 (exclusivamente) a 415 (inclusive).

E assim por diante

Conforme observado anteriormente, ao colocar a segunda e a terceira réplicas, o HyperStore pode, em alguns casos, transmitir tokens para não armazenar mais de uma cópia do objeto em um nó físico. Isso elimina o uso de hyperstore2: disk2 como armazenamento para segunda ou terceira réplicas do mesmo objeto.



Se o disco 2 travar nos discos 1, 3 e 4, os dados continuarão sendo armazenados e os objetos no disco 2 serão armazenados no cluster, porque foram replicados para outros hosts.
Comentário: como resultado, a distribuição de réplicas e / ou fragmentos de objetos no cluster HyperStore é baseada no design do Cassandra, desenvolvido para as necessidades de armazenamento de arquivos. , , , , «» . . . , : , , .


Agora vamos ver como o HyperStore funciona em vários data centers e regiões. No nosso caso, o modo multi-DPC difere do modo multi-regional usando um ou mais espaços de token. No primeiro caso, o espaço do token é uniforme. No segundo, cada região terá um espaço de token independente com (potencialmente) suas próprias configurações para o nível de consistência, capacidade e configurações de armazenamento.
Para entender como isso funciona, voltemos novamente à tradução da documentação, seção “Implantações de vários centros de dados”.

Considere a implantação do HyperStore em dois data centers. Chame-os de DC1 e DC2. Cada centro de dados possui 3 nós físicos. Como nos exemplos anteriores, cada nó físico possui quatro discos, 32 tokens (vNodes) são atribuídos a cada host e assumimos um espaço de token simplificado de 0 a 960. De acordo com esse cenário, com vários datacenters, o espaço de token é dividido em 192 tokens - 32 tokens para cada um dos 6 hosts físicos. Os tokens são distribuídos pelos hosts absolutamente aleatoriamente.

Suponha também que a replicação de objetos S3 nesse caso esteja configurada em duas réplicas em cada data center.

Vejamos como um objeto hipotético S3 com um valor de hash 942 será replicado em 2 data centers:

  • vNode 945 ( ), DC2, hyperstore5:Disk3.
  • vNode 950 ( ) DC2, hyperstore6:Disk4.
  • vNode 955 DC2, , vNode .
  • vNode 0 () — DC1, hyperstore2:Disk3. , (955) (0).
  • vNode (5) DC2, , vNode .
  • vNode 10 () — DC1, hyperstore3:Disk3.


: , , , , . , .
Cloudian. , , . , , , , .
S3 DataLine, , !

Source: https://habr.com/ru/post/pt423853/


All Articles