World of Warcraft

Oficina do Engenheiro: recriando o Esforço de Guerra de Ahn’Qiraj

Oficina do Engenheiro: recriando o Esforço de Guerra de Ahn’Qiraj

A guerra é iminente. Neste mês, lançamos um dos eventos mais esperados de World of Warcraft Classic, o Esforço de Guerra de Ahn’Qiraj. Com a força combinada da Horda e da Aliança, reinos inteiros do Classic se reuniram e contribuíram com recursos para abrir os portões e desbloquear os raides de Ahn’Qiraj. Quando a Guerra das Areias Cambiantes ocorreu pela primeira (e única) vez em 2006, milhares de jogadores de cada reino voaram ou cavalgaram até Silithus para testemunhar ou participar do caos. O comparecimento foi muito maior do que a equipe de desenvolvimento jamais imaginou e, assim, não estávamos preparados. Os servidores logo ficaram sobrecarregados e, durante um período de 12 horas, muitos jogadores acabaram em um ciclo de entrar no jogo, cair e tentar entrar de novo enquanto nossos engenheiros suavam para corrigir problemas e reconectar os jogadores. Conseguimos estabilizar os servidores durante o evento, mas aprendemos muitas lições e vimos oportunidades para melhorar. Quinze anos depois, estávamos prontos para recriar um dos momentos mais épicos da história de WoW no WoW Classic, agora com foco na otimização dos servidores para combater o atraso e eliminar travamentos, além de hospedar em Silithus o dobro dos jogadores que recebemos na estreia do evento em 2006.

Neste artigo, vamos explicar como conseguimos recriar esse aguardadíssimo evento usando jogadores automatizados e testes de estresse para determinar os pontos de ruptura e criar soluções de otimização, como elaboramos à mão soluções de software para resolver problemas de que o hardware não dava conta e como conduzimos um evento mundial com poucos travamentos de servidor, tudo isso sem desfigurar a experiência de jogo do WoW Classic.

Recriando a Segunda Guerra das Areias Cambiantes

Tínhamos três metas específicas na hora de abordar a engenharia do evento: impedir travamentos em sequência, aumentar os limites de jogadores na área esperada e determinar o atraso aceitável antes de transportar jogadores para fora de Silithus. Antes de entrarmos nos detalhes de como maximizamos o desempenho dos servidores, é importante entender as restrições com as quais estamos trabalhando: as limitações da base de código do WoW Classic, o mecanismo das soluções de gerenciamento de população e o impacto delas na jogabilidade.

Anubisaths invadem Azeroth

Além dos limites

A versão moderna de World of Warcraft foi desenvolvida em cima da base de código original, lançada há 15 anos. Desde o lançamento do jogo, desenvolvemos formas mais modernas de lidar com grandes números de jogadores em Battle for Azeroth, especialmente a fragmentação. Fragmentos permitem que os servidores de WoW hospedem muito mais gente no jogo hoje do que em 2006. Em Battle for Azeroth, usamos fragmentos para gerenciar a capacidade dos servidores fazendo uma cópia de uma área (Zuldazar, por exemplo) quando o número de jogadores atinge um certo limite. Isso neutraliza problemas de atraso espalhando os jogadores em diferentes versões da área, já que as interações entre eles são as que mais utilizam CPU devido à quantidade de pacotes enviados constantemente ao servidor para garantir a precisão de movimentos e feitiços. Além disso, a fragmentação reduz os atrasos em potencial durante transições para uma nova área onde a quantidade de jogadores exceda o limite. Parece simples, mas há um porém: o WoW Classic foi desenvolvido como uma recriação fiel dos dados de jogo originais da versão 1.12, e isso envolve preservar suas idiossincrasias. Em casos raros, fragmentos farão sua presa, seja ela um jogador inimigo ou PNJ, desaparecer na transição para uma nova área. Manter os fragmentos significaria perder alguns daqueles momentos nostálgicos de perseguição a jogadores e PNJs entre fronteiras de áreas. Assim, precisávamos criar uma solução que não interferisse na jogabilidade original e, ao mesmo tempo, permitisse colocar mais jogadores no servidor sem forçá-los a sofrer com um atraso impraticável.

