Browse Source

本地缓存消息优化(冷热数据分离)

master
xsx 10 months ago
parent
commit
aba495227c
  1. 2
      im-platform/src/main/java/com/bx/implatform/task/schedule/FileExpireTask.java
  2. 65
      im-uniapp/store/chatStore.js
  3. 60
      im-web/src/store/chatStore.js

2
im-platform/src/main/java/com/bx/implatform/task/schedule/FileExpireTask.java

@ -34,7 +34,7 @@ public class FileExpireTask {
private final MinioProperties minioProps; private final MinioProperties minioProps;
@RedisLock(prefixKey = RedisKey.IM_LOCK_FILE_TASK) @RedisLock(prefixKey = RedisKey.IM_LOCK_FILE_TASK)
@Scheduled(cron = "0 * * * * ?") @Scheduled(cron = "0 0 3 * * ?")
public void run() { public void run() {
log.info("【定时任务】过期文件处理..."); log.info("【定时任务】过期文件处理...");
int batchSize = 100; int batchSize = 100;

65
im-uniapp/store/chatStore.js

@ -22,7 +22,8 @@ export default defineStore('chatStore', {
chat.stored = false; chat.stored = false;
// 清理多余的消息,避免消息过多导致卡顿 // 清理多余的消息,避免消息过多导致卡顿
if (UNI_APP.MAX_MESSAGE_SIZE > 0 && chat.messages.length > UNI_APP.MAX_MESSAGE_SIZE) { if (UNI_APP.MAX_MESSAGE_SIZE > 0 && chat.messages.length > UNI_APP.MAX_MESSAGE_SIZE) {
chat.messages = chat.messages.slice(0, UNI_APP.MAX_MESSAGE_SIZE); let idx = chat.messages.length - UNI_APP.MAX_MESSAGE_SIZE;
chat.messages = chat.messages.slice(idx);
} }
// 暂存至缓冲区 // 暂存至缓冲区
cacheChats.push(JSON.parse(JSON.stringify(chat))); cacheChats.push(JSON.parse(JSON.stringify(chat)));
@ -64,6 +65,7 @@ export default defineStore('chatStore', {
lastContent: "", lastContent: "",
lastSendTime: new Date().getTime(), lastSendTime: new Date().getTime(),
unreadCount: 0, unreadCount: 0,
hotMinIdx: 0,
messages: [], messages: [],
atMe: false, atMe: false,
atAll: false, atAll: false,
@ -244,24 +246,28 @@ export default defineStore('chatStore', {
deleteMessage(msgInfo, chatInfo) { deleteMessage(msgInfo, chatInfo) {
// 获取对方id或群id // 获取对方id或群id
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
let isColdMessage = false;
for (let idx in chat.messages) { for (let idx in chat.messages) {
// 已经发送成功的,根据id删除 // 已经发送成功的,根据id删除
if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) { if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
chat.messages.splice(idx, 1); chat.messages.splice(idx, 1);
isColdMessage = idx < chat.hotMinIdx;
break; break;
} }
// 正在发送中的消息可能没有id,只有临时id // 正在发送中的消息可能没有id,只有临时id
if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) { if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) {
chat.messages.splice(idx, 1); chat.messages.splice(idx, 1);
isColdMessage = idx < chat.hotMinIdx;
break; break;
} }
} }
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage(isColdMessage);
}, },
recallMessage(msgInfo, chatInfo) { recallMessage(msgInfo, chatInfo) {
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
if (!chat) return; if (!chat) return;
let isColdMessage = false;
// 要撤回的消息id // 要撤回的消息id
let id = msgInfo.content; let id = msgInfo.content;
let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName; let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName;
@ -279,6 +285,7 @@ export default defineStore('chatStore', {
if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) { if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) {
chat.unreadCount++; chat.unreadCount++;
} }
isColdMessage = idx < chat.hotMinIdx;
} }
// 被引用的消息也要撤回 // 被引用的消息也要撤回
if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) { if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) {
@ -288,7 +295,7 @@ export default defineStore('chatStore', {
} }
} }
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage(isColdMessage);
}, },
updateChatFromFriend(friend) { updateChatFromFriend(friend) {
let chat = this.findChatByFriend(friend.id) let chat = this.findChatByFriend(friend.id)
@ -336,20 +343,19 @@ export default defineStore('chatStore', {
} }
}, },
refreshChats() { refreshChats() {
if (!cacheChats) { if (!cacheChats) return;
return;
}
// 排序 // 排序
cacheChats.sort((chat1, chat2) => { cacheChats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime);
return chat2.lastSendTime - chat1.lastSendTime; // 记录热数据索引位置
}); cacheChats.forEach(chat => chat.hotMinIdx = chat.messages.length);
// 将消息一次性装载回来 // 将消息一次性装载回来
this.chats = cacheChats; this.chats = cacheChats;
// 清空缓存不再使用 // 清空缓存,不再使用
cacheChats = null; cacheChats = null;
this.saveToStorage(); // 消息持久化
this.saveToStorage(true);
}, },
saveToStorage(state) { saveToStorage(withColdMessage) {
// 加载中不保存,防止卡顿 // 加载中不保存,防止卡顿
if (this.isLoading()) { if (this.isLoading()) {
return; return;
@ -362,12 +368,27 @@ export default defineStore('chatStore', {
this.chats.forEach((chat) => { this.chats.forEach((chat) => {
let chatKey = `${key}-${chat.type}-${chat.targetId}` let chatKey = `${key}-${chat.type}-${chat.targetId}`
if (!chat.stored) { if (!chat.stored) {
chat.stored = true;
if (chat.delete) { if (chat.delete) {
uni.removeStorageSync(chatKey); uni.removeStorageSync(chatKey);
} else { } else {
uni.setStorageSync(chatKey, chat); // 存储冷数据
if (withColdMessage) {
let coldChat = Object.assign({}, chat);
coldChat.messages = chat.messages.slice(0, chat.hotMinIdx);
uni.setStorageSync(chatKey, coldChat)
}
// 存储热消息
let hotKey = chatKey + '-hot';
if (chat.messages.length > chat.hotMinIdx) {
let hotChat = Object.assign({}, chat);
hotChat.messages = chat.messages.slice(chat.hotMinIdx)
uni.setStorageSync(hotKey, hotChat);
console.log("热数据:",hotChat.messages.length)
} else {
uni.removeStorageSync(hotKey);
}
} }
chat.stored = true;
} }
if (!chat.delete) { if (!chat.delete) {
chatKeys.push(chatKey); chatKeys.push(chatKey);
@ -391,20 +412,26 @@ export default defineStore('chatStore', {
this.loadingPrivateMsg = false; this.loadingPrivateMsg = false;
this.loadingGroupMsg = false; this.loadingGroupMsg = false;
}, },
loadChat(context) { loadChat() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let userStore = useUserStore(); let userStore = useUserStore();
let userId = userStore.userInfo.id; let userId = userStore.userInfo.id;
let chatsData = uni.getStorageSync("chats-app-" + userId) let chatsData = uni.getStorageSync("chats-app-" + userId)
if (chatsData) { if (chatsData) {
if (chatsData.chatKeys) { if (chatsData.chatKeys) {
let time = new Date().getTime();
chatsData.chats = []; chatsData.chats = [];
chatsData.chatKeys.forEach(key => { chatsData.chatKeys.forEach(key => {
let chat = uni.getStorageSync(key); let coldChat = uni.getStorageSync(key);
if (chat) { let hotChat = uni.getStorageSync(key + '-hot');
chatsData.chats.push(chat); if (!coldChat && hotChat) {
return;
}
// 冷热消息合并
let chat = Object.assign({}, coldChat, hotChat);
if (hotChat && coldChat) {
chat.messages = coldChat.messages.concat(hotChat.messages)
} }
chatsData.chats.push(chat);
}) })
} }
this.initChats(chatsData); this.initChats(chatsData);

60
im-web/src/store/chatStore.js

@ -69,6 +69,7 @@ export default defineStore('chatStore', {
lastContent: "", lastContent: "",
lastSendTime: new Date().getTime(), lastSendTime: new Date().getTime(),
unreadCount: 0, unreadCount: 0,
hotMinIdx: 0,
messages: [], messages: [],
atMe: false, atMe: false,
atAll: false, atAll: false,
@ -246,24 +247,28 @@ export default defineStore('chatStore', {
}, },
deleteMessage(msgInfo, chatInfo) { deleteMessage(msgInfo, chatInfo) {
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
let isColdMessage = false;
for (let idx in chat.messages) { for (let idx in chat.messages) {
// 已经发送成功的,根据id删除 // 已经发送成功的,根据id删除
if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) { if (chat.messages[idx].id && chat.messages[idx].id == msgInfo.id) {
chat.messages.splice(idx, 1); chat.messages.splice(idx, 1);
isColdMessage = idx < chat.hotMinIdx;
break; break;
} }
// 正在发送中的消息可能没有id,只有临时id // 正在发送中的消息可能没有id,只有临时id
if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) { if (chat.messages[idx].tmpId && chat.messages[idx].tmpId == msgInfo.tmpId) {
chat.messages.splice(idx, 1); chat.messages.splice(idx, 1);
isColdMessage = idx < chat.hotMinIdx;
break; break;
} }
} }
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage(isColdMessage);
}, },
recallMessage(msgInfo, chatInfo) { recallMessage(msgInfo, chatInfo) {
let chat = this.findChat(chatInfo); let chat = this.findChat(chatInfo);
if (!chat) return; if (!chat) return;
let isColdMessage = false;
// 要撤回的消息id // 要撤回的消息id
let id = msgInfo.content; let id = msgInfo.content;
let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName; let name = msgInfo.selfSend ? '你' : chat.type == 'PRIVATE' ? '对方' : msgInfo.sendNickName;
@ -281,6 +286,7 @@ export default defineStore('chatStore', {
if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) { if (!msgInfo.selfSend && msgInfo.status != MESSAGE_STATUS.READED) {
chat.unreadCount++; chat.unreadCount++;
} }
isColdMessage = idx < chat.hotMinIdx;
} }
// 被引用的消息也要撤回 // 被引用的消息也要撤回
if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) { if (m.quoteMessage && m.quoteMessage.id == msgInfo.id) {
@ -290,7 +296,7 @@ export default defineStore('chatStore', {
} }
} }
chat.stored = false; chat.stored = false;
this.saveToStorage(); this.saveToStorage(isColdMessage);
}, },
updateChatFromFriend(friend) { updateChatFromFriend(friend) {
let chat = this.findChatByFriend(friend.id); let chat = this.findChatByFriend(friend.id);
@ -338,20 +344,19 @@ export default defineStore('chatStore', {
} }
}, },
refreshChats() { refreshChats() {
if (!cacheChats) { if (!cacheChats) return;
return;
}
// 排序 // 排序
cacheChats.sort((chat1, chat2) => { cacheChats.sort((chat1, chat2) => chat2.lastSendTime - chat1.lastSendTime);
return chat2.lastSendTime - chat1.lastSendTime; // 记录热数据索引位置
}); cacheChats.forEach(chat => chat.hotMinIdx = chat.messages.length);
// 将消息一次性装载回来 // 将消息一次性装载回来
this.chats = cacheChats; this.chats = cacheChats;
// 清空缓存 // 清空缓存
cacheChats = null; cacheChats = null;
this.saveToStorage(); // 持久化消息
this.saveToStorage(true);
}, },
saveToStorage() { saveToStorage(withColdMessage) {
// 加载中不保存,防止卡顿 // 加载中不保存,防止卡顿
if (this.isLoading()) { if (this.isLoading()) {
return; return;
@ -365,12 +370,26 @@ export default defineStore('chatStore', {
// 只存储有改动的会话 // 只存储有改动的会话
let chatKey = `${key}-${chat.type}-${chat.targetId}` let chatKey = `${key}-${chat.type}-${chat.targetId}`
if (!chat.stored) { if (!chat.stored) {
chat.stored = true;
if (chat.delete) { if (chat.delete) {
localForage.removeItem(chatKey); localForage.removeItem(chatKey);
} else { } else {
localForage.setItem(chatKey, chat); // 存储冷数据
if (withColdMessage) {
let coldChat = Object.assign({}, chat);
coldChat.messages = chat.messages.slice(0, chat.hotMinIdx);
localForage.setItem(chatKey, coldChat)
}
// 存储热消息
let hotKey = chatKey + '-hot';
if (chat.messages.length > chat.hotMinIdx) {
let hotChat = Object.assign({}, chat);
hotChat.messages = chat.messages.slice(chat.hotMinIdx)
localForage.setItem(hotKey, hotChat)
} else {
localForage.removeItem(hotKey);
}
} }
chat.stored = true;
} }
if (!chat.delete) { if (!chat.delete) {
chatKeys.push(chatKey); chatKeys.push(chatKey);
@ -403,9 +422,24 @@ export default defineStore('chatStore', {
const promises = []; const promises = [];
chatsData.chatKeys.forEach(key => { chatsData.chatKeys.forEach(key => {
promises.push(localForage.getItem(key)) promises.push(localForage.getItem(key))
promises.push(localForage.getItem(key + "-hot"))
}) })
Promise.all(promises).then(chats => { Promise.all(promises).then(chats => {
chatsData.chats = chats.filter(o => o); chatsData.chats = [];
// 偶数下标为冷消息,奇数下标为热消息
for (let i = 0; i < chats.length; i += 2) {
if (!chats[i] && !chats[i + 1]) {
continue;
}
let coldChat = chats[i];
let hotChat = chats[i + 1];
// 冷热消息合并
let chat = Object.assign({}, coldChat, hotChat);
if (hotChat && coldChat) {
chat.messages = coldChat.messages.concat(hotChat.messages)
}
chatsData.chats.push(chat);
}
this.initChats(chatsData); this.initChats(chatsData);
resolve(); resolve();
}) })

Loading…
Cancel
Save