一个简单的实时聊天功能差点毁了这次发布

一个基础的实时聊天系统差点毁了我最近的一次发布。

听起来很简单:显示附近的活跃用户并让他们聊天。但技术层面的现实要困难得多。我必须将实时聊天与地理位置和评分系统结合起来,这在底层造成了巨大的复杂性。

架构:

• Frontend: React 和 TypeScript。 • Backend: Node.js,配合 Express 和 WebSockets。 • Database: 用于存储用户和评分的 PostgreSQL。 • Cache: 用于活跃会话和在线状态的 Redis。

地理位置问题

按位置匹配用户并不容易。我必须处理许多边缘情况:

  • 存储经纬度。
  • 使用 Postgres 扩展来查询距离。
  • 处理拒绝位置权限的用户。
  • 处理用户在未打开应用的情况下移动所产生的陈旧数据。

如果再做一次,我会将位置采集与匹配功能拆分为不同的服务。

实时聊天的现实

WebSockets 带来了实时功能,但也带来了混乱。我使用了 Redis pub/sub 模式在不同服务器之间发送消息。

最难的部分在于:

  • 在用户意外断开连接时清理连接。
  • 防止向用户已退出的房间发送消息。
  • 处理重新连接,同时避免产生“幽灵会话”。

我学到了,使用正式的状态机比使用简单的标志位(flags)更好。

评分系统

评分系统在构建之前看起来微不足道,但实际操作起来却不然。我必须确保:

  • 用户不能对同一个会话进行两次评分。
  • 评分能快速聚合,以便在个人资料视图中显示。
  • 数据在整个应用中保持一致。

我在会话 ID 上使用了唯一约束(unique constraints)来防止重复,并缓存了平均分以提升性能。

经验教训

如果今天重新构建这个系统,我会做出三点改变:

  1. 将匹配和聊天拆分为独立的模块。
  2. 对 WebSocket 连接状态进行显式建模。
  3. 从第一天起就为聊天和匹配功能添加更好的日志和指标。

构建软件是一系列微小决策的过程。这些决策决定了你的系统是简洁优雅还是脆弱不堪。

你是否构建过实时聊天或匹配系统?如果有机会,你会做出哪些不同的尝试?

Source: https://dev.to/jaeger974/simple-live-chat-almost-sank-this-release-2pn7