Estilo de arquitetura CQRSCQRS architecture style

Segregação das Responsabilidades de Comando e Consulta (CQRS) é um estilo de arquitetura que separa as operações de leitura das operações de escrita.Command and Query Responsibility Segregation (CQRS) is an architecture style that separates read operations from write operations.

Diagrama lógico de um estilo de arquitetura CQRS

Nas arquiteturas tradicionais, o mesmo modelo de dados é utilizado para consultar e atualizar uma base de dados.In traditional architectures, the same data model is used to query and update a database. É simples e funciona bem para operações CRUD básicas.That's simple and works well for basic CRUD operations. Nas aplicações mais complexas, no entanto, esta abordagem pode tornar-se difícil.In more complex applications, however, this approach can become unwieldy. Por exemplo, no lado de leitura, a aplicação pode efetuar várias consultas diferentes, devolvendo objetos de transferência de dados (DTOs) com formas diferentes.For example, on the read side, the application may perform many different queries, returning data transfer objects (DTOs) with different shapes. O mapeamento de objetos pode tornar-se complicado.Object mapping can become complicated. No lado de escrita, o modelo pode implementar validação complexa e lógica de negócio.On the write side, the model may implement complex validation and business logic. Como resultado, pode acabar por ficar com um modelo demasiado complexo, que faz demasiado.As a result, you can end up with an overly complex model that does too much.

Outro potencial problema é que as cargas de trabalho de leitura e escrita são frequentemente assimétricas, com requisitos de desempenho e dimensionamento muito diferentes.Another potential problem is that read and write workloads are often asymmetrical, with very different performance and scale requirements.

O CQRS aborda estes problemas, separando as leituras e escritas em modelos separados, utilizando comandos para atualizar os dados e consultas ler os dados.CQRS addresses these problems by separating reads and writes into separate models, using commands to update data, and queries to read data.

  • Os comandos devem ser baseados em tarefas, em vez de se se centrarem nos dados.Commands should be task based, rather than data centric. (“Reservar quarto de hotel”, e não “definir o Estado de Reserva para Reservado”.) Os comandos podem ser colocados numa fila para processamento assíncrono, em vez de serem processados de modo síncrona.("Book hotel room," not "set ReservationStatus to Reserved.") Commands may be placed on a queue for asynchronous processing, rather than being processed synchronously.

  • As consultas nunca modificam a base de dados.Queries never modify the database. Uma consulta devolve um DTO que não encapsula qualquer conhecimento de domínio.A query returns a DTO that does not encapsulate any domain knowledge.

Para maior isolamento, pode separar fisicamente os dados de leitura dos dados de escrita.For greater isolation, you can physically separate the read data from the write data. Nesse caso, a base de dados de leitura pode utilizar o seu próprio esquema de dados que está otimizado para consultas.In that case, the read database can use its own data schema that is optimized for queries. Por exemplo, pode armazenar uma vista materializada dos dados, para evitar associações complexas ou mapeamentos de O/RM complexos.For example, it can store a materialized view of the data, in order to avoid complex joins or complex O/RM mappings. Poderá até utilizar um tipo diferente do arquivo de dados.It might even use a different type of data store. Por exemplo, a base de dados de escrita pode ser relacional, enquanto a base de dados de leitura é uma base de dados de documentos.For example, the write database might be relational, while the read database is a document database.

Se forem utilizadas bases de dados de leitura e escrita separadas, têm de ser mantidas sincronizadas. Normalmente isso é conseguido fazendo com que o modelo de escrita publique um evento sempre que atualiza a base de dados.If separate read and write databases are used, they must be kept in sync. Typically this is accomplished by having the write model publish an event whenever it updates the database. Atualizar a base de dados e publicar o evento tem de ocorrer numa única transação.Updating the database and publishing the event must occur in a single transaction.

Algumas implementações de CQRS utilizam o Padrão de Aprovisionamento de Eventos.Some implementations of CQRS use the Event Sourcing pattern. Com este padrão, o estado da aplicação é armazenado como uma sequência de eventos.With this pattern, application state is stored as a sequence of events. Cada evento representa um conjunto de alterações aos dados.Each event represents a set of changes to the data. O estado atual é construído ao reproduzir os eventos.The current state is constructed by replaying the events. Num contexto CQRS, uma vantagem do Aprovisionamento de Eventos é que os mesmos eventos podem ser utilizados para notificar os outros componentes — em particular, para notificar o modelo de leitura.In a CQRS context, one benefit of Event Sourcing is that the same events can be used to notify other components — in particular, to notify the read model. O modelo de leitura utiliza os eventos para criar um instantâneo do estado atual, o que é mais eficiente para consultas.The read model uses the events to create a snapshot of the current state, which is more efficient for queries. No entanto, o Aprovisionamento de Eventos adiciona complexidade à estrutura.However, Event Sourcing adds complexity to the design.

