Um dos problemas críticos que surgem ao criar sistemas multiusuário é o dimensionamento. Existem várias soluções para esses problemas: sharding, modelo de serviço, sistema de componentes de entidade. Hoje vamos considerar todas as opções e também discutir um caso prático para resolver o problema. Inscreva-se agora!
Parte 1Parte 2Eu passo a palavra aos autores.Abordagens tradicionais para a construção de sistemas multiusuário. Arquitetura de serviço
Historicamente, o primeiro método para resolver o problema de dimensionamento foi o sharding - dividindo todo o sistema em vários servidores por qualquer critério, sem um estado geral do mundo. Ou seja, até um certo número de usuários, eles podem estar no mesmo servidor, ver um ao outro e interagir um com o outro; mas, ao adicionar novos, eles acabaram em cópias do espaço virtual em execução em outro servidor e, portanto, não puderam interagir com outros. É claro que isso não é uma solução para o problema, é uma solução alternativa. E embora o sharding faça sentido mesmo agora, em muitos casos são necessárias abordagens que possam realmente aumentar a carga possível no servidor.
A segunda técnica comum é o modelo de serviço. O servidor possui vários componentes que podem ser facilmente duplicados. Por exemplo, este é um banco de dados e trabalha com ele, ou um servidor de ativos que os envia para um cliente ou um servidor de autorização. Todos esses serviços são diferenciados pelo fato de que você pode tê-los em várias instâncias e paralelizar solicitações para eles.
O principal problema é o estado compartilhado
Mas o principal problema é diferente. O que fazer com um estado específico do mundo, o estado do espaço virtual? Suponha que nosso “mundo” consista em uma cena 3D, um conjunto de objetos e vários usuários conectados. Teoricamente, podemos duplicar alguns componentes de software responsáveis por trabalhar com a cena no lado do servidor. Mas o problema é que o estado da cena é uma coisa comum a todos esses componentes. Assim, ao paralelizar os manipuladores, precisamos resolver de alguma forma o problema de sincronizar o trabalho com os dados e, ao mesmo tempo, na própria sincronização, podemos perder mais desempenho do que vencer no paralelismo.
Solução: Sistema Entidade-Componente. Problemas no caso do Extremo Oriente
Uma das abordagens relativamente recentes para esses problemas é o ECS (Entity - Component System). Nesta versão, representamos o objeto do sistema como uma determinada entidade que possui algumas propriedades. Por exemplo, essa pode ser a posição de um objeto no espaço e sua velocidade. Além disso, tudo o que armazenamos no próprio objeto são apenas alguns dados, mas não a lógica de trabalhar com eles. Ou seja, no nosso caso, seis números serão simplesmente atribuídos ao objeto - o vetor de coordenadas e o vetor de velocidade.
A segunda parte do ECS é worker, um sistema que trabalha com um tipo específico de componente. Por exemplo, no nosso caso, pode ser um sistema que altera as coordenadas de um objeto a cada segundo, adicionando velocidade a elas. A idéia principal é que o trabalhador não sabe nada sobre o objeto em si - apenas possui uma fila, um pipeline de componentes que deve processar de acordo com certas regras. Por conseguinte, podemos paralelizar trabalhadores, bem como serviços paralelizados.
Sistemas de agente como método de escrever código paralelo
A abordagem multiagente também não é uma novidade especial, mas recentemente o interesse por sistemas de agentes vem crescendo. Existem vários artigos razoavelmente bons que falam sobre isso em detalhes; portanto, listamos brevemente apenas os princípios mais gerais de tais sistemas:
- O componente principal do sistema é um componente chamado agente ou ator. De certa forma, assemelha-se a um objeto familiar a todos, mas o ator não possui métodos públicos, a única maneira de se comunicar com ele é enviar uma mensagem;
- Para enviar uma mensagem ao agente, existe o conceito de "links". O link fornece uma certa interface (em várias implementações, pode parecer muito diferente), o que permite enviar mensagens. Uma das propriedades importantes aqui é a transparência da localização e a presença de cada agente com um endereço - uma sequência que permite que você obtenha um link para o agente, independentemente de sua localização física, ou seja, o agente pode estar localizado e trabalhar no sistema do agente no mesmo computador ou talvez em outro - nesse caso, o link é obtido em algum endereço de rede;
- O agente tem uma fila de mensagens e eles são processados sequencialmente. Um agente pode ser uma máquina de estados que altera estados e manipuladores de mensagens na ordem de reação a eles;
- Como regra, os sistemas multiagentes são hierárquicos, ou seja, os agentes formam um tipo de árvore. Nesse caso, um erro em um dos agentes não para o sistema inteiro, apenas um agente específico é desconectado, enviando uma mensagem de erro ao seu ancestral. Uma das abordagens populares para lidar com esses erros é deixá-lo travar - quando um agente falha, simplesmente criamos uma nova cópia dele;
- Criar um novo agente não é uma operação que consome muitos recursos, e criar o próprio sistema é muito caro.
Muitas vezes, os sistemas de agentes são usados apenas na abordagem usando o ECS. Como o sistema do agente facilita a criação do número necessário de trabalhadores e o paralelismo do trabalho, simplesmente distribuindo o fluxo de mensagens entre eles, isso parece uma abordagem muito promissora. Por exemplo, é assim que o SpatialOS da Improvable funciona.
Os problemas surgem aqui em um plano ligeiramente diferente. A abordagem do ECS é bastante simples, mas, em princípio, não pode ser chamada de intuitiva, especialmente para programadores inexperientes. Portanto, a criação do código do usuário nesse sistema é uma tarefa não trivial. Além disso, surgem dúvidas sobre a portabilidade de vários objetos entre instâncias do servidor virtual, porque, juntamente com o objeto, devemos transferir todos os trabalhadores se eles (para esse tipo de componente) não estiverem presentes em outro servidor. Em princípio, algumas implementações de sistemas de agentes podem resolver alguns desses problemas, mas escolhemos uma abordagem diferente.
Nosso caso é a essência do Extremo Oriente como agente
No nosso caso, cada objeto de espaço virtual é um agente, ou melhor, um sistema de agentes. Comparando com o ECS clássico, podemos dizer que cada entidade em nós carrega um sistema de "trabalhadores trabalhadores", vinculado ao próprio objeto. Ao mesmo tempo, todas as vantagens do sistema do agente são preservadas (ou seja, podemos executar esse objeto em um encadeamento separado, em uma máquina separada etc., simplesmente alterando as configurações do servidor), mas o objeto permanece portátil e a criação de scripts para ele não requer divisão ECS .
Nesse caso, o estado do mundo é dividido no estado de objetos individuais e cada um deles pode ser processado separadamente. No cliente, também construímos um sistema de agente, que é um tipo de reflexo do status do servidor, e associamos cada agente ao agente. Entre outras coisas, isso também aumenta a confiabilidade do sistema, pois se um objeto individual falhar, apenas esse objeto será desativado e não todo o espaço virtual.
Em um pouco mais detalhadamente, fica assim:

