azure 最佳实践 3--最小协同操作

来源:互联网 发布:海淘族信用数据脸谱 编辑:程序博客网 时间:2024/06/08 17:16
最小化协同操作
最小化应用服务之间的协同,提高可扩展性。
大多数云应用程序包含多个服务 - Web前端,数据库,业务,报表以及高级分析等等。为了可扩展性和可靠性,这些服务应该在多个实例上运行。
当两个实例尝试执行影响某些共享状态的并发操作时会发生什么?在某些情况下,例如,为了保持ACID原则就必须在节点之间进行协同操作。在下图中,节点2正在等待节点1释放数据库锁:




协同限制了水平扩展并制造了瓶颈。在此示例中,当你为应用程序添加更多实例时,你会发现锁竞争增加了。最坏情况,前端实例将花费大部分时间等待锁。“只执行一次”也会造成频繁的协同操作。例如,一个订单必须只被处理一次。两个worker同时监听新订单。worker1拿到要处理的订单。应用程序必须确保Worker2不会重复执行处理订单的工作,并且,如果Worker1崩溃,订单不会被删除。



您可以使用像Scheduler Agent  Supervisor这样的模式来完成worker之间的协调工作,而对于这个处理订单的例子来说,更好的做法是进行分工。每个worker被分配处理一定范围内的订单(比如,按计费区域进行划分)。如果一个worker崩溃,一个新的实例将在前一个实例停止的位置上被启用,但是多个实例之间没有竞争。


推荐的做法


接受最终一致性(而非强一致)。数据被分发时,需要协同才能保证强一致性。例如,某操作同时更新两个数据库。只要系统可以保证最终的一致性即可,可以通过使用补偿事务模式,来进行发生错误时的回滚操作。并不必把它放在一个transaction scope中。


使用领域事件来完成状态同步。领域事件是领域相关的记录。对这些事件感兴趣的服务可以订阅事件,而不是使用全局事务来协调多个服务。如果使用这种方法,系统必须接受最终的一致性(见上一条)。


考虑使用CQRS和event sourcing模式。这两种模式可以帮助减少读写操作的资源竞争。
CQRS模式实现了读写分离。在一些实现中,实现了物理上的读写分离。
在event sourcing模式中,状态的变更会先被记录到数据存储(只能在尾部添加)中。事件的添加是一个原子操作,做到了锁需要的最少化。
这两种模式是相辅相成的。如果CQRS中只写的数据存储中的写操作使用event sroucing,则只读的数据存储则可以监听相同的事件,创建当前状态的可读快照,为查询进行优化。然而,在采用CQRS或event sroucing之前,一定要了解其中的利弊。有关更多信息,请参阅CQRS架构。


数据分区。避免多个应用程序共享同一数据源。微服务架构通过对每个服务中数据源的隔离,实现了这一原则。在单个数据库中,将数据分区可以提高并发性,因为可以并发写入多个分区。


幂等操作设计。如有可能,保证操作是幂等的。这样就可以使用“至少一次”模型来处理。例如,你可以将工作项放在队列中。如果一个worker在操作过程中崩溃,另一个worker继续执行。




使用异步并行处理。如果操作需要异步的执行多个步骤(如远程服务调用),则可以并行调用它们,然后对结果进行聚合。这种做法假设了每个步骤不存在执行顺序的依赖。


尽可能使用乐观并发控制。悲观并发控制使用数据库锁来防止冲突。这会导致性能下降并降低可用性。使用乐观并发控制,每个事务都会修改数据的副本或快照。当事务提交时,由数据库引擎进行事务验证,并选择拒绝任何会影响数据库一致性的事务。
Azure SQL数据库和SQL Server使用快照隔离来支持乐观并发。一些Azure存储服务通过使用Etags支持乐观并发,参照DocumentDB API和Azure存储。


考虑使用MapReduce或其他并行分布式算法。根据数据以及操作类型,可以将工作分解为多个独立任务,由可并行工作的多个节点来执行。请参阅大型计算架构风格.


用领导选举进行协同。在需要协同操作时,请确保协调器在应用程序中不会成为单点故障。可考虑使用领导者选举模式,某个实例被选为领导者,并且承担协同工作。如果领导人失败了,选一个新的实例当选为领导者。
原创粉丝点击