QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

现代 IM 系统中的消息系统架构——模型篇

  • 2019-05-17
  • 本文字数:2825 字

    阅读完需:约 9 分钟

现代IM系统中的消息系统架构——模型篇

前言

架构篇中我们介绍了现代 IM 消息系统的架构,介绍了 Timeline 的抽象模型以及基于 Timeline 模型构建的一个支持『消息漫游』、『多端同步』和『消息检索』多种高级功能的消息系统的典型架构。架构篇中为了简化读者对 Tablestore Timeline 模型的理解,概要性的对 Timeline 的基本逻辑模型做了介绍,以及对消息系统中消息的多种同步模式、存储和索引的基本概念做了一个科普。


本篇文章是对架构篇的一个补充,会对 Tablestore 的 Timeline 模型做一个非常详尽的解读,让读者能够深入到实现层面了解 Timeline 的基本功能以及核心组件。最后我们还是会基于 IM 消息系统这个场景,来看如何基于 Tablestore Timeline 实现 IM 场景下消息同步、存储和索引等基本功能。

Timeline 模型

Timeline 模型以『简单』为设计目标,核心模块构成比较清晰明了,主要包括:


  • Store:Timeline 存储库,类似数据库的表的概念。

  • Identifier:用于区分 Timeline 的唯一标识。

  • Meta:用于描述 Timeline 的元数据,元数据描述采用 free-schema 结构,可自由包含任意列。

  • Queue:一个 Timeline 内所有 Message 存储在 Queue 内。

  • Message:Timeline 内传递的消息体,也是一个 free-schema 的结构,可自由包含任意列。

  • Index:包含 Meta Index 和 Message Index,可对 Meta 或 Message 内的任意列自定义索引,提供灵活的多条件组合查询和搜索。

Timeline Store


Timeline Store 是 Timeline 的存储库,对应于数据库内表的概念。上图是 Timeline Store 的结构图,Store 内会存储所有的 Timeline 数据。Timeline 是一个面向海量消息的数据模型,同时用于消息存储库和同步库,需要满足多种要求:


  • 支撑海量数据存储:对于消息存储库来说,如果需要消息永久存储,则随着时间的积累,数据规模会越来越大,需要存储库能应对长时间积累的海量消息数据存储,需要能达到 PB 级容量。

  • 低存储成本:消息数据的冷热区分是很明显的,大部分查询都会集中在热数据,所以对于冷数据需要有一个比较低成本的存储方式,否则随着时间的积累数据量不断膨胀,存储成本会非常大。

  • 数据生命周期管理:不管是对于消息数据的存储还是同步,数据都需要定义生命周期。存储库是用于在线存储消息数据本身,通常需要设定一个较长周期的保存时间。而同步库是用于写扩散模式的在线或离线推送,通常设定一个较短的保存时间。

  • 极高的写入吞吐:各类场景下的消息系统,除了类似微博、头条这种类型的 Feeds 流系统,像绝大部分即时通讯或朋友圈这类消息场景,通常是采用写扩散的消息同步模式,写扩散要求底层存储具备极高的写入吞吐能力,以应对消息洪峰。

  • 低延迟的读:消息系统通常是应用在在线场景,所以对于查询要求低延迟。


Tablestore Timeline 的底层是基于 LSM 存储引擎的分布式数据库,LSM 的最大优势就是对写入非常友好,天然适合消息写扩散的模式。同时对查询也做了极大优化,例如热数据进缓存、bloom filter 等等。数据表采用 Range Partition 的分区模式,能提供水平扩展的服务能力,以及能自动探测并处理热点分区的负载均衡策略。为了满足同步库和存储库对存储的不同要求,也提供了一些灵活的自定义配置,主要包括:


  • Time to live(数据生命周期):可自定义数据生命周期,例如永久保存,或者保存 N 天。

  • Storage type(存储类型):自定义存储类型,对存储库来说,HDD 是最好的选择,对同步库来说,SSD 是最好的选择。

Timeline Module


Timeline Store 内能存储海量的 Timeline,单个 Timeline 的详细结构图如上,可以看到 Timeline 主要包含了三大部分:


  • Timeline Meta:元数据部分,用于描述 Timeline,包括:

  • Identifier:用于唯一标识 Timeline,可包含多个字段。

  • Meta:用于描述 Timeline 的元数据,可包含任意个数任意类型的字段。

  • Meta Index:元数据索引,可对元数据内任意属性列建索引,支持多字段条件组合查询和检索。

  • Timeline Queue:用于存储和同步消息的队列,队列中元素由两部分组成:

  • Sequence Id:顺序 ID,队列中用于定位 Message 的位点信息,在队列中顺序 ID 保持递增。

  • Message:队列中承载消息的实体,包含了消息的完整内容。

  • Timeline Data:Timeline 的数据部分就是 Message,Message 主要包含:

  • Message:消息实体,其内部也可以包含任意数量任意类型字段。

  • Message Index:消息数据索引,可对消息实体内任意列做索引,支持多字段条件组合查询和检索。

IM 消息系统建模


以一个简易版 IM 系统为例,来看如何基于 Tablestore Timeline 模型建模。按照上图中的例子,存在 A、B、C 三个用户,A 与 B 发生单聊,A 与 C 发生单聊,以及 A、B、C 组成一个群聊,来看下在这个场景下消息同步、存储以及读写流程分别如何基于 Tablestore Timeline 建模。


消息同步模型


