MongoDB: Step Down entre membros de diferentes prioridades

Quando trabalhamos com um Replica Set no MongoDB (caso você ainda não saiba o que é um Replica Set, expliquei neste artigo), é comum que seja necessário alterar o banco primário em cenários de manutenção programada, ou em cenários de falha do host primário, quando o Mongo não faz isso automaticamente. Entretanto, em ambientes onde os membros do Replica Set possuem diferentes prioridades, a execução de um Step Down (comando para que uma eleição de um novo banco primário seja feita) tem suas particularidades.

Como funciona a priority?

A priority (ou prioridade) de um membro do Replica Set é um número associado a ele, de 0 a 1000, que indica a probabilidade daquele membro se tornar o membro primário. Quanto maior o valor, maior esta probabilidade.

A priority dos membros do Replica Set pode ser vista através do método rs.conf() do mongosh. Esse método nos retorna um documento que contém a configuração do Replica Set. Dentro deste documento existe um array chamado “members” e cada item deste array é um documento referente a cada membro do Replica Set. Por exemplo:

rsMongoServer [direct: primary] test> rs.config()
{
  _id: 'rsMongoServer',
  version: 2,
  term: 5,
  members: [
    {
      _id: 0,
      host: 'mongo-server-0:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 2,
      tags: {},
      secondaryDelaySecs: Long('0'),
      votes: 1
    },
    {
      _id: 1,
      host: 'mongo-server-1:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long('0'),
      votes: 1
    },
    {
      _id: 2,
      host: 'mongo-server-2:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 0,
      tags: {},
      secondaryDelaySecs: Long('0'),
      votes: 1
    }
  ],
  protocolVersion: Long('1'),
  writeConcernMajorityJournalDefault: true,
  settings: {
    chainingAllowed: true,
    heartbeatIntervalMillis: 2000,
    heartbeatTimeoutSecs: 10,
    electionTimeoutMillis: 10000,
    catchUpTimeoutMillis: -1,
    catchUpTakeoverDelayMillis: 30000,
    getLastErrorModes: {},
    getLastErrorDefaults: { w: 1, wtimeout: 0 },
    replicaSetId: ObjectId('66ee89b9905cec1617b71f0e')
  }
}

Neste exemplo, o membro “mongo-server-0” tem uma prioridade de 2, o membro “mongo-server-1” tem uma prioridade de 1 e o membro “mongo-server-2” tem uma prioridade de 0. Sendo assim, o membro com prioridade 2 tem a maior probabilidade de ser o membro primário da configuração. Esse tipo de configuração é útil quando desejamos que determinado host seja o primário (um cenário onde um dos hosts possui um hardware melhor ou uma latência menor que os demais, pode ser uma justificativa para essa abordagem).

Membros com prioridade igual a 0 (zero) não podem se tornar o membro primário, e não iniciam eleições por um novo primário.

Cuidados durante o Step Down

Digamos que neste cenário, tenhamos a necessidade de executar uma manutenção no host primário que irá afetar temporariamente a sua performance. Em um Replica Set onde as prioridades dos membros são idênticas, teríamos simplesmente que executar o método rs.stepDown() do mongosh, e um dos demais membros se tornaria o primário, fazendo com que o workload dele não fosse impactado pela manutenção. O mesmo não ocorre em Replica Sets com prioridades diferentes entre seus membros.

Caso um Step Down seja executado para a configuração acima, o membro “mongo-server-1” irá assumir o papel de primário, uma vez que o membro “mongo-server-2” tem prioridade 0 (zero). O problema aqui é que se existe algum membro com uma prioridade maior que o atual primário, o Mongo continua a fazer periodicamente novas eleições, até que o membro com maior prioridade se torne o primário. Esse comportamento é muito útil em cenários onde, após uma falha do primário, desejamos que tão logo ele seja restabelecido, volte a ser o primário novamente.

Como no cenário atual desejamos manter o membro “mongo-server-1” por um período indefinido como primário, precisamos alterar a sua prioridade para um valor maior do que o membro “mongo-server-1”. Para isso, salvamos o documento retornado pelo rs.config() em uma variável:

rsMongoServer [direct: primary] test> cfg = rs.config()

Com o documento na variável, podemos editar o valor dos campos do documento. Como desejamos alterar a prioridade do membro “mongo-server-1”, podemos executar:

rsMongoServer [direct: primary] test> cfg.members[1].priority = 3

Antes de aplicar os novos valores ao Replica Set, podemos verificar como ficaram as prioridades, chamando o array “members”:

rsMongoServer [direct: primary] test> cfg.members
[
  {
    _id: 0,
    host: 'mongo-server-0:27017',
    arbiterOnly: false,
    buildIndexes: true,
    hidden: false,
    priority: 2,
    tags: {},
    secondaryDelaySecs: Long('0'),
    votes: 1
  },
  {
    _id: 1,
    host: 'mongo-server-1:27017',
    arbiterOnly: false,
    buildIndexes: true,
    hidden: false,
    priority: 3,
    tags: {},
    secondaryDelaySecs: Long('0'),
    votes: 1
  },
  {
    _id: 2,
    host: 'mongo-server-2:27017',
    arbiterOnly: false,
    buildIndexes: true,
    hidden: false,
    priority: 0,
    tags: {},
    secondaryDelaySecs: Long('0'),
    votes: 1
  }
]

Agora nosso membro “mongo-server-1” possui uma prioridade de 3, superior à prioridade 2 do membro “mongo-server-0”.

Para aplicar os novos valores à configuração do Replica Set, usamos o método rs.reconfig(), passando por parâmetro o documento presente na variável:

rsMongoServer [direct: primary] test> rs.reconfig(cfg)

Importante: o método rs.reconfig() só pode ser executado no primário.

Uma vez aplicada a nova configuração, o Mongo identificará a alteração da prioridade do membro e uma nova eleição é iniciada, alterando automaticamente o primário, sem a necessidade da execução do Step Down.

Conclusão

De modo geral, antes de executar um Step Down, quando temos a intenção de manter o novo primário por um tempo indeterminado, é verificar como está a atual configuração do Replica Set. Com isso evitamos que novas eleições ocorram e que o primário volte a ser o membro que não desejamos, possivelmente impactando a aplicação conectada ao banco.

Publicar comentário