Para resolver esse problema, decidimos usar camadas, ou seja, cópias de regiões inteiras (os Reinos do Leste, por exemplo), para gerenciar a população de jogadores e os atrasos e manter o charme do lançamento original intacto. Assim, os jogadores podem mais uma vez conduzir Chefes Mundiais de uma área para outra e perseguir jogadores inimigos entre as fronteiras de uma região sem correr o risco de que eles sejam transferidos para um fragmento diferente. No entanto, as camadas não foram desenvolvidas como uma solução permanente. Como a versão 1.12 original não usava tecnologias de fragmentação ou camadas, prometemos aos jogadores que só usaríamos camadas no lançamento do WoW Classic, descartando-as com o tempo quando se dispersassem de maneira mais uniforme pelo mundo. Há alguns poucos casos em que ainda usamos camadas devido a populações enormes de jogadores ativos (Faerlina da América do Norte, por exemplo), mas reduzimos o número de camadas ativas nesses reinos desde o lançamento do jogo. Com 15 anos de espera, a guerra de AQ está entre os eventos mais aguardados do WoW Classic e esperamos que receba a maior quantidade de jogadores em uma área, tirando as áreas iniciais no lançamento do jogo, sem camadas para gerenciá-la. Sem tecnologia de camadas ou fragmentação, tínhamos que ser criativos, e rápido.

Jogadores reunidos em torno do Gongo

Elaborando à mão uma experiência inesquecível

Começamos a tarefa de achar uma solução de população sem camadas nem fragmentação gerando clientes sem cabeça — jogadores automatizados — e instruindo-os a imitar o que os jogadores reais podem fazer, como lançar feitiços, enfrentar PNJs e andar pela área. Com isso, pudemos tirar um instantâneo do possível desempenho com milhares de jogadores interagindo em uma única área. Após rodar essas simulações, organizamos testes de estresse com voluntários para registrar um comportamento mais realista dos jogadores e comparar ambos. Isso nos deu uma indicação de certos pontos de ruptura e de quais partes do código do nosso servidor estavam enfrentando mais problemas com grandes números de jogadores. As medições de tempo de quadro do servidor foram analisadas minuciosamente para ver se estavam chegando perto de deixar um servidor travado, o que também é conhecido como impasse.

O próximo passo foi analisar o que estava afetando o desempenho do servidor para que pudéssemos começar a dividir essa tarefa gigantesca em metas reduzidas. O que encontramos foi um problema polinomial, que não pode ser resolvido apenas com hardware mais acelerado, pois o hardware não melhora exponencialmente. Em vez disso, tivemos que fazer a otimização à mão, escolhendo deliberadamente quais dados devem ser comunicados aos jogadores e com que frequência. Para ilustrar essa situação, vamos supor que haja 20 jogadores pulando em um círculo. O servidor retransmite as ações de cada jogador para os outros 19 através de pacotes (dados entregáveis). Nesse grupo de 20, o servidor processa 380 pacotes (20 jogadores no total x 19 destinatários = 380 pacotes). O problema vai acumulando quando mais jogadores realizam a mesma ação na área. Se aumentarmos nosso exemplo para 500 jogadores, então 249.500 pacotes serão enviados pelo servidor. Se aumentarmos nosso exemplo de novo para 1.500 jogadores, 2.248.500 pacotes serão enviados. Dependendo das ações dos jogadores, vários pacotes são enviados por segundo, tudo isso para uma só ação. Quanto mais pacotes são enviados ao servidor, maior o tempo de processamento que ele vai gastar em um único jogador, para depois lidar com as ações de todos os outros jogadores. Quando esse problema acumula, os servidores começam a se aproximar de um impasse. No WoW Classic, temos muito mais jogadores por reino do que em 2006, então a expectativa é de acomodar uma quantidade de jogadores em torno dos portões que jamais tivemos antes.

Otimizando o desempenho do servidor

Nossos servidores foram configurados para travar e reiniciar se encontrarem um impasse, então sabíamos que era essencial fazer todo o possível para minimizar o tempo de processamento. Após alguns testes, ficou claro que a movimentação era a primeira peça do poder de processamento que estava sobrecarregando nossos servidores. Começamos reduzindo atualizações de direcionamento (exibir para que lado um modelo de personagem está virado) para só mandá-las quando um jogador começar, parar ou usar movimento de teclado. Como a latência já fica comprometida com uma quantidade excessiva de jogadores, gastar tempo na CPU enviando atualizações menores de direcionamento piorava a fidelidade. Assim, era melhor parar de enviá-las. Tomamos a decisão de reduzir a frequência de envio de atualizações de movimentos para poder ter mais jogadores em uma área. Lembre-se de que estamos tentando achar o ponto de ruptura antes de os servidores caírem e, ao mesmo tempo, permitir o máximo de jogadores possível em Silithus. Afinal de contas, é melhor perder algumas atualizações de movimento do que não conseguir sequer entrar com seu personagem. Também começamos a retardar dados marcados como de baixa prioridade. Uma ação considerada “menos importante” não deve ser enviada com a mesma velocidade das ações “mais importantes”. Vimos muitas mensagens enviadas ao mesmo tempo, independentemente da importância delas, e otimizamos o código para só mandar informações menos importantes em lotes e com menor frequência.

