在业务开发的过程当中,每每存在平台代码和业务代码耦合严重难以分离、业务和业务之间代码交织缺乏拆解的现象。平台和业务代码交织致使不易修改,不一样业务的代码交织增长了不一样负责团队之间的协同成本。所以不论从代码质量,仍是从团队协做的角度来看都严重地影响了开发团队之间的协同效率和开发效率,最终影响到了用户体验和业务发展。在闲鱼,商品发布和编辑功能也是如此。本文将以闲鱼商品发布和编辑功能的改造为例,向你们展现闲鱼是如何解决此类问题,从而更有效地协同更多团队更快更稳定地支撑各类业务的。html
为了实现上述目标,针对发布和编辑功能,进行了两轮升级。第一轮的目标在于“平台和业务分离、业务和业务隔离”;而第二轮将更进一步,目标在于“系统之间的解耦合,提高团队协同效率”。缓存
第一轮改造中,闲鱼将原先的商品发布和编辑功能从老应用中抽取到了新应用item。为了实现“平台和业务分离、业务和业务隔离”的目标,闲鱼自研了一套技术框架SWAK,具体请参考文章《业务代码解构利器--SWAK》,该文介绍了其设计思想和实现原理。接入SWAK框架后,平台逻辑和业务逻辑获得了分离,各个业务(如租房业务、免费送业务)之间的逻辑也再也不耦合,而是变成package隔离(固然也是能够作成jar包隔离)。安全
看一看改造后的应用状况示意图:
微信
根据这样的开发方式,咱们能够把开发同窗分红以下的两种角色:网络
如在以前的《业务代码解构利器--SWAK》一文中指出的同样,通过SWAK改造后,得到了以下的几个优势:框架
- 代码逻辑清晰,可变和不可变一目了然。
以租房为例——租房业务的同窗须要在item应用中维护一套租房发布编辑相关的逻辑(如校验地小区数据、地铁数据真实性等);租房业务的同窗还须要在详情应用的逻辑中维护一套和租房详情相关的逻辑(如展现地图,展现内部设施标签);租房业务的同窗还须要在交易应用的逻辑中维护一套和租房交易相关的逻辑(如预定看房)等等。租房的同窗不只仅须要着手于本身的代码逻辑,还须要修改发布和编辑应用item、还须要修改详情应用,还须要修改交易应用......这种体验是很是糟糕的,有极大的可能性接手一个简单业务就须要修改和发布四五个应用。异步
另外一方面,从主干开发人员的角度来讲,其应用不只仅由本身或本身的小团队来维护,还有不少业务开发人员也在修改和发布此应用,且频率会远远超过主干开发任务的发布和部署频次(不然就是主干扩展点逻辑抽取得很差了)。这不利于整个应用的稳定性。A业务服务挂了,应该只影响A业务,而不该该影响主干。依此逻辑,最好能作到JVM隔离。本质上来讲,第一轮改造完成了业务之间的解耦合,而第二轮则是系统之间的解耦合。性能
康威定律告诉咱们:测试
Any organization that designs a system (defined more broadly here than just information systems) will inevitably produce a design whose structure is a copy of the organization's communication structure.阿里云
简而言之就是人员组织结构和系统结构之间的一致性。而完成系统之间的解耦合又偏偏是符合康威定律的。这一轮的改造,咱们称之为“业务服务化”。
经过这种方式,咱们将主干应用和各业务应用完全分离了。仍然以租房业务为例,租房团队负责开发和维护租房业务的独立应用rent。租房个性化的发布和编辑需求只须要开发和部署rent应用,而没必要修改主干应用。主干应用只由主干团队的同窗负责维护,不会被其余业务团队的同窗所开发和部署,稳定性更加能得以保障。各业务系统独立开发、独立部署。这些都大幅地减小了没必要要的沟通成本、提高协同效率。
主干应用和业务应用是经过薄薄的一层接口所联系起来的,这层薄薄的接口都是“声明”:Interface定义、DO的定义和扩展点的默认Reduce策略定义。
在以前的《业务代码解构利器--SWAK》一文中指出了,SWAK框架在应用启动的时候会经过各类注册器(registery)注册框架所需的信息。其中最重要的信息就是——业务tag及其对应的SWAK接口的实现类类名或者类实例instance。大多RPC框架都会在client端提供一个代理,代理掉内部的服务发现、保活、序列化、网络通讯、反序列化等一系列操做。实际上,SWAK为了支持远程服务调用,只须要将业务tag,以及这些RPC的client的instance的对应关系注册进去就能够了。在闲鱼,RPC使用的是阿里通用的HSF框架(其相似的一个开源框架是Dubbo),这里的RPC的client就是HSF中的ConsumerBean。
上文还提到了RPC调用会引入服务超时、链接异常的概念。为什么要限制超时?是由于不能被单个应用的超时占据了主干应用的服务资源而引发其余服务和整个应用系统受到影响(如大多数线程阻塞在超时调用上)。不管是超时异常仍是链接异常,在业务上也有对应的处理策略。在这里,咱们定义了三种异常处理策略,经过在配置上设置相应的注解,SWAK框架会自动按照策略来处理异常。这三种策略是:
众所周知,RPC调用相对于本地调用会增长一部分的网络传输和序列化开销。对于单次调用来讲,增长若干ms并无什么问题,但对于调用10次、20次或更多,这笔开销就至关可观而应该引发重视了。为此,如何下降RPC开销,是一个必需要考虑的问题。
最可靠的方法就是下降RPC的次数。
在实践中咱们发现,不少扩展点实际上都是获取业务配置。如在闲鱼业务中,“是否支持多库存”就是一种配置,如租房不支持多库存。这些业务配置项是由其业务形态所决定的,基本不会变更。所以能够将一组配置项打包一块儿调用,而且能够缓存下来,也能够直接由主干应用进行维护。在item应用里,这些配置项关系到主干的通用存储过程,目前由各业务方委托主干开发人员进行维护,目前配置在主干环境。能够经过阿里的动态配置平台(如Switch、Diamond)进行动态修改。
另外咱们对部分邻接的扩展点进行了合并。这些相邻扩展点之间的逻辑比较简单,且不会中断主流程。经过“配置型接口”和“邻接扩展点合并”这两种操做,咱们将扩展点数量下降由17个下降到了6个。要注意的是,扩展点并非越少越好。扩展点越少,越意味着“过分拟合”,可能会对后续业务变动没法适应致使主干须要大幅改动,所以须要在数量和扩展性之间找到一个平衡。
另外值得一提的是,SWAK为配置型扩展点作了相应的小改造,并提供了查看当前配置型扩展点返回值的可视化界面。开发人员能够直观地了解当前各个业务的配置值。
在闲鱼,各类业务所须要存储的东西大同小异,从闲鱼的发布界面上来看就不难发现这一点,都是在基础对象(如标题、描述、图片)以外添加一些业务相关的数据,如拍卖业务中指定拍卖的开拍时间等信息,免费送业务中设置兑换币值,图书业务上设置条形码。即对一本图书进行拍卖固然也是容许的,这就出现了拍卖业务和图书业务叠加起来的复合型业务。
对于主干应用开发人员来讲,应该提供单个接口以支持全部业务类型,这样不用每次修改或者新增业务时都须要提供新接口。从稳定性的角度考虑,这样的要求很合理。既然是单个接口,那么DO的定义也应该统一。以商品DO为例,有如下三种方式:
使用第三种的对象模型,以新加一种业务为例,其开发流程是:
业务应用在扩展点返回值中设置须要更新的数据,由主干应用合并。业务应用不该该也不能够直接修改ItemDO,避免影响其余业务的处理逻辑。对于发布和编辑这种须要持久化存储的逻辑来讲,必需要强控各业务对ItemDO的修改,不然理论上来讲,各业务都有可能将全部的关键字段修改得面目全非。前面提到的“配置型接口”中,就有这样的配置——该业务是否能够修改属性字段、该业务是否能够修改描述字段等配置。
闲鱼的商品发布和编辑功能基于SWAK框架通过了两次改造升级,第一次升级完成了平台和业务之间的解耦合以及业务和业务之间的解耦合,第二次升级经过平台和业务间使用RPC调用完成了系统和系统之间的解耦合。改造以后,能更有效地协同更多团队更快更稳定地支撑各类业务。SWAK框架依然在继续演进,如部分扩展点原则上能够经过并行处理或异步化处理来提高性能,但暂时尚未提供支持。在这两次改造中, 咱们还在测试用例的采集、回放、监控告警等方面也有不少积累,敬请期待后续的文章分享。
原文连接 更多技术干货 请关注阿里云云栖社区微信号 :yunqiinsight