作者:京东批发 常文标
商卡聚合服务是一个玲珑的rpc利用,性能是对立查问商品的促销、自营包邮、价格信息、区域库存、区域可配送等等利益点或其余信息。本文重点分享商卡聚合服务的代码设计,包含正当的Sirector线程调度(cpu使用率低),和可维护性的设计。 简版代码示例如下: git@github.com:changwenbiao/demosoa.git
代码应用sirector-core组件并行调度(应用线程并行执行EventHandler的onEvent办法)申请上游rpc接口获取各利益点或其余商品信息。因为申请上游有些通用解决逻辑比方ump监控、调用开关等,所以形象出一个通用的EventHandler名为AbstractBenefitHandler。具体调用利益点的实现类只需继承AbstractBenefitHandler并重写其形象办法。
接下来重点讲代码如何节俭cpu使用率和易于保护的设计。
1.如何节俭cpu
AbstractBenefitHandler提供isSwitchOn办法,用于决定是否应用sirector组件调配线程执行调度EventHandler。绝对于调配线程执行全副的EventHandler,判断是否须要调用才调配线程调用的形式可无效缩小线程调度从而缩小cpu使用率。isSwitchOn办法中可退出cms管制开关逻辑比方应用ducc开关,也可退出依据用户参数判断开关的逻辑,比方查问区域库存须要四级地址,若用户不传四级地址则敞开调用EventHandler(申请上游rpc)。代码实现如下:其中ducc开关在父类中的isSwitchOn中实现,sirector.begin办法承受可变参数列表参数,可将List<AbstractBenefitHandler>转化为AbstractBenefitHandler[]作为入参。
@Overridepublic boolean isSwitchOn() { boolean superSwitchOn = super.isSwitchOn(); if (!superSwitchOn) { return false; } else { //失常为四级地址,如果少于四级则敞开调用 String area = seckillBenefitRequest.getSeckillParam().getArea(); return !StringUtils.isBlank(area) && area.contains("_") && area.split("_").length >= 4; }}
List<String> handlerNames = Lists.newArrayList("areaStockHandler", "partitionProductsHandler");List<AbstractBenefitHandler> handlerList = handlerNames.stream() .map(handlerName -> applicationContext.getBean(handlerName, AbstractBenefitHandler.class).setBenefitRequestAndBizName(request, "demoAppName")) .filter(AbstractBenefitHandler::isSwitchOn).collect(Collectors.toList());Sirector<MiaoShaEvent> sirector = new Sirector<MiaoShaEvent>(bigSeckillEventProcessThreadPool);AbstractBenefitHandler[] eventHandlersArr = new AbstractBenefitHandler[handlerList.size()];handlerList.toArray(eventHandlersArr);sirector.begin(eventHandlersArr);sirector.ready();sirector.publish(new MiaoShaEvent(), 500); //这里开始应用线程并行执行EventHandler的onEvent办法
2. 如何容易保护
缩小一些模版代码(如ump监控):所有Handler的实现类的ump监控都写在父类中的onEvent中,父类的onEvent调用子类实现的onEvent0(解决具体利益点rpc申请解决)办法。
短小代码的实现:AbstractBenefitHandler提供fillResponseInfo办法以向“ResponseVO”中填数据,具体填利益点数据的代码则由相应handler实现类解决。因而各个handler填充利益点“ResponseVO”的代码都是短小的,防止了代码写在一起的长代码。单个handler填充利益点数据和批量对立填充利益点数据代码别离如下:
@Overridepublic void fillResponseInfo(List<BftInfo> bftInfoList) { if (MapUtils.isNotEmpty(areaStockMap)) { for (BftInfo result : bftInfoList) { String skuId = result.getBaseInfo().getSkuId(); if (areaStockMap.containsKey(skuId)) { result.getCommonInfo().setAreaStock(areaStockMap.get(skuId)); } } }}
handlerList.forEach(h -> h.fillResponseInfo(bftInfoList));
缩小一些硬编码:handler实现类配置为原型模式(scope="prototype")的spring bean,通过applicationContext.getBean办法对立获取,防止一些创立(new关键字)具体实现类的代码,若新增利益点调用只需编码AbstractBenefitHandler实现类并配置为spring bean即可。批量获取handler代码如下
List<String> handlerNames = Lists.newArrayList("areaStockHandler", "partitionProductsHandler");List<AbstractBenefitHandler> handlerList = handlerNames.stream() .map(handlerName -> applicationContext.getBean(handlerName, AbstractBenefitHandler.class).setBenefitRequestAndBizName(request, "demoAppName")) .filter(AbstractBenefitHandler::isSwitchOn).collect(Collectors.toList());