消息抽象层设计和实现-OSS.DataFlow
前面已经介绍了消息生产消费中间类库(OSS.DataFlow)的简单使用,这篇主要介绍内部的设计实现。主要内容包含:
1. 消息生产消费的抽象设计。
2. 具体使用示例
一. 消息生产消费的抽象设计。
需要首先强调的是,这里的生产消费抽象主要在业务使用层面,抛开具体的RabbitMQ之类的消息队列产品。可能说起来比较模糊,我们先看下常见的业务调用消息队列的情况:
上边是一个常见的通过消息队列将业务异步拆解的模型,按道理结构已经十分简单了,特别是对于一个相对稳定的业务,代码基本变动不大的情况下,这个模型基本足够了。不过对于一个爱折腾的开发人,不玩点花里胡哨的,存在感就没了,经过各种假设论证之后,终于找到了这么几个不满意的地方:
1. 开发,测试,生产,都需要搭建对应的Rabbit实例,特别是开发测试环境抢消息,再加上多人开发,大麻烦可能没有,但小麻烦一定是不断的。
2. 业务代码中,直接调用了具体消息队列的产品,当某一个模块消息量快速上升,无法局部切换队列产品。(当然你也可以切分出独立的服务,但是耗时,代价相对较大)。
3. 对于同一解决方案内的异步消息,或多或少的会出现生产消息调用和消费消息调用代码分散(比如用户登录后添加日志)。
4. 当前的项目代码依赖外部消息队列或者数据库(如果公司偏项目型,新项目无法轻装上阵)
以上臆测仅个人偏见,仅供参考。在我的角度,我希望在业务调用消息中转的过程中,需要面向的是接口,在需要的时候适配即可,所以我尝试添加一个轻简的中间层。
这个中间层第一件事就是隔离,草图设计如下:
通过全局 DataFlowFactory 能够创建消息发布者(IDataPublisher),并能够注入订阅者(IDataSubscriber) ,业务层只需要通过 IDataPublisher,IDataSubscriber 接口交互,和具体消息存储设施脱离。顺着这个思路,当业务需要生产写入消息时,创建发布者,并通过发布者写入消息,并完成订阅者的回调,这个环路即可完成。
现在只需要解决两个问题:
1. 创建的发布者,如何实现不同场景的扩展。
2. 如何完成对应的订阅者(支持同一消息类型,多个订阅者)的回调。
这里我引入一个全局管理对象(DataFlowManager),内部的调用过程图示如下:
在 DataFlowManager 中提供了 PublisherProvider 公开属性,可用来扩展不同消息设施的发布者实现。同时,提供了 NotifySubscriber 方法,作为已注册消息订阅者的统一触发入口(内部完成了多个订阅者的调度,当然如果针对特殊消费者调用,用户也可以跳过注册订阅者,自由实现订阅处理)。
通过上边的整个过程,完全实现了消息中间层的功能,以插件的形式将具体的消息设施在程序的全局入口注入,这样就可以针对不同环境不同业务模块(入口的参数 source_name 控制)做定制化。同时,在大多数的项目中(包括在开发环境中)并无需立即使用独立的消息设施,所以在中间件的内部,提供了一个默认的内存消息队列实现,这样也保证了类库的即引即用,扩展后的图示如下:
根据上边的过程图可以看出,内部的默认队列,和外部队列所处统一层级,当没有提供用户自定义 PublisherProvider时(或者Provider 返回的 DataPublisher为空),系统会执行内部的默认队列实现。
二. 具体使用示例
上边展示了内部设计,这里介绍具体的代码使用层面,看在实际的使用中是如何简化内敛整个消息的处理。
1. 业务侧调用:
上边演示了消息Key为 “ P-S-Msg ” ,有两个订阅者(这里使用了委托方法,也可以传入继承IDataSubscriber<MsgData> 接口的实例),并且创建了一个名为 _publisher 的发布者(如果没有注册其他消息存储适配实现,会走默认内部消息队列实现,即创建一个名为 NewSource 的队列)。除了上边的使用方式,有些时候我们的生产和消费代码都是同一个服务内部,比如用户登录和添加登录日志,这个时候提供了一个更简单的方式:
可以看出,具体的业务代码相对很清晰,不需要关注具体的消息底层实现,或者什么触发方式(定时,webhook或者内部消费线程)。而这些内容全部转移到全局模块插件化适配。
二. 消息的底层适配:
上边的代码,自定义了一个 CustomMsgStorage 消息存储适配器,并在全局初始化时,赋值给 DataFlowManager.PublisherProvider ,在这个适配器里,约定了当 source_name 等于 CustomStorageQueue 时返回消息发布者 CustomMsgStoragePublisher,当然这个具体实现可以替换成 RabbitMQ,Redis,Mysql 等等,当消息实际消费触发时,调用 DataFlowManager.NotifySubscriber() 方法即可,在上边的测试用例里,我简化了这个过程,直接调用,实际场景根据情况调整即可(比如放在RabbitMQ的消费监控线程,或者读取Mysql数据的定时任务中)。
简单来说,DataFlowFactory处理业务使用接口(通过 msgkey 关联生产者和消费订阅者),DataFlowManager 控制具体的消息适配(通过 source_name 来控制底层适配), 基本解决了前面我所顾虑的问题。
如果你已经看到这里,并且感觉还行的话可以在下方点个赞,或者也可以关注我的公总号(见二维码)
消息抽象层设计和实现-OSS.DataFlow的更多相关文章
- SDK接入(U8SDK)——SDK抽象层的设计
上一篇文章,我们总体地分析并设计了一套高效的SDK接入方案,也罗列出这套方案,我们需要完成的工作.这里再罗列并回顾下: 1.统一抽象的SDK接入框架 2.各个SDK接入实现 3.一键打包工具 4.统一 ...
- 事件消息生产消费中间件-OSS.DataFlow
系统重构解耦的过程涉及不同领域服务分拆,或同一服务下实时响应部分和非响应部分分拆,分解后的各部分通过异步消息的流转传递,完成整体的业务逻辑,但是频繁的在业务层面直接调用不同消息队列的SDK,个人感觉不 ...
- Java消息系统简单设计与实现
前言:由于导师在我的毕设项目里加了消息系统(本来想水水就过的..),没办法...来稍微研究研究吧..简单简单... 需求分析 我的毕设是一个博客系统,类似于简书这样的,所以消息系统也类似,在用户的消息 ...
- 【开源】OSharp框架解说系列(5.1):EntityFramework数据层设计
OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...
- ENode 1.0 - 消息队列的设计思路
开源地址:https://github.com/tangxuehua/enode 上一篇文章,简单介绍了enode框架内部的整体实现思路,用到了staged event-driven architec ...
- enode框架step by step之消息队列的设计思路
enode框架step by step之消息队列的设计思路 enode框架系列step by step文章系列索引: enode框架step by step之开篇 enode框架step by ste ...
- 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 1
现在,如果你已经能熟练地使用MySQL客户端软件来操作数据库中的数据,就可以开始学习如何使用PHP来显示和修改数据库中的数据了.PHP提供了标准的函数来操作数据库.在PHP 5以上的版本中可以使用My ...
- 网络编程之网络架构及其演变过程、互联网与互联网的组成、OSI七层协议、socket抽象层
目录 网络架构及其演变过程 单机架构 CS架构 BS架构 BS架构和CS架构的区别 C/S架构的优缺点: B/S架构的优缺点: 互联网与互联网的组成 互联网的组成(教科书版) 互联网的组成(科普版) ...
- redis源码分析(二)-rio(读写抽象层)
Redis io抽象层 Redis中涉及到多种io,如socket与file,为了统一对它们的操作,redis设计了一个抽象层,即rio,使用rio可以实现将数据写入到不同的底层io,但是接口相同.r ...
随机推荐
- 从零入门 Serverless | Serverless Kubernetes 应用部署及扩缩容
作者 | 邓青琳(轻零) 阿里云技术专家 导读:本文分为三个部分,首先给大家演示 Serverless Kubernetes 集群的创建和业务应用的部署,其次介绍 Serverless Kuberne ...
- 题解 2020.10.24 考试 T3 数列
题目传送门 题目大意 给出一个数 \(n\),你要构造一个数列,满足里面每个数都是 \(n\) 的因子,且每一个数与前面不互质的个数不超过 \(1\).问有多少种合法方案. 保证 \(n\) 的不同质 ...
- 题解 Christmas Game
题目传送门 题目大意 给出 \(t\) 个 \(n\) 个点 \(m\) 条边的无向图,每次可以从任意一棵树选择一条边删掉,然后该树不与根(为 \(1\) )联通的部分被删掉.不能操作的人输.问谁有必 ...
- 北鲲云超算如何让仿真技术、HPC和人工智能之间的深度融合?
在CAE领域,随着仿真技术在多个行业的深度应用,也带来了仿真模型日益复杂.仿真过程数据倍增.仿真计算费用昂贵等问题,降阶模型.人工智能.云计算等多种技术和仿真技术的深度融合,成为了仿真技术的重要发展趋 ...
- diff算法深入一下?
文章转自豆皮范儿-diff算法深入一下 一.前言 有同学问:能否详细说一下 diff 算法. 简单说:diff 算法是一种优化手段,将前后两个模块进行差异化比较,修补(更新)差异的过程叫做 patch ...
- JVM:内存溢出OOM
JVM:内存溢出OOM 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 经典错误 JVM 中常见的两个 OOM 错误 StackoverflowError:栈溢出 ...
- MySQL:提高笔记-3
MySQL:提高笔记-3 学完基础的语法后,进一步对 MySQL 进行学习,前几篇为: MySQL:提高笔记-1 MySQL:提高笔记-2 MySQL:提高笔记-3,本文 说明:这是根据 bilibi ...
- [no_code]团队贡献分分配规则
项目 内容 2020春季计算机学院软件工程(罗杰 任健) 2020春季计算机学院软件工程(罗杰 任健) 作业要求 团队贡献分分配规则 我们在这个课程的目标是 远程协同工作,采用最新技术开发软件 这个作 ...
- stm32电机控制之控制两路直流电机!看完你会了吗
手头上有一个差分驱动的小车,使用两个直流电机驱动,要实现小车的在给定速度下运动,完成直线行驶,转向,加速,刹车等复杂运动. 使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制, ...
- 构建乘积数组 牛客网 剑指Offer
构建成绩数组 牛客网 剑指Offer 题目描述 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...*A[i-1]A[i ...