消息中间件核心实体(0)

消息中间件核心实体(0)

最近两周在做的一个新项目,一个主从复制的组件,这两天刚跑通测试。

从之前讨论的架构来说,消息中间件也是有主从复制这个模块的,像Rocket就支持主从模式。

在做这个项目之前已经写过两个版本的主从复制模块,基本思路是:

  1. Slave主动和Master建立链接
  2. Slave从Master不断Pull数据
  3. 并ack进度给Master
  4. Master根据Slave的进度来支持异步复制、半同步复制的语义
  5. Slave上有replay线程根据复制数据恢复上层状态

也可以采用Master向Slave push数据的方式(如果自己做主从复制,一定要去了解MySQL的主从复制实现)。

已经做了两个版本的主从复制了,为什么最近又会起新项目去做这个事情呢?因为我们意识到主从复制其实是一个相对独立的模块,和上层的消息业务并不相关。比如DB、或者持久化KV存储去做高可用方案的话可能都会涉及到主从复制这样一个模块。

所以我们想说能不能把主从模块从消息中间件中剥离出来,写成一个相对独立的模块。从确定这么做到完成第一个可以run的版本,花了两周时间,其中有8、9天在进行设计和领域建模(核心实体的定义),编码也就4、5天的样子。这也是这个版本和之前版本最大的区别,我们花了大量的时间去抽象实体,最后在编码上反而会简单很多;而之的版本抽象层次太低,有太多过程化的编码,虽然能run也没什么问题,但总是不够“优雅”。

说了这么多其实是想说,定义好实体基本上可以说完成项目编码的百分之三四十了。好的实体定义(领域模型)会让之后系统的实现变得简单。

废话说了这么多,接着谈一谈消息中间件中一些重要的实体和组件。

消息

Message

消息实体是消息中间件中最重要的对象了,关乎到用户能写入什么、消费什么,关乎到索引结构的设计。

一条消息最基础的属性有:

  • topic
  • content\body

topic表示这条消息属于哪个主题,这样最终Consumer可以通过订阅这个topic来消费这条消息。content或body,消息内容或消息体(RocketMQ是body,我们习惯叫content),它是一个byte数组。因为作为消息中间件我们只会去存储数据,数据的编解码是有用户自己决定的。

出去最最基础的这两个属性,在使用消息中间件时往往会有过滤的需求。比如可能交易业务会将所有的订单发送到一个topic,这时下游的业务方需要关注自己的业务,可能一些是需要处理虚拟商品的业务,一些是需要处理特普通商品的,这样就需要每个业务方能过滤出自己需要的消息。

所以Message往往会有一个tag属性:

  • topic
  • tag
  • content\body

用于做消息过滤。tag属性是一个String类型的,每条消息可以有一个tag,我们称为打标,Consumer在订阅消息的时候可以指定自己需要的一批tag。

RocketMQ中(开源版本)也这样去实现了,但是它将消息所有的属性放入到一个Map中:

  • properties:Map<String,String>

(不知道RocketMQ有没有支持多tag的版本,我们遇到过希望消息有多个tag的情况。这也是个挺正常的需求,比如可以从不同维护划分消息,比如支付类型+商品类型等,过滤的时候是一个and的逻辑,这个可以作为一个功能提升的考虑)

RocketMQ的Message properties中还有key、delaylevel、waitstore等属性,分别用于查询消息、设置延迟投递、是否等待刷盘等。

以上是暴露给用户的Message对象的基础属性,也决定了用户能执行的操作无非是配置上面一些内容。

MessageExt

Message是基础的消息,对于系统内部发送和消费时这些属性是不够的,所以内部回去拓展一个MessageExt,包含额外的一些属性:

  • id:消息的ID,可以考虑能否用一个long类型来做成全局唯一的,这样可以基于它做幂等之类的操作
  • queueId:目标的队列ID(这条消息最终落到哪个分区中——分区即队列,每个分区都是一个先进先出的队列)
  • bornTime:消息的产生时间
  • bornAddress:消息的产生地址
  • storeTime:消息的存储时间
  • crc:crc校验
  • ...

主题

Topic

主题相关的,最基础的实体是Topic,它描述了主题最基础的属性,比如名称、负责人等。

  • name
  • owner

owner信息可以是topic所属的团队或责任人等,主要用户在发生异常或其他需要人工反馈的场景下,能找到对应的人或者发送告警。

