写点什么

响应式架构与 RxJava 在有赞零售的实践

  • 2020-03-15
  • 本文字数:3099 字

    阅读完需:约 10 分钟

响应式架构与 RxJava 在有赞零售的实践

随着有赞零售业务的快速发展,系统和业务复杂度也在不断提升。如何解决系统服务化后,多个系统之间的耦合,提升业务的响应时间与吞吐量,有效保证系统的健壮性和稳定性,是我们面临的主要问题。结合目前技术体系和业务特点的思考,我们在业务中实践了响应式架构以及 RxJava 框架,来解决系统与业务复杂所带来的问题。

一、实践响应式架构

响应式架构是指业务组件和功能由 事件驱动,每个组件异步驱动,可以并行和分布式部署及运行。


响应式架构可以带来以下优势:


  • 大幅度降低应用程序内部的耦合性

  • 事件传递形式简化了并行程序的开发工作,使开发人员无须与并发编程基础元素打交道,同时可以解决许多并发编程难题,如死锁等。

  • 响应式架构能够大幅度提高调用方法的安全性和速度。

  • 对复杂业务系统的领域建模,响应式架构可以天然支持。每个系统组件就可以对应到一个业务实体,业务实体之间通过接收事件来完成一次业务操作。


我们使用响应式架构主要是为解决多个系统间的多次远程调用带来的分布式问题,尤其在长任务场景中,响应式架构显得尤其必要。


有赞连锁出现后,随着连锁商家经营规模的扩张,会在系统中创建新的门店。创建新门店会引发一系列业务初始化工作,例如店铺、员工、仓库、商品、库存等业务域,并且各业务域之间存在一定的依赖关系(如图 1 所示),例如商品依赖仓库初始化完成。



图 1 连锁新建分店系统依赖关系


商家新增门店时,在店铺初始化完成后,连锁系统发送店铺初始化成功消息,相应系统对事件进行响应,处理完成(成功/失败)后将回执给连锁系统,连锁系统根据相关业务的反馈,决定是继续通知下游业务,还是结束整个过程。新建门店部分流程如图 2 所示。


在创建门店业务中,每个系统响应连锁系统发出的消息,处理完成后进行回执。通过这种模式,业务系统本身不关心其他系统是否成功或失败,只需对通知的事件进行处理,整体初始化进度与异常处理由连锁系统来控制。这种设计使得各业务系统之间没有直接耦合并保持相互独立。



图 2 连锁体系新增分店消息驱动图


上面的案例介绍了在复杂业务场景下系统间对响应式架构的实践,系统内部同样会遇到复杂业务场景。下面介绍下在系统内部应对复杂业务的实践。

二、RxJava 在有赞零售实践

Rxjava 是用来编写异步和基于消息的程序的类库。RxJava 在 Android 有着广泛的使用,主要应用在用户界面绘制与服务端通讯等场景。RxJava 的核心思想是响应式编程以及事件、异步这两个特点。响应式编程是一种通过异步和事件流来构建程序的编程模型。在复杂的业务开发中,最棘手的问题就是如何清晰直观的展现复杂的业务逻辑,并且方便后续的业务维护与扩展。

2.1 响应式编程使得复杂业务逻辑更清晰

有赞零售的业务场景中有着复杂的业务逻辑,有赞目前提供多种产品供商家选择,商家在不同产品进行切换时,为了商家更好的体验,不同业务的切换会进行数据初始化与处理。例如有赞微商城转换到有赞零售。


这里拿着微商城升级零售的业务场景给大家举例。微商城升级为零售时需要对商品进行转换。首先初始化店铺基础信息。然后读取商品流,将微商城的商品类型转换成零售支持的商品类型。最后读取规格,为规格创建供应链商品库,创建门店商品与添加网店商品的供应链商品关联关系。整体转换流程如图 3 所示。图中也画出了可以并发处理的场景。



图 3 微商城升级有赞零售流程