Bônus e penalidades eram outro peso enorme no nosso desempenho. Em todo o mundo, especialmente ao lutar contra grupos, bônus e penalidades são aplicados a unidades o tempo todo. Embora isso não pareça nada de mais, com uma grande concentração de jogadores próximos, essa informação precisa ser passada adiante. De forma semelhante ao retardamento de dados de baixa prioridade, agora agrupamos os bônus e penalidades em lotes para evitar o envio de vários pacotes sucessivos aos jogadores.

Gerenciando populações de jogadores

Além de otimizar os servidores para lidar com mais jogadores em cada área, não deixamos de notar que seria impossível acomodar a população inteira de um reino — mais que o dobro do que o reino do WoW 1.12 original podia acomodar — em Silithus. Decisões difíceis tiveram que ser tomadas para limitar o acesso à área, controlando quantos e quais jogadores poderiam entrar. Decidimos que só personagens de nível 60 podiam entrar em Silithus, e só enquanto o local não enchesse. Criar essa restrição foi a escolha certa a fazer, já que o evento em Silithus é conteúdo pós-jogo e os jogadores de nível mais baixo ainda podem participar do Esforço de Guerra em outras áreas — matando anubisaths que vagam nos Sertões desenvolvidos para personagens de níveis 20 a 30, por exemplo. O segundo ponto importante foi que sabíamos o número máximo de jogadores que podíamos manter em uma área sem travar o servidor; a questão agora era em quanto esse número deveria ser reduzido para obter a melhor proporção entre desempenho e jogadores. Nos testes, descobrimos que esse número ficava em torno de 1.500 jogadores se todos estivessem empilhados. No entanto, como o evento ocorre em toda a área, vimos pouquíssimos problemas de desempenho quando os jogadores se dispersavam.

O evento foi planejado para ocorrer em todas as regiões, então tínhamos que garantir que funcionasse entre diversas camadas. Isto é, um portador de Cetro que tocasse o gongo em uma camada deveria iniciar o evento em todas as outras ligadas ao mesmo reino. Como a ativação do evento se baseia em uma interação de jogadores, queríamos garantir que o portador de Cetro ficasse visível entre camadas, para que todos os jogadores no mesmo reino pudessem vê-lo. Isso gerou um problema interessante, já que agora os servidores tinham que retransmitir uma informação que normalmente não precisariam comunicar entre si. Isso pode criar uma série de complicações enquanto compilamos e enviamos atualizações entre os servidores para garantir que os dados sejam espelhados em várias camadas, talvez para milhares de jogadores.

Começamos a desenvolver essa tecnologia com a introdução do Campeonato de Pesca da Selva do Espinhaço e depois a aplicamos aos bônus mundiais de Onyxia, Nefarian, Zul'Gurub e Dilacerar. Quando achamos que a tecnologia funcionava conforme planejado, estávamos prontos para testá-la com as outras desenvolvidas para o evento de guerra de AQ.

Jogadores da Horda em Silithus

Experimentando as soluções

Depois de abordar os principais obstáculos tecnológicos e implementar diversas maneiras de otimizar o desempenho dos servidores, estava na hora de testar tudo em que trabalhamos. Criamos uma versão reduzida da guerra de 10 horas, ajustada para durar apenas uma.

Durante o primeiro teste de estresse, deixamos quase todos os jogadores na área para ver o que aconteceria. Em um certo ponto, chegamos a quase 150% da capacidade de um reino inteiro da versão 1.12. Foi aí que vimos nosso reino de teste travar. Sabíamos que o limite de pessoas que iríamos permitir na área era bem alto, e mesmo assim estávamos vendo números bem maiores. Investigamos o problema e notamos que o código que permitia que os jogadores entrassem ou saíssem de uma área era uma fila que não processava muitos jogadores ao mesmo tempo. Era por isso que jogadores não estavam sendo transferidos para fora e outros ficavam presos em rotas de voo por um tempo maior do que o normal. Restauramos o servidor e continuamos o teste de estresse, ajustando durante o processo. Reduzimos lentamente o número até um ponto em que ainda havia atrasos, mas tudo era razoavelmente jogável e mantínhamos um número de jogadores muito maior do que qualquer área já havia visto. O evento previsto para durar apenas uma hora e meia acabou sendo concluído em quatro horas por causa dos travamentos.

O segundo teste de estresse foi realizado uma semana depois. Isso permitiu ver se nossas otimizações funcionavam. Ao carregarmos o teste de estresse, notamos imediatamente as melhoras: os jogadores não ficavam mais presos nas rotas de voo para Silithus! Conseguimos obter dados suficientes que demonstravam quantos jogadores poderíamos ter no local confortavelmente. Após os dois testes, prosseguimos com os números que consideramos apropriados para o melhor equilíbrio entre gerenciar os atrasos e a estabilidade dos servidores. Com os testes, pudemos conferir se as otimizações funcionariam, e consideramos os dois um sucesso, já que conseguimos identificar limites de áreas e ajustá-los.