RocketMQ中对应的是TopicConfig实体,描述了主题最基础的属性:

  • topicName
  • readQueueNums
  • writeQueueNums
  • perm:读写模式
  • topicFilterType:过滤类型(只支持单tag,尚不支持多tag)
  • topicSysFlag:系统属性
  • order:是否顺序?

其中一些属性并没有很理解,比如readQueueNums和writeQueueNums,一个topic不应该有多少读的队列就有多少写的队列吗?(没有实践中使用RocketMQ的经验,还望了解的同学指教)

Topic元数据

和主题相关的最重要的实体应该是队列的分布情况,即一个Topic包含了哪些队列,把这个元数据暂且成为TopicMeta。

一个TopicMeta对象需要有队列的部分情况,这样,

  • 在发送时,根据消息的topic属性,获取到TopicMeta再从中获取队列信息,然后写入到特定的队列中
  • 在消费时,获取队列信息,然后从每个队列中获取数据

在第一次考虑这个实体的时候,它大概是这个样子的:

  • Topic topic:包含一个Topic实体,表明基础信息
  • int queueNums:包含的队列数
  • List broker:分布的Broker节点

这个结构能满足需求。

Producer拿到TopicMeta后,根据brokers.size * queueNums得到总分区数,每次发送消息时根据一定的路由策略选择一个分区(队列)作为目标分区进行写入。

Consumer拿到TopicMeta后,知道所有的broker,知道分区数,这样就知道了所有的分区情况(每个Broker上同一个Topic拥有相同数据的分区,编号为[0, queueNums-1]),能建立所有分区的消费关系。

但是在不断的实践中,发现这种模式并不是一种很好的抽象:

  1. 在对Topic进行扩容和缩容的时候,只能以Broker为单位,即每次扩容或缩容的分区数都是queueNums的倍数
  2. 隐含了一层关系,即客户端知道总分区数的计算规则和分区的分布规则

对TopicMeta的抽象应该是真实的描述Topic的队列的分布情况,所以TopicMeta应该包含所有的队列的分布情况,应该包含一个Set或List集合,里面包含了所有的队列。

TopicMeta

  • Topic topic
  • Set/List queues:队列信息(Queue描述了自身的信息)

Kafka的实现中是Topic信息包含了所有队列的信息,使用了一个Map去存储,Key是一个Integer,应该是Partition的ID。

队列

Queue是消息聚合的最小单位,一个Queue应该反映出自身所处的物理地址,这样可以进行写入和消费,另外应该包含一些状态来描述是否可读可写。另外应该有它的备份信息(高可用是每个部分都应该考虑的),即这个队列的备份队列分布等。

Kafka中这个对象叫TopicPartitionInfo,包含属性如下:

  • int partition
  • Node leader
  • List<Node> replicas
  • List<Node> isr

这个实体定义相对来说是比较好的,描述了这个队列当前的Leader,它的备份,也就是每个队列都是可以进行主备切换的(回想一下,Kafka中每个Broker相互备份Partition的,而不是Broker之间的主从备份)。在客户端也不会隐含什么规则,而是直接根据路由策略来使用分区(队列)。

小结

消息中间件模型中远远不止上面这一些实体,但是不希望篇幅太长(看起来太累),所以打算拆开成几篇。

这篇主要是基础的实体,下一篇会写和核心流程相关的一些实体,主要会是路由、数据读取等。

时间: 2024-10-16 02:12:38

消息中间件核心实体(0)的相关文章

消息中间件activemq-5.13.0整合spring

首先说明这里是在qctivemq配置好并启动服务的情况下进行,请先自行配置好.也可关注我的博文(消息中间件qctivemq安全验证配置)进行配置. 1.首先看一下项目结构 2.所需jar包,这里只列出mq相关jar包,spring相关不与说明. 3.消息生产service  QueueMessageProducer package cn.carowl.activemq; import javax.jms.Destination; import javax.jms.JMSException; im

消息中间件activemq-5.13.0安全验证配置

activemq分为控制端和客户端,下面分别介绍安全认证配置方法. 1.控制端安全配置 (1). ActiveMQ目录conf下找到jetty.xml: <bean id="securityConstraint" class="org.eclipse.jetty.util.security.Constraint"> <property name="name" value="BASIC" /> <p

