最近公司小程序中要植入一个聊天。所以,我用swoole写了一个。聊天我就不多说了,今天来谈谈用redis写的用户会话列表。本片文章大部分都是我写的废话,只有少量的代码,这些都是我自己假象设计的。本身就是一个计算机的小白,可能不入一些大佬的眼,也有可能存在这一定的bug,欢迎大哥们发现问题后指正。🙏
需求:
- 未读消息数
- 每当来新消息,新消息要展示在上面
- 删除对话后,清除聊天记录(不清除就永久存在)
假设有用户A与B,redis设计如下:(A为发送方,B为接受方)
聊天消息
(list) chat:A:B
先用sort
对A、B排序,让两个用户间生成唯一的聊天记录
使用rpush
在链表右侧追加一条数据
当数据大于500时,把它压入mysql。
这个你可以在每接收一条数据后就进行判断是否压入数据库,也可以写一个shell脚本,让他每天指定时间入查询压入数据库
未读消息数
(string) unread:A:B:B 也要生成 weBight:A:B:A
使用incr
自增,每当来一条新消息,对方就加一。当进入会话后,把它清零
因为是A发送的,所以这个时候,要用set
把 weBight:A:B:A设置为0
会话列表
(zset) weight:A:B:B 也要生成 weBight:A:B:A
使用zIncrBy
插入weBight:A:B:B,自增分数。当进入会话后,把当前值分数清零
因为是A发送的,所以这个时候,要用zAdd
把 weight:A:B:A设置为0
记录消息起始位置
(hash) historyMsg:A:B:A 也要生成 historyMsg:A:B:B
当接到消息时,判断historyMsg:A:B:A是否为空
为空:那就插入redis=>当前消息id (chat:A:B返回的id)
不为空:说明有起始位置
- 存在redis=>? 当进入会话获取消息时,直接获取到当前位置就可以
- 存在mysql=>? 那就需要获取到所有的redis数据,在加上mysql的数据了
总结一下整体流程(使用的时laravel)
有新消息,创建chat:A:B、unread:A:B:A 、weight:A:B:A 、historyMsg:A:B:A …
查询weight:A:B:A展示用户会话列表。根据分数,排序获取用户id数组
根据排序的id数组去读取数据库用户信息
1
return User::whereIn('id',[3,1,2])->orderByRaw("FIND_IN_SET(id,'3,1,2')")->get();
当用户进入会话后,unread:A:B:A 、weight:A:B:A 值清零
根据historyMsg:A:B:A展示最多显示到什么地方(redis分页)
1
2
3
4
5
6$arr = [A,B];
sort($arr)//这个就是上面说的sort排序,双方共用一个
$page = isset($request->page) ? (int)$request->page : (int)1;
$pageSize = isset($request->page_size) ? (int)$request->page_size : (int)10;
$msg = $this->redis->lRange("chat:{$arr[0]}:{$arr[1]}",-1 * $page * $pageSize,-1 * (($page - 1) * $pageSize + 1));当用户删除当前会话时,就把(historyMsg:A:B:A)给删除