Espalhando as soluções de servidor por toda Azeroth

Originalmente, as otimizações estavam planejadas apenas para Silithus durante a Guerra das Areias. Quando determinamos que eram seguras para uso global, aplicamos as otimizações em todo o mundo na versão 1.13.5. Com o início do Esforço de Guerra, os jogadores começaram a entregar suprimentos e coletar cadáveres de insetos em massa. Vimos um aumento enorme de jogadores não apenas em Silithus, mas também nas capitais e nas áreas externas. As otimizações ajudaram a melhorar o desempenho dessas experiências, permitindo batalhas JxJ em larga escala por toda Azeroth. Alguns jogadores até chegaram a gerar o Chefe Mundial Trovejardus para ajudar a expulsar a outra facção de uma Colmeia.

Antes mesmo do evento de abertura do portão, alguns servidores exibiram problemas estranhos que faziam o Esforço de Guerra não progredir neles. Alguns servidores estavam concluindo seus Esforços de Guerra tão rápido que geravam uma condição de raça na lógica de cada entrega que podia impedir a inicialização da contagem de cinco dias. Como a chance desse caso raro acontecer era muito pequena, conseguimos corrigir esses servidores manualmente e depois resolver o problema para os reinos futuros que concluíssem seus Esforços.

Quando os Esforços de Guerra foram concluídos e cinco dias se passaram para a abertura dos portões, começamos a monitorar os reinos chineses, os primeiros a abrirem no mundo. O primeiro servidor na China com um Gongo ativo foi Ouro. Enquanto monitorávamos as populações das nossas camadas, vimos que a maioria dos jogadores de cada camada estava em Silithus. Iniciar o evento em diversas camadas na capacidade máxima, com vários milhares de jogadores ao mesmo tempo, era algo que nunca tínhamos feito. Embora houvesse um atraso visível, nossos servidores não sofreram nenhum travamento no primeiro conjunto de reinos abrindo na China.

Que soe o Gongo!

Em 4 de agosto, notamos que vários reinos da América do Norte estariam prontos para soar seus gongos assim que os servidores voltassem de uma reinicialização. Monitoramos ativamente esses reinos, um por um, em contas de Mestre de Jogo e através das nossas ferramentas de observação para observar e lidar com qualquer problema que pudesse aparecer. Cada reino abriu e iniciou o evento sem problemas. Portadores de Cetros receberam suas prestigiosas montarias Tanque de Batalha Qiraji Preto, jogadores lutaram contra insetos ainda maiores e ficamos satisfeitos com a estabilidade. Enquanto esperávamos que nosso primeiro servidor pós-reinicialização concluísse seu período de espera de cinco dias, notamos um problema considerável: os eventos não persistiam após a reinicialização. Ou seja, se um servidor travasse ou fosse reinicializado, perdíamos toda a progressão no evento. Embora esse problema existisse desde o início do desenvolvimento do WoW Classic, não havia muitas aplicações de persistência de eventos entre reinicializações de servidores. Nossa equipe conseguiu resolver o problema rapidamente, mas precisávamos garantir que nenhuma reinicialização posterior acontecesse até conseguirmos implementar uma correção e catalogar corretamente todos os status dos Esforços de Guerra no nosso banco de dados sem interromper o jogo.


Alguns podem alegar que permitir o travamento de servidores foi o que tornou a guerra de AQ original tão caótica e memorável. Em vez disso, nos empenhamos em cultivar o mesmo fervor criando uma experiência muito mais estável, que pudesse ser compartilhada com cerca de 1.500 jogadores em Silithus ao mesmo tempo em cada servidor. Queríamos que as memórias da guerra de AQ no Classic fossem ter o máximo possível de jogadores passando pelas 10 horas do evento sem interrupção. Embora alguns poucos reinos tenham travado, conseguimos colocá-los online de novo rapidamente. Esses reinos se recuperaram totalmente e voltaram a ficar online em minutos, e nenhum travamento ocorreu depois.

Mais de 4.000 jogadores de todo o mundo se tornaram Senhores dos Escaravelhos, e esse número continua a crescer com o avanço de cada servidor em seus Esforços de Guerra. Está sendo incrível acompanhar a empolgação e o envolvimento no WoW Classic desde que o Esforço de Guerra de AQ começou, e estamos muito agradecidos a todos que se juntaram a nós para a segunda Guerra das Areias Cambiantes!

Próximo artigo

Destaques