场景描述:
我们的IM软件有PC端和手机端.
同时在线的用户,通过长连接转发,并且存储消息.
接收方不在线,存储消息.
用户打开电脑端软件或者手机端网络掉线重新连接,都需要获取未读消息数量.当用户点击未读消息的时候,提供消息正文.

经过抽象,JAVA这块需要提供两个接口
1.获取用户的未读消息列表
2.给定发送方ID和接收方ID,返回消息内容.

发送方用户ID  srcid
接收方用户ID  destid
每个会话的当前消息ID  mid(针对每个发送方和接收方,自增)

1.发送方用户通过电脑将消息发送至Web服务器.消息主要内容(srcid,destid,msg)

2.Web服务器根据srcid,destid获取会话的mid(会话状态的自增ID)

3.将消息放入持久化队列,并且更新redis未读消息列表
首先将(srcid,destid,mid,msg)放入持久化队列.
然后更新redis的用户未读消息列表.

未读消息列表在Redis的存储结构如下.

在接收方ID的前面增加一个前缀,表明是手机未读消息还是PC未读消息.这个作为key
value是一个HashMap.这个HashMap的key是发送方ID,value是未读消息数量.
一旦用户登录,直接拉取该用户的HashMap内容展示.

这部分内容是有过期时间的,假如用户长时间未使用.这个PC-destid和Mobile-destid的条目将被删除.
如果程序发现这个条目不存在.则去数据库中查询未读消息列表.

假如我的ID是1000,老板的ID是1001,老板给我发送了三条消息,但是我一直没有在线.
程序将做如下操作.
127.0.0.1:6379> HINCRBY pc-1000 1001 1
(integer) 1
127.0.0.1:6379> HINCRBY pc-1000 1001 1
(integer) 2
127.0.0.1:6379> HINCRBY pc-1000 1001 1
(integer) 3

127.0.0.1:6379> HINCRBY mobile-1000 1001 1
(integer) 1
127.0.0.1:6379> HINCRBY mobile-1000 1001 1
(integer) 2
127.0.0.1:6379> HINCRBY mobile-1000 1001 1
(integer) 3

如果我登录手机客户端,点击未读消息.则对Redis操作如下,删除对应条目
127.0.0.1:6379> hdel mobile-1000 1001
(integer) 1
127.0.0.1:6379> 
并且回写数据库一个状态标识(已读的最大mid).这个回写数据库的过程,也是异步的,每隔30s回写一次数据库状态.

这个时候,我登录PC端,还是可以查看未读消息数量的.这个业务要求有点奇怪.但是要求就是这么做.

4.如果发送方的其他设备在线,或者接收方的设备在线,则转发消息.

5.JAVA从队列中异步获取消息,然后批量Insert到数据库.

数据库存储设计
初始设计使用4台MySQL分库.使用(发送方用户ID+接收方用户ID) mod 64
这样的好处是,A用户发送B用户和B用户发送A用户的消息,都会落在同一个底层数据库.
这样获取A,B之间的聊天内容,使用一个SQL查询即可.

聊天消息表,本身也是按照时间进行分区

  1. createtable chat_msg(
  2. id bigint auto_increment,
  3. srcid bigint notnull,
  4. destid bigint notnull,
  5. mid bigint notnull,
  6. msg TEXT,
  7. ts timestamp notnulldefaultcurrent_timestamp,
  8. hashvalue tinyintnotnull,
  9. primarykey(id,ts)
  10. )partitionby range(UNIX_TIMESTAMP(ts))
  11. (
  12. partition p201511VALUES LESS THAN(UNIX_TIMESTAMP('2015-11-01 00:00:00')),
  13. partition p201512VALUES LESS THAN(UNIX_TIMESTAMP('2015-12-01 00:00:00')),
  14. partition p201601VALUES LESS THAN(UNIX_TIMESTAMP('2016-01-01 00:00:00'))
  15. );

用户状态表
sessionId是聊天双方,(较小的ID在前,较大的ID在后) 的会话状态信息
pcMid是用户pc端已读的最大消息ID
mobileMid是用户手机端已读的最大消息ID
hashvalue是 (发送方用户ID+接收方用户ID ) mod 64 计算后的值.暂时没有用.

  1. createtable read_chat_mid(
  2. id bigint primarykey auto_increment,
  3. uid bigintnotnull,
  4. sessionId varchar(45)notnull,
  5. pcMid bigint notnulldefault 0,
  6. mobileMid bigint notnulldefault 0,
  7. hashvalue tinyintnotnull,
  8. ts timestamp notnulldefaultcurrent_timestampon update current_timestamp
  9. );

获取用户未读消息的SQL如下.

  1. createindex inx_1on chat_msg(ts,srcid,destid,mid);
  2. createuniqueindex inx_2on read_chat_mid(uid,sessionId);

查询用户1,2之间的聊天内容

  1. select mid,srcid,destid,msgpb,tsfrom im_0.chat_msg_3where idin(
  2. select t.idfrom(
  3. select t1.idfrom
  4. (
  5. (select id from im_0.chat_msg_3where srcid=1and destid=2
  6. and ts>now()-interval'1' month
  7. and mid>ifnull((select mobileMid from im_0.read_chat_mid_3where sessionId='1,2'anduid=1),0)orderby tsdesc limit 200)
  8. unionall
  9. (select id from im_0.chat_msg_3where srcid=2and destid=1
  10. and ts>now()-interval'1' month
  11. and mid>ifnull((select mobileMid from im_0.read_chat_mid_3where sessionId='1,2'anduid=1),0)orderby tsdesc limit 200)
  12. )as t1orderby iddesc limit 200
  13. )as t
  14. )orderby middesc;