【.NET】EF框架之Entity Framework的核心--EDM设计器

上篇博客初步认识EF,总是在说EDM,到底什么是EDM呢?下面我们就来揭开它神秘的面纱:   xml中那些"乱七八糟"的代码. Entity Data Model就是所谓的实体数据模型,也就是EDM.在VS中添加ADO.net实体数据模型就可以直接画实体,向上可以方便我们的开发,向下直接映射到数据库,开发人员操作实体无须了解数据库表结构.下面就是.edmx中的两个实体了,我们这里不涉及数据库的概念,而是用一个叫做DBContext的上下文对象表示这些实体的集合. EDM设计器可以设计上

Quartz.NET 2.0 学习笔记(1) :Quartz.NET简介

转自:http://www.cnblogs.com/lzrabbit/archive/2012/04/13/2447609.html Quartz.NET 项目地址 http://quartznet.sourceforge.net/ Quartz.NET 2.0 学习笔记(1) :Quartz.NET简介 Quartz.NET 2.0 学习笔记(2) :和1.0的几点不同 Quartz.NET 2.0 学习笔记(3) :通过配置文件实现任务调度 Quartz.NET 2.0 学习笔记(4) :c

Kong(V1.0.2) Clustering Reference

介绍 Kong集群允许您通过添加更多的机器来处理更多的传入请求来水平扩展系统.它们将共享相同的配置,因为它们指向相同的数据库.指向相同数据存储的Kong节点将是相同Kong集群的一部分. 您需要在Kong集群前面有一个负载均衡器,以便跨可用Kong节点分发流量. 一个Kong集群能做什么,不能做什么 拥有一个Kong集群并不意味着您的客户端流量将立即在您的Kong节点之间进行负载均衡.在Kong节点前面仍然需要一个负载均衡器来分配流量.相反,Kong集群意味着这些节点将共享相同的配置. 出于性能

程序员的自我救赎---3.1:理解Oauth2.0

<前言> (一) Winner2.0 框架基础分析 (二)PLSQL报表系统 (三)SSO单点登录 (四) 短信中心与消息中心 (五)钱包系统 (六)GPU支付中心 (七)权限系统 (八)监控系统 (九)会员中心 (十) APP版本控制系统 (十一)Winner前端框架与RPC接口规范讲解 (十二)上层应用案例 (十三)总结 <理解Oauth2.0> 关于SSO分两个篇章来讲,先讲讲Oauth2.0,之前还特地百度了一下Oauth怎么读,我们每次交流的时候都直接读字母O·A·U·T

.Net Core 3.0 关于Windows Form和WPF的全面支持

引言 ".NET 核心是开源和跨平台.您可以使用 .NET Core 在 Windows.Mac.十几个 Linux.iPhone.IoT 设备等上运行服务器应用程序! .NET 酷睿是开源.跨平台和快速的.今天就出来了完全支持.开源,是的,但完全支持与微软的全部重量. 与 .NET 核心 3.0 一起,C# 8.0 今天就已推出!它也是开源的,是你们许多人用来制作应用程序的语言.Visual Studio 16.3 同时支持 C# 8.0 和 .NET 核心 3.0,并为所有新的 .NET 酷

大型网站技术

大型网站开发 网站架构 缓存和数据一致性 分布式事务 负载均衡和高可用 微服务 消息队列 秒杀系统 大型网站特点 海量数据 高并用 高可用 需求多 容量的估算 常见容量估算:数据量 并发量 带宽 CPU|MEM|DISK 容量评估步骤 1.评估总访问量 2.评估平均访问量 QPS 3.评估高峰 QPS 4.评估系统 单机极限 5.计算容量 常见性能测试方案 ab JMeter LoadRunner 系统负载 System Load :系统CPU繁忙程度的度量 有多少进程在等待被CPU调用 (进程

Erlang 104 OTP - incomplete

笔记系列 Erlang环境和顺序编程Erlang并发编程Erlang分布式编程YawsErlang/OTP 日期              变更说明 2014-12-21 A Outline, 1 Agenda 0 Scope 围绕OTP设计原则,分别记录行为模式.监督树概念.应用.发布和部署,以及[3]中一个产品级缓存解决方案. 1 OTP Design Principles Erlang Doc: OTP Design Principles User's Guide OTP设计原则阐述的是如