即時聊天(IM)儲存方案
單位即時聊天改版了.
正好趁著這次機會踢了MongoDB.
大家都拍手叫好..可見MongoDB這玩意多麼的不得人心...都覺得不好用..
場景描述:
我們的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查詢即可.
聊天訊息表,本身也是按照時間進行分割槽
使用者狀態表
sessionId是聊天雙方,(較小的ID在前,較大的ID在後) 的會話狀態資訊
pcMid是使用者pc端已讀的最大訊息ID
mobileMid是使用者手機端已讀的最大訊息ID
hashvalue是(傳送方使用者ID+接收方使用者ID) mod 64 計算後的值.暫時沒有用.
獲取使用者未讀訊息的SQL如下.
查詢使用者1,2之間的聊天內容
系統效能評估
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以上.
僅僅是四臺資料庫的情況,對於我們的業務.5年之內應該都不用考慮擴容的問題.
讓DBA做架構設計的好處是,不會把坑留在資料庫層面坑自己...
正好趁著這次機會踢了MongoDB.
大家都拍手叫好..可見MongoDB這玩意多麼的不得人心...都覺得不好用..
場景描述:
我們的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查詢即可.
聊天訊息表,本身也是按照時間進行分割槽
-
create table chat_msg(
-
id bigint auto_increment,
-
srcid bigint not null,
-
destid bigint not null,
-
mid bigint not null,
-
msg TEXT,
-
ts timestamp not null default current_timestamp,
-
hashvalue tinyint not null,
-
primary key (id,ts)
-
)partition by range(UNIX_TIMESTAMP(ts))
-
(
-
partition p201511 VALUES LESS THAN(UNIX_TIMESTAMP('2015-11-01 00:00:00')),
-
partition p201512 VALUES LESS THAN(UNIX_TIMESTAMP('2015-12-01 00:00:00')),
-
partition p201601 VALUES LESS THAN(UNIX_TIMESTAMP('2016-01-01 00:00:00'))
- );
使用者狀態表
sessionId是聊天雙方,(較小的ID在前,較大的ID在後) 的會話狀態資訊
pcMid是使用者pc端已讀的最大訊息ID
mobileMid是使用者手機端已讀的最大訊息ID
hashvalue是(傳送方使用者ID+接收方使用者ID) mod 64 計算後的值.暫時沒有用.
-
create table read_chat_mid(
-
id bigint primary key auto_increment,
-
uid bigint not null,
-
sessionId varchar(45) not null,
-
pcMid bigint not null default 0,
-
mobileMid bigint not null default 0,
-
hashvalue tinyint not null,
-
ts timestamp not null default current_timestamp on update current_timestamp
- );
獲取使用者未讀訊息的SQL如下.
-
create index inx_1 on chat_msg(ts,srcid,destid,mid);
-
- create unique index inx_2 on read_chat_mid(uid,sessionId);
查詢使用者1,2之間的聊天內容
-
select mid,srcid,destid,msgpb,ts from im_0.chat_msg_3 where id in (
-
select t.id from(
-
select t1.id from
-
(
-
(select id from im_0.chat_msg_3 where srcid=1 and destid=2
-
and ts>now()-interval '1' month
-
and mid>ifnull((select mobileMid from im_0.read_chat_mid_3 where sessionId='1,2' and uid=1),0) order by ts desc limit 200)
-
union all
-
(select id from im_0.chat_msg_3 where srcid=2 and destid=1
-
and ts>now()-interval '1' month
-
and mid>ifnull((select mobileMid from im_0.read_chat_mid_3 where sessionId='1,2' and uid=1),0) order by ts desc limit 200)
-
) as t1 order by id desc limit 200
-
) as t
- ) order by mid desc;
系統效能評估
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以上.
僅僅是四臺資料庫的情況,對於我們的業務.5年之內應該都不用考慮擴容的問題.
讓DBA做架構設計的好處是,不會把坑留在資料庫層面坑自己...
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-1845643/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- LongChat-企業IM即時聊天軟體GC
- IM即時通訊聊天社交APP VX 聊天語音視訊系統APP
- SpringBoot整合開源IM框架MobileIMSDK,實現即時通訊IM聊天功能Spring Boot框架
- 區塊鏈IM聊天軟體開發,即時通訊系統搭建原始碼區塊鏈原始碼
- 多人協作文件,即時線上儲存
- vue 高仿微信即時 IM 聊天|仿微信 vue+h5 版|仿微信介面VueH5
- 即時通訊H5聊天系統IM聊天APP仿微信雙端android ios帶後臺H5APPAndroidiOS
- 小程式實現實時聊天IM功能
- 區塊鏈IM社交直播軟體開發,即時通訊聊天系統開發區塊鏈
- 即時聊天社交系統開發/聊天交友/ChatGPT社交聊天ChatGPT
- 2.5K star 一款外掛化&易擴充的即時聊天(IM)平臺
- 校園IM即時通APP深度整合與定製開發解決方案APP
- eddChat即時通訊(聊天系統)
- 新浪微博私信,即時聊天介面研究
- 2024年,國內外哪些企業IM即時通訊聊天軟體支援OEM模式?模式
- 即時通訊im原始碼(開源的社群交友聊天系統原始碼uniapp)詳析原始碼APP
- 即時聊天軟體需要符合哪些要求?
- 即時通訊IM技術領域提高篇
- java Activiti6 工作流引擎 websocket 即時聊天 SSM原始碼 支援手機即時通訊聊天JavaWebSSM原始碼
- IM即時通訊設計 高併發聊天服務:伺服器 + qt客戶端(附原始碼)伺服器QT客戶端原始碼
- ChatGPT社交聊天/即時聊天社交交友系統技術開發/聊天交友ChatGPT
- 儲存遷移方案
- MySQL儲存過程 (即函式)MySql儲存過程函式
- QQ聊天記錄儲存如何實現?
- 談談儲存即服務(STaaS)解決方案具有什麼優勢?
- 基於 swoole擴充套件 的即時通訊 im套件
- 即時通訊IM技術領域基礎篇
- 即時通訊(IM)江湖的新兵與舊將薦
- xmpp實現的即時通訊聊天(一)
- xmpp實現的即時通訊聊天(二)
- 區塊鏈IM社交系統開發,IM即時通訊平臺搭建app區塊鏈APP
- Golang IM架構聊天開發Golang架構
- java 進銷存 crm websocket即時聊天發圖片文字 好友群組 SSM原始碼JavaWebSSM原始碼
- 重灌系統如何儲存qq聊天記錄
- 「實戰」搭建完整的IM(即時通訊)應用(2)
- 「實戰」搭建完整的IM(即時通訊)應用(1)
- 【融雲分析】 IM 即時通訊之鏈路保活
- Android 接入騰訊IM即時通訊(詳細圖文)Android