随着互联网的快速发展,即时通讯应用在我们的日常生活中愈发普及。 WhatsApp、微信、Telegram 等即时通讯应用已经成为人们生活中不可或缺的一部分。而这些平台之所以能够成为用户的首选,离不开高效稳定的后台技术支持。因此,在搭建即时通讯平台时,如何设计高效稳定的数据库成为非常重要的问题。本文将从 IM 大数据库的设计入手,探讨构建高效稳定的即时通讯平台的方法。
一、IM 大数据库的设计
1. 数据库的类型
MySQL 是一个开源的关系型数据库管理系统,它被广泛地应用在 Web 应用开发中。在 IM 大数据库的选型中,选择 MySQL 是比较合适的。因为 MySQL 的优势在于它是轻量级的、易于使用的、可扩展的,并且被广泛支持。
2. 数据库的架构
IM 大数据库的架构应该分为两个分层。之一层是主数据库,它存放着所有的数据。第二层是读写分离服务器,它负责将主数据库的数据分发到各个读服务器中。
3. 数据库的表
IM 大数据库的表设计应该尽量遵循以下原则:将需要关联的字段存放在同一张表中,避免null值的产生,将经常使用的字段创建索引。对于 MySQL 数据库而言,适当地使用 InnoDB 引擎和 MyISAM 引擎是可以提升性能的。对于关系表中要经常进行的查、改操作应该采用 InnoDB 引擎,对于读取比较多而写入比较少的表,应该采用 MyISAM 引擎。
4. 数据库的存储
IM 大数据库的存储能够直接关系到系统的性能和稳定性。在存储方面,Redis 是一款非常聚合的存储系统,它是一款基于内存超高性能的键值对存储系统。在 IM 大数据库的存储方案上,可以考虑使用 Redis 作为缓存服务器,将 Redis 和 MySQL 一起使用并相互协作,提高整个系统的性能。
二、构建高效稳定的即时通讯平台
1. 消息服务
消息服务是即时通讯平台中非常重要的一部分,它需要实时高效地传输信息。在构建消息服务时,需要考虑到消息的格式、编码和解码方式。同时,消息服务需要考虑到服务器的集群部署和高可用性,避免任何一个节点出现故障导致整个系统崩溃。
2. 负载均衡
在构建即时通讯平台时,需要考虑到负载均衡来避免系统瓶颈。因此,在服务器的架构中应该考虑使用负载均衡器来分配不同的请求到不同的服务器上,从而达到平衡服务器负载的目的。
3. 安全性
安全性是构建即时通讯平台过程中需要重点考虑的问题。在设计时,需要考虑账户登录的安全问题、消息传输的安全问题和数据存储的安全问题。具体实现方面可以采用 SSL/TLS 加密算法、密码哈希算法等技术加强平台的安全性。
4. 可扩展性
在构建即时通讯平台时,我们需要考虑到平台的未来发展。因此,在设计方案时应该考虑可扩展性。即时通讯平台应该有不同的模块,可以动态扩展或者去除这些模块。
5. 数据备份和恢复
对于任何一个系统而言,数据都是非常重要的。在构建即时通讯平台时,数据备份和恢复应该是必备的。数据备份和恢复可以采用备份数据库、定期备份相关关键数据等方式来保障数据的安全。
三、
在设计和构建 IM 大数据库时应该遵循以下原则:选择合适的数据库类型、设计合理的数据库架构和表结构、采用合适的存储方式、保障消息服务的高效可靠性、使用负载均衡器平衡服务器负载、加强平台的安全性、保证平台的可扩展性和备份数据以确保数据的安全。在遵循这些原则的同时,我们可以构建出高效稳定的即时通讯平台。
相关问题拓展阅读:
- 如何设计数据库?
- 教你设计大型Oracle数据库
- 为自己搭建一个分布式 IM(即时通讯) 系统
如何设计数据库?
系统磨做架构师:数据库系统瞎桥衡之数据库设计方法、基本步消丛骤和需求分析
方法/步骤
常见数据库设计
请点击输入图片描述
一主多从
冗余读库带来的副作用:读写有延时,可能不一致;写仍然是单点隐判,不能保证写高可用。
请拆携明点击输入图片描述
主库冗余
存在数据不一致问题
请点击输入图旅告片描述
数据读取速度
请点击输入图片描述
利用缓存来实现
请点击输入图片描述
常见缓存设计如下
请点击输入图片描述
教你设计大型Oracle数据库
本文教你如何设计大型Oracle数据库 希望对大家有所帮助
一 概论
超大型系统的特点为
处理的用户数一般都超过百万 有的还超过千万 数据库的数据量一般超过 TB;
系统必须提供实时响应功能 系统需不停机运行 要求系统有很高的可用性及可扩展性
为了能达到以上要求 除了需要性能优越的计算机和海量存储设备外 还需要先进的数据库结构设计和优化的应用系统
一般的超大型系统采用双机或多机集群系统 下面以数据库采用Oracle 并行服务器为例来谈谈超大型数据库设计方法
确定系统的ORACLE并行服务器应用划分策略迅盯
数据库物理结构的设计
系统硬盘的划分及分配
备份及恢复策略的考虑
二 Oracle并行服务器应用划分策略
Oracle并行服务器允许不同节点上的多个INSTANCE实例同时访问一个数据库 以提高系统的可用性 可扩展性及性能 Oracle并行服务器中的每个INSTANCE实例都可将共享数据库中的表或索引的数据块读入本地的缓冲区中 这就意味着一个数据块可存在于多个INSTANCE实例的SGA区中 那么保持这些缓冲区的数据的一致性就很哗亮重要 Oracle使用 PCM( Parallel Cache Management)锁维护缓冲区的一致性 Oracle同时通过I DLM(集成的分布式锁管理器)实现PCM 锁 并通过专门的LCK进程实现INSTANCE实例间的数据一致
考虑这种情况 INSTANCE 对BLOCK X块修改 这时INSTANCE 对BLOCK X块也需要修改 Oracle并行服务器利用PCM锁机制 使BLOCK X从INSTANCE 的SGA区写入数据库数据文件中 又从数据文件中把BLOCK X块读入INSTANCE 的SGA区中 发生这种情况即为一个PING PING使原来 个MEMORY IO可以完成的工作变成 个DISK IO和 个 MEMORY IO才能够完成 如果系统中有过多的PING 将大大降低系统的性能
Oracle并行服务器中的每个PCM锁可管理多个数据块 PCM锁管理的数据块的个数与分配给一个数据文件的PCM锁的个数及该数据文件的大小有关 当INSTANCE 和INSTANCE 要操作不同的BLOCK 如果这些BLOCK 是由同一个PCM锁管理的 仍然会发生PING 这些PING称为FALSE PING 当多个INSTANCE访问相同的BLOCK而产生的PING是TRUE PING
合理的应用划分使不同的应用访问不同的数据 可避免或减少TRUE PING;通过给FALSE PING较多的数据文件分配更多的PCM锁可减少 FALSE PING的次数 增加PCM锁不能减少TRUE PING
所以 Oracle并行服务器设计的目的是使系统交易处理合理的分布在INSTANCE实例间 以最小化PING 同时合理的分配PCM锁 减少FALSE PING 设计的关键是找出可能产生的冲突 从而决定应用划分的策略 应用划分有如下四种方法
根据功能模块划分 不同的节点运行不同的应用
根据用户划分 不同类型的用户运行在不同的节点上
根据数据划分 不同的节点访问不同的数据或索引
根据时间划分 不同的应用在不同的时间段运行
应用划分的两个重要原则是使PING最小化及使各节点的负载大致均衡
三 数据库物理结构的设计
数据库物理结构设计包括确定表及索引的物理存储参数 确定及分配数据亩芦和库表空间 确定初始的回滚段 临时表空间 redo log files等 并确定主要的初始化参数 物理设计的目的是提高系统的性能 整个物理设计的参数可以根据实际运行情况作调整
表及索引数据量估算及物理存储参数的设置
lishixinzhi/Article/program/Oracle/202311/18944
为自己搭建一个分布式 IM(即时通讯) 系统
CIM(CROSS-IM) 一款面向开发者的 IM(即时通讯)系统;同时提供了一些组件帮助开发者构建一款属于自己可水平扩展的 IM 。
借助 CIM 你可以实现以下需求:
下面来看看具体的架构设计。
整体主要由以下模块组成:
cim-server
IM 服务端;用于接收 client 连接、消息透传、消息推送等功能。
支持集群部署。
cim-forward-route
消息路由服务器;用于处理消息路由、消息转发、用户登录、用户下线以及一些运营工具(获取在线用户数等)。
cim-client
IM 客户端;给用户使用的消息终端,一个命令即可启动并向其他人发起通讯(群聊、私聊);同时内置了一些常用命令方便使用。
整体的流程也比较简单,流程图如下:
所以当我们自己部署时需要以下步骤:
接下来重点看看具体的实现,比如群聊、私聊消息如何流转;IM 服务端负载均衡;服务如何注册发现等等。
IM 服务端
先来看看服务端;主要是实现客户端上下线、消息下发等功能。
首先是服务启动:
由于是在 SpringBoot 中搭建的,所以在应用启动时需要启动 Netty 服务。
从 pipline 中可以看出使用了 Protobuf 的编解码(具体报文在客户端中分析)。
注册发现
需要满足 IM 服务端的水平扩展需求,所以 cim-server 是需要将自身数据发布到注册中心的。
所以在应用启动成功后需要将自身数据注册到 Zookeeper 中。
最主要的目的就是将当前应用的 ip + cim-server-port+ http-port 注册上去。
上图是我在演示环境中注册的两个 cim-server 实例(由于在一台服务器,所以只是端口不同)。
这样在客户端(监听这个 Zookeeper 节点)就能实时的知道目前可用的服务信息。
登录
当客户端请求 cim-forward-route 中的登录接口(详见下文)做完业务验证(就相当于日常登录其他网站一样)之后,客户端会向服务端发起一个长连接,如之前的流程所示:
这时客户端会发送一个特殊报文,表明当前是登录信息。
服务端收到后就需要将该客户端的 userID 和当前 Channel 通道凳正告关系保存起来。
同时也缓存了用户的信息,也就是 userID 和 用户名。
离线
当客户端断线后也需要将刚才缓存的信息清除掉。
同时也需要调用 route 接口清除相关信息(具体接口看下文)。
IM 路由
从架构图中可以看枣明出,路由层是非常重要的一环;它提供了一系列的 HTTP 服务承接了客户端和服务端。
目前主要是以下几个接口。
注册接口
由于每一个客户端都是需要登录才能使用的,所以清枝之一步自然是注册。
这里就设计的比较简单,直接利用 Redis 来存储用户信息;用户信息也只有 ID 和 userName 而已。
只是为了方便查询在 Redis 中的 KV 又反过来存储了一份 VK,这样 ID 和 userName 都必须唯一。
登录接口
这里的登录和 cim-server 中的登录不一样,具有业务性质,
为了实现只能一个用户登录,使用了 Redis 中的 set 来保存登录信息;利用 userID 作为 key ,重复的登录就会写入失败。
获取一台可用的路由实例也比较简单:
当然要获取 Zookeeper 中的服务实例前自然是需要监听 cim-server 之前注册上去的那个节点。
具体代码如下:
也是在应用启动之后监听 Zookeeper 中的路由节点,一旦发生变化就会更新内部缓存。
群聊接口
这是一个真正发消息的接口,实现的效果就是其中一个客户端发消息,其余所有客户端都能收到!
流程肯定是客户端发送一条消息到服务端,服务端收到后在上文介绍的 SessionSocketHolder 中遍历所有 Channel(通道)然后下发消息即可。
服务端是单机倒也可以,但现在是集群设计。所以所有的客户端会根据之前的轮询算法分配到不同的 cim-server 实例中。
因此就需要路由层来发挥作用了。
路由接口收到消息后首先遍历出所有的客户端和服务实例的关系。
路由关系在 Redis 中的存放如下:
由于 Redis 单线程的特质,当数据量大时;一旦使用 keys 匹配所有 cim-route:* 数据,会导致 Redis 不能处理其他请求。
所以这里改为使用 scan 命令来遍历所有的 cim-route:*。
接着会挨个调用每个客户端所在的服务端的 HTTP 接口用于推送消息。
在 cim-server 中的实现如下:
cim-server 收到消息后会在内部缓存中查询该 userID 的通道,接着只需要发消息即可。
在线用户接口
这是一个辅助接口,可以查询出当前在线用户信息。
实现也很简单,也就是查询之前保存 ”用户登录状态的那个去重 set “即可。
私聊接口
之所以说获取在线用户是一个辅助接口,其实就是用于辅助私聊使用的。
一般我们使用私聊的前提肯定得知道当前哪些用户在线,接着你才会知道你要和谁进行私聊。
类似于这样:
在我们这个场景中,私聊的前提就是需要获得在线用户的 userID。
所以私聊接口在收到消息后需要查询到接收者所在的 cim-server 实例信息,后续的步骤就和群聊一致了。调用接收者所在实例的 HTTP 接口下发信息。
只是群聊是遍历所有的在线用户,私聊只发送一个的区别。
下线接口
一旦客户端下线,我们就需要将之前存放在 Redis 中的一些信息删除掉(路由信息、登录状态)。
IM 客户端
客户端中的一些逻辑其实在上文已经谈到一些了。
登录
之一步也就是登录,需要在启动时调用 route 的登录接口,获得 cim-server 信息再创建连接。
登录过程中 route 接口会判断是否为重复登录,重复登录则会直接退出程序。
接下来是利用 route 接口返回的 cim-server 实例信息(ip+port)创建连接。
最后一步就是发送一个登录标志的信息到服务端,让它保持客户端和 Channel 的关系。
自定义协议
上文提到的一些登录报文、真正的消息报文这些其实都是在我们自定义协议中可以区别出来的。
由于是使用 Google Protocol Buffer 编解码,所以先看看原始格式。
其实这个协议中目前一共就三个字段:
目前主要是三种类型,分别对应不同的业务:
心跳
为了保持客户端和服务端的连接,每隔一段时间没有发送消息都需要自动的发送心跳。
目前的策略是每隔一分钟就是发送一个心跳包到服务端:
这样服务端每隔一分钟没有收到业务消息时就会收到 ping 的心跳包:
内置命令
客户端也内置了一些基本命令来方便使用。
比如输入 :q 就会退出客户端,同时会关闭一些系统资源。
当输入 :olu(onlineUser 的简写)就会去调用 route 的获取所有在线用户接口。
群聊
群聊的使用非常简单,只需要在控制台输入消息回车即可。
这时会去调用 route 的群聊接口。
私聊
私聊也是同理,但前提是需要触发关键字;使用 userId;;消息内容 这样的格式才会给某个用户发送消息,所以一般都需要先使用 :olu 命令获取所以在线用户才方便使用。
消息回调
为了满足一些定制需求,比如消息需要保存之类的。
所以在客户端收到消息之后会回调一个接口,在这个接口中可以自定义实现。
因此先创建了一个 caller 的 bean,这个 bean 中包含了一个 CustomMsgHandleListener 接口,需要自行处理只需要实现此接口即可。
自定义界面
由于我自己不怎么会写界面,但保不准有其他大牛会写。所以客户端中的群聊、私聊、获取在线用户、消息回调等业务(以及之后的业务)都是以接口形式提供。
也方便后面做页面集成,只需要调这些接口就行了;具体实现不用怎么关心。
cim 目前只是之一版,BUG 多,功能少(只拉了几个群友做了测试);不过后续还会接着完善,至少这一版会给那些没有相关经验的朋友带来一些思路。
欢迎工作一到五年的Java工程师朋友们加入Java程序员开发:
群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用”没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!
im大数据库设计的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于im大数据库设计,IM大数据库设计 | 构建高效稳定的即时通讯平台,如何设计数据库?,教你设计大型Oracle数据库,为自己搭建一个分布式 IM(即时通讯) 系统的信息别忘了在本站进行查找喔。