如果单纯使用设计模式来解决上面这种场景单一、但业务逻辑特别复杂的场景,是很难做到的。也可以看到除了初始化信息那一步,后面的商品模型转化自始至终在业务中流转的事件都是商品,这里就可以使用 RxJava 来优化业务代码使得处理流程可以并发,加快升级速度。


最终我们按照图 3 的流程处理升级逻辑,其中的并发场景,比如保存完零售商品后,并发处理库存、和销售渠道,使用 rxjava 封装的方法帮助我们进行并发操作。如下所示代码结构清晰,对外屏蔽了复杂的并发处理逻辑。


Observable.zip(  callAsync(()->处理库存相关操作),  callAsync(()->更新商品库门店销售渠道),  callAsync(()->创建商品库与网店商品关联关系),  (sku1,sku2,sku3)-> sku).blockingFirst();
复制代码


最终我们的整体的代码:


UpgradeItem.listItems(manager, shop)  .flatMap(item-> fromCallable(()->更新为零售商品类型))  .flatMap(item-> fromCallable(()->并发处理商品操作), true)  .flatMap(item-> 商品流转化为sku流, true)  .flatMap(sku-> fromCallable(()->保存零售商品))  .flatMap(sku-> fromCallable(()->并发处理保存商品后续操作, true)  .subscribeOn(Schedulers.io());
复制代码


整个商品处理流程就是上面这段代码,一目了然,后面扩展可以自己在中间加入处理流程,也可以在对应业务方法中修改逻辑。

2.2 多服务、数据源组合

随着微服务架构兴起,我们将不同的业务域拆分成不同的系统。这样方便了系统的维护,提升了系统的扩展性,但是给上层业务系统也带来了很多麻烦。往往我们为了展示一个页面会涉及到 2-3 个或更多的应用,而多次的分布式调用不但使得系统的 rt 增加,也使得核心页面的出错风险更高。


降低 rt:在假设第三方接口已经达到性能顶点的情况下,并发是解决多次分布式调用降低 rt 的常用方法。


自动降级:传统编程方法中,自动降级处理,意味着我们代码中会出现一大堆 try/catch,而使用 rxjava,我们可以直接定义当流处理异常时,程序需要怎么做,这样的代码看起来非常简洁。


商品搜索作为商品管理的核心入口,根据不同场景聚合商品、优惠、库存等信息。由于商品列表页展示的信息涉及到多服务数据的整合,一方面需要保证整个接口的 rt,另一方面不希望由于一个商品数据或外部服务的异常影响到整个商品列表的加载。因此该场景非常适用于 RxJava。



最终我们的代码


1.根据入参获取商品加载器


//只有包含的merger才会加载List<SkuAttrMerger> validMergers =   Observable.fromIterable(skuAttrMergers).filter(loader -> request.getAttributes().contains(loader.supportAttribute().getValue())).toList().blockingGet();
复制代码


2.根据 es 结果获取商品各个属性详情并加载到 SkuAttrContext 中(某类属性加载失败则忽略)


//调用load并发加载数据到商品属性上下文中Observable.fromIterable(商品信息加载器列表).flatMap(商品信息加载器-> Observable.fromCallable(() ->异步加载商品信息)).onErrorResumeNext(Observable.empty())//如果失败则忽略.subscribeOn(Schedulers.io()),false,线程数(为加载器数 量)).blockingSubscribe();
复制代码


3.组装搜索结果(如果某个 sku 组装失败则直接忽略)


//调用merge将数据合并到目标对象商品搜索返回结果列表 = Observable.fromIterable(商品id列表)  .map(商品id->初始化商品搜索结果返回对象)  .flatMap(商品搜索结果返回对象-> {    val observables=Observable.fromIterable(商品加载器列表)      .map(loader -> Observable.fromCallable(() ->合并每个sku的不同属性)).toList().blockingGet();    return Observable.zipIterable(observables, (a) -> sku, false, 线程数)    .onErrorResumeNext(Observable.empty()); //如果失败则忽略    }, false, 1)  .toList()  .blockingGet();
复制代码

三、后记

本文主要介绍了响应式架构与 RxJava 在有赞零售的使用场景。目前我们对响应式架构的实践方式是:在系统间使用消息中间件来进行实现,在系统内则使用 RxJava 实现异步化和响应式编程。对于响应式架构的思想,我们也在探索阶段,并在部分业务场景进行实践。未来面对越来越复杂的零售业务场景,会用响应式架构全面实现系统业务的异步化。总的来说响应式架构思想为提升复杂业务系统健壮性、灵活性提供了强有力的支撑。后面大家如果想更多的讨论响应式架构与编程的实践,欢迎联系我们。


2020-03-15 20:191127

评论

发布
暂无评论
发现更多内容

APISIX Ingress 对 Gateway API 的支持和应用

API7.ai 技术团队

云原生 APISIX API Gateway Ingress Controller

共创精彩游戏未来,华为云大数据解决方案助力游戏企业成功转型!

秃头也爱科技

干货|无源元件之——电感基础知识(详解)

元器件秋姐

科普 电感器 电感 电感元件 电子知识

什么样的魔法棒,能让AI魔法师一夜成名?

白洞计划

超融合一体流式引擎,打造分布式数据库新纪元

亚信AntDB数据库

AntDB 国产数据库 AntDB数据库

2022-12-29:nsq是go语言写的消息队列。请问k3s部署nsq,yaml如何写?

福大大架构师每日一题

云原生 k8s k3s nsq 福大大

HTTPS基础知识

穿过生命散发芬芳

https 12月月更

界面原型设计

梦笔生花

android GUI设计 mockplus droiddraw

华为云OBS对象存储服务:这个管家很贴心

爱尚科技

智能且高效,华为云CDN三大特点助企业云上创新

爱科技的水月

【web 开发基础】PHP查询数组中的指定元素 (50)

迷彩

数组 数组操作 二维数组 PHP基础 数组查询

cleanmymac2024永久版mac系统清理软件

茶色酒

CleanMyMac CleanMyMac X

人生的喜悦、不快与成长,都在那一篇篇的文字中得到记录 | 2022 年终总结

宇宙之一粟

年终总结 人生故事 代码之外 12月月更

云渲染一张图大概多久?云渲染快吗?

Renderbus瑞云渲染农场

云渲染

什么样的魔法棒,能让AI魔法师一夜成名?

脑极体

华为云微服务引擎0停机迁移Nacos?它是这样做的

科技之光

华为云OBS:让大数据的容器再无容量限制

爱尚科技

C#-使用Consul

kdyonly

C#

助力网络碳中和 | 华为发布站点能源十大趋势

Geek_2d6073

缓解等待焦虑,华为云CDN为您提供畅快下载体验

爱科技的水月

【架构设计】保持简单轻量设计的三个原则——DRY,KISS, YAGNI

JAVA旭阳

Java 架构

【web 开发基础】PHP中获取数组的元素个数 (51)

迷彩

数组 数组操作 PHP基础 数组查询 统计数组

小米封杨:工业设备预测性维护及时序数据库选型

YMatrix 超融合数据库

工业4.0 超融合数据库 预测性维护 设备预测性维护 YMatrix

MatrixDB v4.6.0 发布,查询性能和图形化操作界面全面升级!

YMatrix 超融合数据库

Prometheus 存储引擎 超融合数据库 YMatrix MatrixGate

亚信科技通信、交通行业数据库项目入选“星河”标杆、优秀案例

亚信AntDB数据库

AntDB 国产数据库 AntDB数据库

让下载速度更快更稳,华为云CDN多重技术助力网络加速

爱科技的水月

企业数据存储,还得看华为云对象存储服务OBS

爱尚科技

FL Studio2024中文版本水果软件下载

茶色酒

FL Studio FL Studio 21

华为云对象存储OBS超高性能数据存储能力,推进企业快速上云

爱尚科技

华为云CDN引领网站性能全面优化

爱科技的水月

CleanMyMac2024激活码使用教程

茶色酒

CleanMyMac CleanMyMac X

响应式架构与 RxJava 在有赞零售的实践_文化 & 方法_陈肃_InfoQ精选文章