系统性能评估

MySQL基本配置
innodb_buffer_pool_size=512m
innodb_flush_log_at_trx_commit =0
sync_binlog=0
innodb_support_xa=0
log_bin=master

下面是工作环境测试,在生产服务器上使用raid10,IO能力还会进一步提升.
每个月每台数据库服务器 在200w记录之前,使用Load File接口,每秒Insert可以达到 1.7w左右
每个月每台数据库服务器 在800w记录之前,使用Load File接口,每秒Insert可以达到 1.1w左右
可以认为系统每秒Insert至少在4w以上.
理论上的系统最大处理能力至少在每秒64w以上.

即时聊天(IM)存储方案相关推荐

  1. 即时聊天app开发-即时通讯app开发方案分析

    如今,即时聊天APP层出不穷,它已经成为人们日常生活中密不可分的社交工具.如今,即时聊天APP不仅是聊天工具,也是企业营销的利器.我们经常可以在聊天主页上看到一些广告.如有必要,用户可以直接点击广告了 ...

  2. Web端即时聊天项目实现(基于WebSocket)

    Web端即时聊天项目实现 项目背景  其实这个项目算是我做过的花时间最长也投入心血最多的一个项目了,当时决定开始做这个的时候我几乎什么都不会,那时我个人的情况是: JavaEE方面: 会jsp+ser ...

  3. 要把微博、贴吧变成即时聊天,总共分几步?

    刷微博是许多人每天的"例行指部锻炼",一扫一划,就能评论热点话题,订阅热门动态.当然,也有不少人对明星不感兴趣,转而去刷 Reddit.贴吧.虎扑.知识星球或是其他 BBS 社区. ...

  4. uniapp结合腾讯云及时通信IM的聊天记录本地存储方案

    uniapp结合腾讯云及时通信IM的聊天记录本地存储方案 UniApp 是一个跨平台的应用开发框架,可以使用 Vue.js 开发多端应用(如H5.小程序.App等).在 UniApp 中,可以使用 u ...

  5. DAS、NAS、SAN、iSCSI 存储方案概述

    目前服务器所使用的专业存储方案有DAS.NAS.SAN.iSCSI几种.存储根据服务器类型可以分为:封闭系统的存储和开放系统的存储: (1)封闭系统主要指大型机. (2)开放系统指基于包括Window ...

  6. golang从简单的即时聊天来看架构演变

    前言 俗话说的好,架构从来都不是一蹴而就的,没有什么架构一开始设计就是最终版本,其中需要经过很多步骤的变化,今天我们就从一个最简单的例子来看看,究竟架构这个东西是怎么变的. 我将从一个最简单的聊天室的 ...

  7. ZBLOG即时聊天(客服)插件v1.3.2版本下载,强大的在线客服系统源码

    ZBLOG即时聊天(客服)插件v1.3.2版本下载,强大的在线客服系统源码 测试报告:本插件我已按照测试了,正常按照开启,插件配置可正常顺利保存,后台配置项无问题.不过因为本插件要配置的东西太多了,且 ...

  8. android简单即时聊天sdk

    android简单即时聊天sdk 切换用户登录的实现 联系人列表的实现 聊天页的实现 消息缓存与排序 消息接收和分发--数据库队列和投递队列 有序列表的维护 切换用户登录的实现 由于不同的登录用户需要 ...

  9. uni-app 即时聊天:朋友圈

    在写uni-app即时聊天项目的时候,就想着用uni-app实现微信朋友圈的功能,在完成这些功能的时候,也遇到了很多的问题,比如数据表的设计(个人动态表,朋友圈动态表,通知表等),因为也是第一次去制作 ...

最新文章

  1. 1003 我要通过!
  2. 部署在IIS上的网站如何调试
  3. 使用阿里云OSS上传文件
  4. SQL判断NULL的几种常见方式
  5. Centos 配置Red5流媒体服务器
  6. t30智能插座怎么设置_如何设置ConnectSense智能插座
  7. ipad如何连接电脑_电脑无法连接外网远程调试,一文教你如何用手机让台式机连接外网...
  8. mysql有dataguard吗_Oracle查看是否搭建DataGuard
  9. 使用了visual assist.net
  10. 商业银行会计学内容概述
  11. 让你的 commit 更有价值
  12. eclipse 图形界面设计技巧——JLabel
  13. html中如何使用input表单隐藏域?
  14. 解决sysman.mgmt_task_qtable ORA-600 kdsgrp1错误
  15. 华为云备份会上传私密相册吗_2 亿部华为手机背后,这个功能不能忽视
  16. HEVC编码技术简介
  17. 天池大赛——天猫用户复购预测
  18. 月入3k和月入3w的女生有什么区别?
  19. Spring 技术内幕读书笔记
  20. algorithm头文件下的常用函数-学习笔记

热门文章

  1. 手机红米5android7.11,红米5手机_红米5手机配置|价格【全解析】-太平洋IT百科
  2. ResNet详解与分析
  3. 微信[电脑版]如何更换默认通知铃声
  4. 最简单的 Git 入门教程
  5. 基于ARCGIS二次开发可视化开发环境搭建(JAVA)
  6. 【转】值得推荐的android开发框架简介
  7. Eclipse解决SVN版本冲突
  8. spark+mongodb大数据框架搭建
  9. 这些年,我与Google不得不说的那些事儿
  10. sct分散加载文件格式与应用