知道这些坑,你还敢乱把单体架构拆成分布式吗?( 五 )


}
booleanflag=skuMainWriteservice.editorProduct(skuMainUpdate);
if(flag){
if(!zkConfManagerCenterService.isDefaultStoreStatisticsScore(skuMainBean.getOrgCode())){
SkuMainBeansaveSkumainBean=skuMainservice.queryDbById(skuMainUpdate.getId());
//防止未查到,把缓存覆盖
if(saveSkumainBean!=null){
skuMainWriteservice.cacheSkuMainBean(saveSkumainBean);
}
//发送Sku修改MQ
skuMainWriteservice.sendSkuModifyMq(SkuModifyOpSourceEnum.MIX_UPDATE_SKU,originalSku,newSkuMainInfoMQEntity(skuMainUpdate));
}else{
LOGGER.info("addopenplatformsku,notnotnotsendmq!skuId={}",skuMainBean.getId());
}
}
}catch(Exceptione){
LOGGER.error("修改商品信息失败.e:",e);
thrownewException(e);
}
}
④构建好的业务层
知道这些坑,你还敢乱把单体架构拆成分布式吗?
文章图片
5)拆分小结
拆分到这里 , 业务层的划分基本就比较清晰了 , 而且在这个增量整合底层代码的过程中 , 面向过程的业务线也都梳理的比较清晰了 , 底层方法也都提取到了业务层收口 , 通过接口对外提供服务 。 那么接下来我们要面临的问题就是 , 如何对具体的读写进行拆分 。
3、基于CQRS打造分布式服务
上面我们也提到了 , 进行了整体功能的拆分 , 并没有对具体的读写服务的拆分 。 在面向服务的场景下 , 功能里也是分读服务、写服务 。 那么我们有什么原则来指导读写服务的分离么?那就是CQRS的思想:命令职责查询分离 , 不单单指代码 , 同样也是适用于服务 。
知道这些坑,你还敢乱把单体架构拆成分布式吗?
文章图片
1)优先拆分读还是优先拆分写
建议从拆分读开始 , 因为读服务相对于写服务简单一些 , 而且更容易提高系统对外服务的稳定性 , 写服务的流程相对底层改动比较大 , 测试的周期也会比较长 。 在前期 , 动写服务系统出问题的概率会比较大 , 所以综合稳定性、扩展性来说 , 优先拆分读服务是一个比较好的选择 。
2)CQRS的思想适合所有业务场景吗
以库存系统举例 , 我们就按照CQRS的思想复刻一版 , 看看会出现什么问题 。 每一次修改同步库存写入任务表schedule任务读取任务表把任务表的修改数据同步到Read服务中的redis中
在这个过程中 , 存在两个问题:大数据量任务同步的问题 。 也就是EventBus同步redis的数据同步速度问题 。 延迟问题 。 库存要求实时性非常高 , 如果因为任务积压导致的延迟 , 会让库存陷入困境之中 。 大量的库存数量不对导致的超卖、超卖会瞬间击溃业务 。
知道这些坑,你还敢乱把单体架构拆成分布式吗?
文章图片
所以每一个架构、每一种思想都是要结合业务去分析 , 我们可以借鉴CQRS的命令查询职责分离 , 在面对业务系统部署的时候 , 不要死板的遵循固有的模式 , 要对现有的风格做出一定的取舍 。 所以 , 我们在应对库存业务的时候 , 基于CQRS的风格创建出了库存独有的CQRS-StockCenter(名字自己起的哈哈)
3)CQRS的活学活用:CQRS-StockCenterbusiness业务层写入命令writeService服务写入读服务RedisMQ消息作为异步数据补全写入mysql备份、写入流水
知道这些坑,你还敢乱把单体架构拆成分布式吗?
文章图片
库存通过这套设计强依赖了Redis来作为库存查询、修改的中间件 。 保障了数据的强一致性 。 库存在原有的服务上 , 分离了读写 , 保障了系统的CQRS命令职责查询分离 。
知道这些坑,你还敢乱把单体架构拆成分布式吗?
文章图片