消息同步选择写扩散模型,能完全利用 Tablestore Timeline 的优势,以及针对 IM 消息场景读多写少的特性,通过写扩散来平衡读写,均衡整个系统的资源。写扩散模型下,每个接收消息的个体均拥有一个收件箱,所有需要同步至该个体的消息需要投递到其收件箱内。图上例子中,A、B、C 三个用户分别拥有收件箱,每个用户不同的设备端,均从同一个收件箱内拉取新消息。


消息同步库


收件箱存储在同步库内,同步库中每个收件箱对应一个 Timeline。根据图上的例子,总共存在 3 个 Timeline 作为收件箱。每个消息接收端保存有本地最新拉取的消息的 SequenceID,每次拉取新消息均是从该 SequenceID 开始拉取消息。对同步库的查询会比较频繁,通常是对最新消息的查询,所以要求热数据尽量缓存在内存中,能提供高并发低延迟的查询。所以对同步库的配置,一般是需要 SSD 存储。消息如果已经同步到了所有的终端,则代表收件箱内的该消息已经被消费完毕,理论上可以清理。但设计上来说不做主动清理,而是给数据定义一个较短的生命周期来自动过期,一般定义为一周或者两周。数据过期之后,如果仍要同步拉取新消息,则需要退化到读扩散的模式,从存储库中拉取消息。


消息存储库


消息存储库中保存有每个会话的消息,每个会话的发件箱对应一个 Timeline。发件箱内的消息支持按会话维度拉取消息,例如浏览某个会话内的历史消息则通过读取发件箱完成。一般来说,新消息通过在线推送或者查询同步库可投递到各个接收端,所以对存储库的查询会相对来说较少。而存储库用于长期存储消息,例如永久存储,相对同步库来说数据量会较大。所以存储库的选择一般是 HDD,数据生命周期根据消息需要保存的时间来定,通常是一个较长的时间。


消息索引库


消息索引库依附于存储库,使用了 Timeline 的 Message Index,可以对存储库内的消息进行索引,例如对文本内容的全文索引、收件人、发件人以及发送时间的索引等,能支持全文检索等高级查询和搜索。

总结

本篇文章主要对 Tablestore Timeline 模型进行了详解,介绍了 Timeline 各模块包括 Store、Meta、Queue、Data 和 Index 等,最后以一个简单的 IM 场景举例如何基于 Timeline 来建模。


本文作者:木洛


本文来源:阿里云云栖社区


来源链接:


https://yq.aliyun.com/articles/701593


2019-05-17 08:007283

评论

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

算法题学习---链表内指定区间反转

桑榆

算法题 10月月更 C++

观察者模式的基础原理

阿泽🧸

观察者模式 10月月更

一个“简单”的面试题:什么是环回地址127.0.0.1?

wljslmz

10月月更 127.0.0.1 环回地址

【web 开发基础】PHP 快速入门(9)-PHP 运算符之位运算符详解

迷彩

位运算 10月月更 PHP基础 PHP位运算

leetcode 191. Number of 1 Bits 位1的个数(简单)

okokabcd

LeetCode 数据结构与算法

Spring Boot「13」使用 Actuator

Samson

Java spring 学习笔记 spring-boot 10月月更

大家都在“卷”的推荐系统还有进步空间吗?看技术大牛们怎么说

小红书技术REDtech

Java实现随机人名抽取

魏铁锤

10月月更

Java领域又一神作!《凤凰架构》仅开源3小时,竟遭受Github万人哄抢

程序员小毕

程序员 架构 分布式 程序人生 系统设计

当我遇到10亿参数组合

FunTester

C# 线程的优先级

IC00

C# 学习 程序员 上位机 10月月更

MapReduce作业生命周期

穿过生命散发芬芳

mapreduce 10月月更

知识管理是团队的心脏,让企业管理更上一层楼

Baklib

文档 文档协同

Java | if语句和循环结构

陌上

ide Java、 10月月更

Vue.nextTick核心原理

yyds2026

Vue

Java之抽象类

魏铁锤

10月月更

【愚公系列】2022年10月 Go教学课程 038-异常处理

愚公搬代码

10月月更

“程”风破浪的开发者|APP自动化效果测试工具

芯动大师

学习方法 “程”风破浪的开发者 手机APP测试

C# 快捷菜单ConTextMenustrip控件学习

IC00

C# 学习 程序员 上位机 10月月更

DevOps|1024程序员节如何做?介绍下我的思路

laofo

DevOps 研发效能 1024程序员节 快手

Opencv 图像处理:数字图像的必会知识

timerring

OpenCV 计算机视觉 10月月更

企业文档过多如何管理?文档协同能够帮到你

Baklib

文档 文档管理

【LeetCode】分割数组Java题解

Albert

算法 LeetCode 10月月更

OpenCloudOS社区发起的程序员节专属系列活动

B Impact

SegmentFault 思否发布开源问答社区软件 Answer

万事ONES

1024里的小温暖,用技术让生活变得更美好!

阿里技术

1024程序员节

[极客大挑战 2019]Http 题解

w010w

Web HTTP CTF 10月月更

2022-10-24:以下go语言代码输出什么?A:3 3;B:3 4;C:0 0;D:0 1。 package main func main() { m := make(map[int]int

福大大架构师每日一题

golang 福大大 选择题

有没有完全自主的国产化数据库技术

王磊

【资损】分布式环境中的幂等性控制设计

小明Java问道之路

架构 微服务 安全 10月月更 资损

鸿蒙开发工具 DevEco Studio 3.0 体验与项目介绍

宇宙之一粟

HarmonyOS 鸿蒙应用开发 10月月更

现代IM系统中的消息系统架构——模型篇_架构_木洛_InfoQ精选文章