原因并发
新系统重构中,收获了一个重要的设计教训。
性能
事情是这样滴,以下图所示:
大数据
有一个 Hbase 表 oe_item 存放订单商品相关的交易信息,rowkey 设计为 “订单号_oldItemID” ,是经过 storm 同步任务处理 old_item 表的binlog订阅写入该表的。oe_item 的量级很大。优化
在老的实现方式中,因为应用在访问这个表以前没法取到订单的oldItemID, 所以,须要拿到订单号去 scan 这个表。显然这个开销是很大的。当须要访问大量订单的 oe_item 数据时,并发访问这个表会致使超时,线程被hang住,进而影响系统总体稳定性。如有可能,应该干掉 scan oe_item 这个威胁系统稳定性的耗时操做。
线程
系统重构后,经过详情API接口,可以获取到新订单及newItemID, 可以获取到老订单及oldItemId。显然,对于老订单来讲,能够用{order_no}_{oldItemID}拼成 rowkey 来 batchGet oe_item 表; 然而,对于新订单,因为没法获取到oldItemID, 这使得要获取新订单 oe_item 表的信息,依然要 scan 这个表,而不能替换为 batchGet, —— 众所周知, batchGet 操做一般比 scan 操做的性能要更好,获取大数据量时稳定性更优 , —— 所以,错过了优化系统稳定性的一个关键环节。是否是很蛋疼 ?
设计
教训orm
在没有对总体设计足够清晰以前,不要急于着手去解决一个问题。 仓促地解决一个问题,会致使解决不足,继续受到该问题的困扰,以前的方案甚至会形成束缚。blog
敏捷设计并非不作充分的思考和设计,而是强调不要“过犹不及”; 完成当前须要的,并为扩展预留空间。 这实际上须要更充分的设计考量。接口
好比作订单导出配置化时,我是采用小步优化逼近的方式来实现配置能力的。这当然也能解决问题,可是当面对新问题时,时而有某个地方考虑不周到,须要再修改代码和发布。 这便是由于在总体设计上没有思考的足够清晰,没有足够的融会贯通, 以至于老是纰漏百出。同步
所以,解决问题,要从总体设计上尽可能考量得足够清晰,而后再下手去作。
这里说的是,当创建新模型时,不要去兼容老方案,不然永远都无法摆脱历史包袱。
好比作新退款信息获取的时候,当时贪急求快(也考虑到退款金额不对致使订单状态不对,会诱导商家误发货), 就沿用老方案的存储,将新退款的数据也存储在老的退款 HBase 表里, 结果新老退款都须要去 scan 这个表,性能开销甚大,并且对稳定性有影响。
正确的作法应该是, 针对新模型,创建新方案的存储,而后在应用中聚合两种方案,分流,冷却老方案的存储和获取,一段时间后,就会自动切换到新方案上,摆脱老方案的历史包袱。
约定胜于配置。 良好的约定,可使得系统的交互和整合更加简洁清晰, 而不须要考虑过多的状况,致使复杂度上升。
好比导出扩展字段时,约定扩展字段在下单表里的存储形式,而后导出按照这种约定去获取相应数据。 除非下单存储有误,不然导出是不会有问题的,省了不少事。
在设计存储的时候,就要想到如何去使用。
Think Deeper, Design Better.