Cloud Design Pattern - CQRS Pattern (读写隔离模式)

1.前言

上一篇我们讨论了云计算设计模式之服务聚合,这一篇我们来讨论下云计算设计模式之读写分离模式.在传统的应用中我们通过DBContext操作数据库都是在同一个Repository中对数据执行CRUD操作.我们都知道,数据库读写操作的I/O效率有较大差异的.发送到数据库的读写请求,会因为某些耗时的写入操作影响读取数据操作的效率,从而降低了系统吞吐量.另外,从安全的角度来说,读写采用同一个接口,也不利于我们通过权限控制数据读写操作,一旦用户非法拥有调用数据读写接口的权限,可以造成很大的破坏,而如果做了使用了读写分离模式,这种概率就减少一半.

2.读写分离

在数据库高可用方案的发展过程中,首先是手动地做数据库备份,后来是数据库镜像,主数据库挂了,镜像数据库会立即代替主数据库提供服务,最终发展成SqlAlwaysOn.SqlAlwaysOn就是做了读写分离的.这是SQL Server数据库提供的读写分离设计.

从软件架构的角度来说,设计不同的接口来完成数据读取和数据更新操作,更加方便扩展,容易满足业务快速发展的需求.传统的应用中,我们使用DTO来存放临时数据,如果考虑并发的话,很可能会出现数据不一致的情形,即对DTO的修改还没反映到数据库,另一个线程就从数据库里面读取数据,这时候读取的数据已经是脏数据了.

读写隔离的模式就是要使用隔离的接口来操作数据,下图展示了这种设计思想.

这时候在数据库中我们读取和操作的是同一个数据库,如果数据没有锁机制,那么还是可能发生脏读,如果有锁机制,那么还是会发生阻塞.如果从不同的数据源来读写就不会有这种问题了,那么数据源之间就必须有同步机制了.如下图所示

3.Example

1)读模型

// Query interface
namespace ReadModel
{
  public interface ProductsDao
  {
    ProductDisplay FindById(int productId);
    IEnumerable<ProductDisplay> FindByName(string name);
    IEnumerable<ProductInventory> FindOutOfStockProducts();
    IEnumerable<ProductDisplay> FindRelatedProducts(int productId);
  }

  public class ProductDisplay
  {
    public int ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal UnitPrice { get; set; }
    public bool IsOutOfStock { get; set; }
    public double UserRating { get; set; }
  }

  public class ProductInventory
  {
    public int ID { get; set; }
    public string Name { get; set; }
    public int CurrentStock { get; set; }
  }
}
为了接下来定义更新操作,先定义Commond相关接口及实现接口的类.

public interface Icommand
{
  Guid Id { get; }
}

public class RateProduct : Icommand
{
  public RateProduct()
  {
    this.Id = Guid.NewGuid();
  }
  public Guid Id { get; set; }
  public int ProductId { get; set; }
  public int rating { get; set; }
  public int UserId {get; set; }
}
系统使用一个Handler类来执行应用提交的更新请求,根据以往我们了解到的云计算的设计经验,我们会把请求放入消息队列,然后使用消费者进行逐一处理.示例如下:

public class ProductsCommandHandler : 
    ICommandHandler<AddNewProduct>,
    ICommandHandler<RateProduct>,
    ICommandHandler<AddToInventory>,
    ICommandHandler<ConfirmItemShipped>,
    ICommandHandler<UpdateStockFromInventoryRecount>    
{
  private readonly IRepository<Product> repository;

  public ProductsCommandHandler (IRepository<Product> repository)
  {
    this.repository = repository;
  }

  void Handle (AddNewProduct command)
  {
    ...
  }

  void Handle (RateProduct command)
  {
    var product = repository.Find(command.ProductId);
    if (product != null)
    {
      product.RateProuct(command.UserId, command.rating);
      repository.Save(product);
    }
  }

  void Handle (AddToInventory command)
  {
    ...
  }

  void Handle (ConfirmItemsShipped command)
  {
    ...
  }

  void Handle (UpdateStockFromInventoryRecount command)
  {
    ...
  }
}
那么在业务逻辑层,我们如何设计接口,请参考如下范例:

public interface ProductsDomain
{
  void AddNewProduct(int id, string name, string description, decimal price);
  void RateProduct(int userId int rating);
  void AddToInventory(int productId, int quantity);
  void ConfirmItemsShipped(int productId, int quantity);
  void UpdateStockFromInventoryRecount(int productId, int updatedQuantity);
}
4.相关阅读

The following patterns and guidance may also be relevant when implementing this pattern:

Data Consistency Primer. This guidance explains the issues that are typically encountered due to eventual consistency between the read and write data stores when using the CQRS pattern, and how these issues can be resolved.

Data Partitioning Guidance. This guidance describes how the read and write data stores used in the CQRS pattern can be divided into separate partitions that can be managed and accessed separately to improve scalability, reduce contention, and optimize performance.

Event Sourcing Pattern. This pattern describes in more detail how Event Sourcing can be used with the CQRS pattern to simplify tasks in complex domains; improve performance, scalability, and responsiveness; provide consistency for transactional data; and maintain full audit trails and history that may enable compensating actions.

Materialized View Pattern. The read model of a CQRS implementation may contain materialized views of the write model data, or the read model may be used to generate materialized views.







Cloud applications have a unique set of characteristics. They run on commodity hardware, provide services to untrusted users, and deal with unpredictable workloads. These factors impose a range of problems that you, as a designer or developer, need to resolve. Your applications must be resilient so that they can recover from failures, secure to protect services from malicious attacks, and elastic in order to respond to an ever changing workload. This guide demonstrates design patterns that can help you to solve the problems you might encounter in many different areas of cloud application development. Each pattern discusses design considerations, and explains how you can implement it using the features of Windows Azure. The patterns are grouped into categories: availability, data management, design and implementation, messaging, performance and scalability, resilience, management and monitoring, and security. You will also see more general guidance related to these areas of concern. It explains key concepts such as data consistency and asynchronous messaging. In addition, there is useful guidance and explanation of the key considerations for designing features such as data partitioning, telemetry, and hosting in multiple datacenters. These patterns and guidance can help you to improve the quality of applications and services you create, and make the development process more efficient. Enjoy! Table of Contents Part 1. Preface Part 2. PATTERNS Chapter 1. Cache-Aside Pattern Chapter 2. Circuit Breaker Pattern Chapter 3. Compensating Transaction Pattern Chapter 4. Competing Consumers Pattern Chapter 5. Compute Resource Consolidation Pattern Chapter 6. Command and Query Responsibility Segregation (CQRS) Pattern Chapter 7. Event Sourcing Pattern Chapter 8. External Confguration Store Pattern Chapter 9. Federated Identity Pattern Chapter 10. Gatekeeper Pattern Chapter 11. Health Endpoint Monitoring Pattern Chapter 12. Index Table Pattern Chapter 13. Leader Election Pattern
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值