最近公司小程序中要植入一个聊天。所以,我用swoole写了一个。聊天我就不多说了,今天来谈谈用redis写的用户会话列表。本片文章大部分都是我写的废话,只有少量的代码,这些都是我自己假象设计的。本身就是一个计算机的小白,可能不入一些大佬的眼,也有可能存在这一定的bug,欢迎大哥们发现问题后指正。🙏


需求:

  1. 未读消息数
  2. 每当来新消息,新消息要展示在上面
  3. 删除对话后,清除聊天记录(不清除就永久存在)

假设有用户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)

  1. 有新消息,创建chat:A:B、unread:A:B:A 、weight:A:B:A 、historyMsg:A:B:A …

  2. 查询weight:A:B:A展示用户会话列表。根据分数,排序获取用户id数组

    根据排序的id数组去读取数据库用户信息

    1
    return User::whereIn('id',[3,1,2])->orderByRaw("FIND_IN_SET(id,'3,1,2')")->get();
  3. 当用户进入会话后,unread:A:B:A 、weight:A:B:A 值清零

  4. 根据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));
  5. 当用户删除当前会话时,就把(historyMsg:A:B:A)给删除