Eventos CQRS

Quando utilizar esta arquiteturaWhen to use this architecture

Considere o CQRS para domínios de colaboração em que muitos utilizadores acedem aos mesmos dados, especialmente quando as cargas de trabalho de leitura e escrita são assimétricas.Consider CQRS for collaborative domains where many users access the same data, especially when the read and write workloads are asymmetrical.

O CQRS não é uma arquitetura de nível superior que se aplica a um sistema completo.CQRS is not a top-level architecture that applies to an entire system. Aplique o CQRS apenas aos subsistemas em que não existe um valor evidente na separação de leituras e escritas.Apply CQRS only to those subsystems where there is clear value in separating reads and writes. Caso contrário, estará a criar complexidade adicional sem nenhuma vantagem.Otherwise, you are creating additional complexity for no benefit.

BenefíciosBenefits

  • Dimensionamento de forma independente.Independently scaling. O CQRS permite que as cargas de trabalho de leitura e escrita sejam dimensionadas de forma independente, e poderá resultar em menos contenções de bloqueio.CQRS allows the read and write workloads to scale independently, and may result in fewer lock contentions.
  • Esquemas de dados otimizados.Optimized data schemas. O lado de leitura pode utilizar um esquema que está otimizado para consultas, enquanto o lado de escrita utiliza um esquema que está otimizado para atualizações.The read side can use a schema that is optimized for queries, while the write side uses a schema that is optimized for updates.
  • Segurança.Security. É mais fácil garantir que apenas as entidades de domínio corretas estão a efetuar operações de escrita nos dados.It's easier to ensure that only the right domain entities are performing writes on the data.
  • Separação das preocupações.Separation of concerns. A separação dos lados de leitura e escrita pode resultar na criação de modelos que são mais flexíveis e sustentáveis.Segregating the read and write sides can result in models that are more maintainable and flexible. A maioria da lógica de negócio complexa vai para no modelo de escrita.Most of the complex business logic goes into the write model. O modelo de leitura pode ser relativamente simples.The read model can be relatively simple.
  • Consultas mais simples.Simpler queries. Ao armazenar uma vista materializada na base de dados de leitura, a aplicação pode evitar associações complexas durante as consultas.By storing a materialized view in the read database, the application can avoid complex joins when querying.

DesafiosChallenges

  • Complexidade.Complexity. A ideia básica do CQRS é simples.The basic idea of CQRS is simple. Mas pode levar a uma estrutura de aplicação mais complexa, especialmente se incluir o padrão de Aprovisionamento de Eventos.But it can lead to a more complex application design, especially if they include the Event Sourcing pattern.

  • Mensagens.Messaging. Embora o CQRS não requeira mensagens, é comum utilizar mensagens para processar comandos e publicar eventos de atualização.Although CQRS does not require messaging, it's common to use messaging to process commands and publish update events. Nesse caso, a aplicação deve processar falhas de mensagens ou mensagens duplicadas.In that case, the application must handle message failures or duplicate messages.

  • Consistência eventual.Eventual consistency. Se separar as bases de dados de leitura e escrita, os dados de leitura poderão ficar obsoletos.If you separate the read and write databases, the read data may be stale.

Melhores práticasBest practices

CQRS em microsserviçosCQRS in microservices

O CQRS pode ser especialmente útil numa arquitetura de microsserviços.CQRS can be especially useful in a microservices architecture. Um dos princípios dos microsserviços é que um serviço não consegue aceder diretamente ao arquivo de dados de outro serviço.One of the principles of microservices is that a service cannot directly access another service's data store.

Diagrama de uma abordagem incorreta para os microsserviços

No diagrama seguinte, o serviço A escreve num arquivo de dados, e o Serviço B mantém uma vista materializada dos dados.In the following diagram, Service A writes to a data store, and Service B keeps a materialized view of the data. O serviço A publica um evento sempre que escreve no arquivo de dados.Service A publishes an event whenever it writes to the data store. O Serviço B subscreve o evento.Service B subscribes to the event.

Diagrama de uma abordagem correto para os microsserviços