说明.md 4.0 KB

message_server 是一个 websocket 服务,最初的设计是为实现聊天功能。

聊天功能大概如下:

  1. 每个用户(商家或客户)端可创建一个与 server 的 socket 连接
  2. socket 连接是被一个 room 空间所包含的
  3. 客户与商家能互相聊天,说明他们一定是在同一个 room 空间下

当前,message_server 只能让不同用户端在一起互相通信实现聊天,但还缺失以下功能或数据:

  1. 一个用户最近与哪些人聊过天(最近的时长最大设置为 7天)
  2. 没把一个用户用参数标识好 --- 从而能准确查询某个用户是否在线,在哪个房间(room)
  3. 现有 room 的概念,如果我想知道当前有多少用户在线,可以说把 rooms 中所有 room 遍历就可以实现。试问,需要搞个优化方案吗,从而更高效快速查询某个用户是否在线,总共有多少用户在线?

按以上列出的缺失功能,设计出实现的技术方案与细节:

如果可以归纳在一起实现的就直接按整体实现来。
  1. 一个用户最近与哪些人聊过天

    • 如果用户是门店(Client.userInfo.Type == 'shop'),那么与他关联的聊天个体是客户(customer)。请用 redis 数据结构中有序字典为门店用户创建出“聊天用户群体”,其中排序权重(score)使用是时间戳,时间越是最近,就排序在越前边。
    • 如果用户是门店(Client.userInfo.Type == 'customer'),那么与他关联的聊天个体是店家(shop)。请用 redis 数据结构中有序字典为门店用户创建出“聊天用户群体”,其中排序权重(score)使用是时间戳,时间越是最近,就排序在越前边。
    • 有了聊天用户数据的同时,还要有与每个聊天体的未读消息数。为了不额外添加数据结构,要对保存“聊天用户群体”的有序字典的 score 做个特殊设计,从而实现在记录未读消息数。由于 score 是个浮点数,那么就充分利用它的特点:整数部分是 时间戳,小数部分其实是未读消息数
  2. 统计:有多少在线用户

  3. 用 Client.name 就能查询该用户是否在线,及在哪个房间。

AI 优化的需求

为了高效实现“最近联系人列表”和“未读消息数”,我们将为每个用户创建一个 Redis 有序集合(Sorted Set)

设计细节:

  • 数据结构: 为不同类别用户创建有序集合:门店(shop)以 shop_chats:{ShopId} 为键名,客户(customer)以 customer_chats:{UserId}
  • 成员(Member): 集合的成员是与该用户聊天的另一个用户的 ID({contact_id})。
  • 分数(Score): 这是设计的核心。我们将分数(score)设计为一个浮点数,利用它的特性同时存储两个信息:
    • 整数部分: 存储 Unix 时间戳(timestamp)。这样,当有新的聊天发生时,只需更新这个时间戳,Redis 会自动根据时间戳对联系人进行排序,越新的聊天越靠前。
    • 小数部分: 存储未读消息数(unread_count)。例如,我们可以将小数部分乘以一个很大的数(如 1000)来表示未读消息数,以确保其在浮点数精度范围内。或者更简单地,直接使用一个相对较小的数作为未读数的乘数。
      • 举例: score = timestamp + (unread_count / 1000.0)。每收到一条新消息,只需递增 unread_count,并更新 score

优势:

  • 高效排序: Redis 有序集合天然支持按分数排序,无需额外操作即可获取最近联系人列表。
  • 一举两得: 利用 score 的浮点数特性,在一个数据结构中同时存储了时间戳和未读消息数,减少了对 Redis 内存的占用和数据同步的复杂性。
  • TTL 支持: 可以为这个键设置一个 过期时间(TTL),比如 7 天,来自动清理过期的聊天记录,符合你的需求。

疑问:

  1. 同一个用户是否可以用不同设备实现进入同一个房间 ?