作者 | 搜狐视频 赵文浩,对于服务端的开发者而言,我们总有一个共同的目标,那就是如何用更少的资源获得足够的性能来支持我们的服务!,我们不是在性能优化中,就是在性能优化的路上。作为Javaer我们,服务性能优化的武器库中,异步和并发是永远不会过时的两个。,然而理想很美好,现实很骨感:,在服务端引入响应式编程,是解决如上问题的一个好的思路。,下面,我以搜狐视频服务端PUGC团队在PUGC视频对象创建接口的重构工作的实践为背景,介绍响应式(基于RxJava)异步非阻塞编程在服务端的应用在服务端的应用。,PUGC视频对象创建接口,从业务角度看:用于为用户上传视频数据前在服务端为其分配一个视频对象记录,该视频对象记录被用于描述当前视频的完整生命周期,从技术角度看:它是一个聚合接口,通过组合多个上游接口数据,主业务过程涉及:帐号、内容审核、视频对象存储、转码、CDN调度等,实现业务过程。,该接口代码年代久远,从提交记录中可查到的最早的历史在2013年,随着业务的变化,开发人员的变更,代码中充斥着各种各样的味道。不论是从业务角度、性能角度亦或是日常维护角度看,都难以满足需要。,为了解决以上的诸多问题,我们开始了重构(重写)之路。,重构的原则是保证接口实现的业务规则的一致性,通过仔细研读代码,整理出接口中实现的诸多特性和业务规则。,视频对象创建主流程如下图所示:,
, 注:时序图中描述的是主流程中的关键点,因篇幅所限并未列出每个调用的具体细节,从用户请求到达服务端开始划分业务执行阶段:,这其中每个阶段的内容都需要通过若干个上游接口调用协作来完成,因篇幅所限,并未完全描述每个阶段的具体实现细节。,通过分析业务流的特点:,结合接口重构核心目标:,我们决定基于响应式异步非阻塞架构对接口进行重构:,涉及的基础组件,同步阻塞模式适配响应式异步非阻塞,因后续章节代码示例中主要以dubbo服务接口调用为主,所以我以视频服务端团队基于dubbo-2.6.5版本实现的dubbo响应式客户端dubbo-reactive-consumer为例,介绍将传统的同步阻塞模式适配响应式异步非阻塞的思路。,Dubbo是目前视频服务端用使用的较多的RPC框架,目前最新的版本是Dubbo3.x(注:由于历史原因,目前团队使用的版本还停留在2.6.5版本)。在Spring环境中,比较简便的注入dubbo服务接口代理对象(简称接口对象)的方式是通过@com.alibaba.dubbo.config.annotation.Reference注解自动注入,示例如下:,默认情况下,这种方式注入的是基于同步阻塞模式接口对象,由于dubbo客户端基于Netty实现,所以它天生是是异步的。一般情况下,如果希望通过异步方式使用dubbo客户端可以按如下方式操作:,为支持响应式框架,同时保持通过@com.alibaba.dubbo.config.annotation.Reference注解自动注入接口对象的方式,我们的实现过程如下:,将接口对象包装成响应式引用类型:ReactiveReference<Service>,接口中提供了两个方法用到了整个单值类型的响应式流:,实现响应式引用实现ReactiveReferenceImpl<Service>,DubboSubscription<T>用于同Dubbo框架桥接,实现如下:,于是基于我们的响应式dubbo客户端,服务接口的调用方式为:,注:此处的实现为常规的Spring生命周期处理,与本文无关,具体实现细节不再赘述,扩展com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor使dubbo自动注入框架支持ReactiveReference<Service>类型,自动设置为异步模式,且向目标Component中注入的实际类型为ReactiveReferenceImpl<Service>,我们在读懂业务流一节中对视频对象创建主流程做了说明,然后将主流程分成了5个阶段,现在我们使用RxJava代码来描述这5个阶段(注:后续代码仅用于演示主流程的实现过程,并不是完整的实现过程)。,输入参数Args,过程结果PassObj,响应式流主干,每个阶段的详细实现:,数据校验阶段:帐号状态/入参合规/内容重复性,对象创建阶段: 视频对象存储,关联数据对象创建阶段,上传准备:从CDN调度视频内容存储结点,以上内容是搜狐视频服务端PUGC团队,首次在核心业务接口中应用响应式异步非阻塞架构的思考和实施过程,文中主要阐述了两个内容:,通过本次重构,我们获得了如下收益:,结束,感谢阅读!
© 版权声明
文章版权归作者所有,未经允许请勿转载。