Qualquer objeto de espaço é um pequeno sistema de agente que consiste no agente principal da entidade criada quando o servidor é iniciado, que não é um agente de contêiner de componente e um conjunto de componentes do manipulador de mensagens. Para conectar o cliente, a propriedade de transparência da rede é usada, ou seja, cada objeto específico no cliente possui um link para o objeto do agente do servidor. Ao mesmo tempo, ao conectar, um novo agente é criado dinamicamente, que é um descendente do principal.

Um sistema de agente também é criado no lado do cliente, mas os agentes da entidade são formados por uma mensagem do lado do servidor. Após a criação, o agente recebe um link para o agente do servidor e cria um componente de processamento de mensagens que inclui filas para receber e enviar mensagens do servidor. Um objeto do Unity também é criado e partes do cliente dos componentes do objeto herdadas do MonoBehaviour. Ao mesmo tempo, a parte do Unity e a parte do agente trabalham em diferentes segmentos, o manipulador de mensagens é responsável pela sincronização (se possível, é minimizado).
Algo assim (sem detalhes especiais) se parece com a implementação de espaço virtual dinâmico na variante JIF. No próximo artigo, falaremos sobre big data pessoal e trabalharemos com estatísticas, bem como sobre blockchain.
Os autores
A Jedium é uma empresa parceira da Microsoft que trabalha no campo da realidade virtual aumentada e da inteligência artificial. A Jedium desenvolveu uma estrutura para simplificar o desenvolvimento de projetos complexos no Unity, parte dos quais está disponível publicamente
no GitHub . A Jedium planeja reabastecer o repositório com novos módulos de estrutura, bem como soluções de integração com o Microsoft Azure.
Vitaliy Chashchin - Desenvolvedor de software com mais de 10 anos de experiência no design e implementação de aplicativos cliente-servidor tridimensionais - do conceito à completa implementação e integração de aplicativos e soluções no campo da realidade virtual. Arquiteto de Sistemas Jedium LLC, MSc em TI.
Alexey SarafanovGerente de Marketing na Jedium LLC.
Sergey KudryavtsevCEO e fundador da Jedium LLC.