前面已经介绍了消息生产消费中间类库(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的更多相关文章

  1. SDK接入(U8SDK)——SDK抽象层的设计

    上一篇文章,我们总体地分析并设计了一套高效的SDK接入方案,也罗列出这套方案,我们需要完成的工作.这里再罗列并回顾下: 1.统一抽象的SDK接入框架 2.各个SDK接入实现 3.一键打包工具 4.统一 ...

  2. 事件消息生产消费中间件-OSS.DataFlow

    系统重构解耦的过程涉及不同领域服务分拆,或同一服务下实时响应部分和非响应部分分拆,分解后的各部分通过异步消息的流转传递,完成整体的业务逻辑,但是频繁的在业务层面直接调用不同消息队列的SDK,个人感觉不 ...

  3. Java消息系统简单设计与实现

    前言:由于导师在我的毕设项目里加了消息系统(本来想水水就过的..),没办法...来稍微研究研究吧..简单简单... 需求分析 我的毕设是一个博客系统,类似于简书这样的,所以消息系统也类似,在用户的消息 ...

  4. 【开源】OSharp框架解说系列(5.1):EntityFramework数据层设计

    OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...

  5. ENode 1.0 - 消息队列的设计思路

    开源地址:https://github.com/tangxuehua/enode 上一篇文章,简单介绍了enode框架内部的整体实现思路,用到了staged event-driven architec ...

  6. enode框架step by step之消息队列的设计思路

    enode框架step by step之消息队列的设计思路 enode框架系列step by step文章系列索引: enode框架step by step之开篇 enode框架step by ste ...

  7. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 1

    现在,如果你已经能熟练地使用MySQL客户端软件来操作数据库中的数据,就可以开始学习如何使用PHP来显示和修改数据库中的数据了.PHP提供了标准的函数来操作数据库.在PHP 5以上的版本中可以使用My ...

  8. 网络编程之网络架构及其演变过程、互联网与互联网的组成、OSI七层协议、socket抽象层

    目录 网络架构及其演变过程 单机架构 CS架构 BS架构 BS架构和CS架构的区别 C/S架构的优缺点: B/S架构的优缺点: 互联网与互联网的组成 互联网的组成(教科书版) 互联网的组成(科普版) ...

  9. redis源码分析(二)-rio(读写抽象层)

    Redis io抽象层 Redis中涉及到多种io,如socket与file,为了统一对它们的操作,redis设计了一个抽象层,即rio,使用rio可以实现将数据写入到不同的底层io,但是接口相同.r ...

随机推荐

  1. 微信小程序应用安全分析及设计

    针对微信关于小程序安全设计的分析 针对微信小程序开发配置及部分配置机制分析微信小程序安全设计: AppSecret 管理员生成AppSecret,在与微信后台交互过程中部分接口使用,如 auth.co ...

  2. The type name or alias SqlServer could not be resolved.Please check your configuration

    The type name or alias SqlServer could not be resolved.Please check your configuration file.... 检查一下 ...

  3. 洛谷5024 保卫王国 (动态dp)

    qwq非正解. 但是能跑过. 1e5 log方还是很稳的啊 首先,考虑最普通的\(dp\) 令\(dp1[x][0]表示不选这个点,dp1[x][1]表示选这个点的最大最小花费\) 那么 \(dp1[ ...

  4. 【分享】 一款自用的Anki卡片模板:黄子涵单词卡片 v1

    [分享] 一款自用的Anki卡片模板:黄子涵单词卡片 v1 说明 第一代的功能 主要有两部分组成:英文和含义,目前主要是为自己记忆Web前端一些常用的单词而服务 有美美哒背景图,本来想修改为随机背景图 ...

  5. 在python中实现BASE64编码

    什么是Base64编码 BASE64是用于传输8Bit字节的编码方式之一,是一种基于64个可打印字符来表示二进制数据的方法. 如下是转换表:The Base64 Alphabet Base64编码可以 ...

  6. JAVA复习总体大纲

    1 java基础. [1].变量--- 数据类型 变量名=值; 数据类型: 1.基本数据类型. byte[1字节] short[2字节] int[4字节] long[8字节] float[4字节] d ...

  7. 第五课第四周笔记1:Transformer Network Intuition 变压器网络直觉

    目录 Transformer Network Intuition 变压器网络直觉 Transformer Network Intuition 变压器网络直觉 深度学习中最令人兴奋的发展之一是 Tran ...

  8. Beta阶段性总结

    1.题士开发总结 2.反思 2.1 Issue管理 从0522敲定各个功能的API后,团队成员及时沟通,积极开发,但由于开发过程没能有效体现在issue上(如未能及时在issue上形成记录,功能开发完 ...

  9. 第0次 Beta Scrum Meeting

    本次会议为Beta阶段第0次Scrum Meeting会议 会议概要 会议时间:2021年5月27日 会议地点:「腾讯会议」线上进行 会议时长:1小时 会议内容简介:本次会议为Beta阶段启程会议,主 ...

  10. 认识spring security

    在一个系统中认证和授权是常有的事情,现在比较流行的框架有spring security.shiro等等.他们都能很好的帮助我们完成认证和授权的功能.那么假如说让我们自己完成一个登录那么应该大致的流程是 ...