谁来锁
由Service来锁还是有domain的内部方法来锁,或可以通过拦截器读取url上的id来锁。
URL
这种方案看上去最简单也最可靠,但是不够灵活。特别是一个操作会影响多个业务对象(如果只是通知也许简单点)。并且所谓的业务逻辑往往是这些关联性,而不仅仅是按照前端数据来update
DOMAIN
这种做法的问题是没法批量锁,无法保证事务。既不能满足多个不同domain之间的大锁,也不能进行多个同类domain的批量操作。特别是还有些极端情况连锁哪些domain是哪些都不知道。如果先查询domain再来锁,这时之前查询的domain信息已经过期了。
另一个方案就是使用懒加载,只有执行write方法时才加锁重新获取。但这样带来的问题是不能由domain的调用方来get数据来做判断
Service
这样看来锁的问题和持久由谁来做很像。如果基于一个简单的分配,domain是由产品经理来写,那么锁应该由Service来完成。
多人锁
有时一个service调用了另一个service时会导致第二个service加锁失败
如果不加锁又无法保证事务的一致性
这时考虑第一个service把锁传递给第二个
回调
如果一个锁涉及到两类微服务,为防止并发而使用锁,但是这个时候又发生了回调?
最好的当然是要从业务上梳理好不应出现这种情况,那么从技术上要求涉及到多个微服务时必须释放锁
逻辑锁
另一种不使用zookeeper之类来加锁的方案是通过业务状态来处理,例如当需要变成XX状态时先变成XX_pending的状态,等到其他条件都处理完了再变成XX状态,这个时候如果出现了并发操作,那么遇到pending的状态就需要等待或失败,否则就会出现脏读,另一方面有些方法是期望状态为XX_pending的,这些方法是专门处理pending的。这样一个业务操作可能会涉及到两类方法,一类方法把一个非pending的状态置为pending。另一种方法用来置为非pending(可能是回滚)。
这样如果发生了回调,那么回调的时候必然要求状态为pending(或兼容pending的情况)从而突破了锁
锁的细粒度
一般来说,锁的细粒度和aggregate保持一致,越小并发也就越好。