架构误区系列 20:不当的聚合
本期架构误区系列说一个服务设计粒度的问题。一些初级的架构师往往对于服务粒度的控制比较困惑,究其原因很多时候是在于对领域边界和接口分层理解上的不足。本期通过一个实例的剖析来阐述一下这个粒度的选择问题。
场景描述
本期的场景是在收银台页面有一个用户当前交易订单查询的功能。同时,为了满足不同用户的不同诉求,我么在后台会维护一个用户的个性化偏好设置,控制交易的执行是由用户人工触发还是系统根据规则自动触发。两种不同的触发方式,在订单列表上显示的操作会有区别(显示的按钮数量不同)。
初始的设计
开发同学为了满足这个用户个性化操作的诉求,对订单查询服务进行了扩展,加入了一个扩展字段,里面会返回前端用户订单操作的偏好,例如:
问题的剖析
这个设计大致存在 4 个问题:
订单查询和用户偏好查询两者的查询频率其实是不同的。订单在每次渲染收银台订单管理页面的时候都会查询,偏好查询其实应该是 by session 的,用户登录查询一次就可以了。如果两者聚合在一起,人为的增加了偏好查询服务的 QPS。
订单服务和用户偏好服务其实理论上属于两个领域的范畴。目前由于业务还处于比较初期的阶段,用户量还不大,所以这两个领域还由同一个应用承载。未来如果进行了应用拆分,会存在订单查询服务中包装用户偏好查询服务的情况,这个属于高等级服务依赖低等级服务。
一个订单查询服务,里面硬塞了一个扩展字段。这个里面的 key-value 也无法做严格的控制,返回前端是否有遗漏无法做严格的校验。
订单查询服务相对是稳定的,用户偏好相对来说变更的可能性比较大。后续每增加一个偏好,可能就需要对订单查询服务做一次变更。一般来说,订单查询功能回归的场景多,偏好查询相对需要回归的点有限。两者聚合在一起,偏好的变更有大量的回归工作。
这些问题,究其根本原因,就是没有弄清楚两类查询服务的业务领域归属,将两类差异很大的服务强行聚合在一起,导致在开发、测试、运维和隔离上出现了各种的问题。
合理的设计
合理的架构设计,原则也很简单:不同的业务领域单独设计服务。
所以,应该存在两个互相独立的服务:
订单查询,返回订单列表。
用户偏好查询,根据场景返回特定的偏好列表。
同时,对于偏好查询服务,属于典型的读多写少的服务,可以通过引入缓存提升查询效率和稳定性。
在本场景下,前端应该在用户登录阶段调用用户偏好查询服务;在渲染收银单阶段,调用订单查询服务,并结合前面在浏览器端缓存的偏好信息,渲染订单列表和按钮。
即使前端口有设计上限制,不想在浏览器缓存偏好,需要在查询订单列表的时候同时返回偏好,那也应该在 Baas 层,对两个服务做聚合:前端一次请求,Baas 层调用后端两个服务,聚合返回。
总结
我们在设计服务的时候,对于服务粒度的选择,可以考虑如下原则:
不同领域边界的,必须设计成独立的服务。
服务运维级别不同的,尽量拆分成独立的服务。
读写比例差异较大的,可以考虑拆分。
后续功能迭代频率不同的,可以考虑拆分。
版权声明: 本文为 InfoQ 作者【agnostic】的原创文章。
原文链接:【http://xie.infoq.cn/article/6fe85bd5a30d687865d83a744】。文章转载请联系作者。
评论