0%

GoChat 项目总览

GoChat 聊天系统项目总览

本文是 GoChat 聊天系统系列博客的第一篇,主要聚焦于项目的整体架构设计与技术选型。后续将针对各个核心模块(如 WebSocket 通信、微服务拆分、消息队列解耦、服务注册与发现等)分别撰写详细专题,欢迎持续关注!

一、项目简介

GoChat 项目的起点其实很简单:我最初完成了一个能实现基本聊天功能的 version1.0。这个版本虽然能用,但随着时间推移,我发现它太过简陋,架构上也有不少不妥之处,难以满足更高的并发和扩展需求。

因此,我决定对项目进行彻底重构,着手开发 version2.0。在新版本中,我希望不仅能完善功能,还能应用更多现代技术和更合理的架构设计。

在这个过程中,我不断学习和调研,逐步确定了合适的技术栈:后端采用 Go 语言,服务间通信选择了高效的 gRPC,服务注册与发现用 etcd,消息解耦和异步处理则引入了 RabbitMQ,数据存储和缓存分别用 MySQL 和 Redis。前端则用原生 JavaScript,方便灵活地实现 WebSocket 通信和用户交互。

整个项目的架构和功能都是一步步搭建和完善起来的:从最初的单体服务,到服务拆分、消息队列引入、再到 WebSocket 微服务独立化,每一步都伴随着技术选型、架构调整和大量的实践探索。最终,GoChat 实现了多用户实时聊天、断线重连、消息去重、踢人下线等主要功能,也让我在分布式系统和高并发编程方面有了更深刻的理解和成长。

主要功能:

  • 多用户实时聊天
  • WebSocket 断线重连
  • 消息去重与缓存
  • 多端登录检测与踢人下线
  • 消息异步处理与可靠投递

技术栈:

  • 后端:Go、gRPC、RabbitMQ、Redis、MySQL
  • 前端:原生 JavaScript
  • 通信协议:WebSocket、gRPC

二、系统架构与模块划分

在设计 GoChat 的整体架构时,我希望它既能应对高并发场景,又具备良好的扩展性和解耦能力。因此,我采用了如下分层分布式架构:

1. API 网关层

这是对外暴露的唯一入口,负责接收前端的 HTTP/WebSocket 请求、用户认证和权限校验等。API 层会将用户的操作请求封装成消息,异步投递到消息队列(RabbitMQ),实现流量削峰和服务解耦。对于实时通信,API 层还负责为用户分发 WebSocket 微服务的连接 URL。

  • 鉴权与限流:API 层通过 JWT 对用户请求进行鉴权,结合令牌桶中间件和本地+Redis双层结构进行接口限流,防止恶意请求和流量突发。
  • 唯一性校验:通过布隆过滤器中间件高效校验用户名唯一性,提升高并发下的校验效率。

2. WebSocket 微服务

WebSocket 微服务专门负责维护客户端的长连接,处理实时消息的收发和下发。用户在通过 API 层认证后,会获得一个 WebSocket 服务的连接地址,然后直接与 WebSocket 微服务建立长连接。

  • 连接流程
    1. 客户端首先访问 API 层接口,完成认证。
    2. API 层返回 WebSocket 微服务的连接 URL(带有临时 token)。
    3. 客户端用该 URL 建立 WebSocket 长连接。
  • 消息处理协作
    • 当用户通过 WebSocket 发送消息时,WebSocket 微服务会校验消息,并立即推送给目标用户,同时进行消息持久化,保证消息的实时性和可靠性。
    • 通过 Redis 维护连接信息,结合 RabbitMQ 实现分布式部署下的消息统一分发,保障不同服务端间的用户通信。

这种设计让 WebSocket 微服务专注于连接和实时性,消息微服务专注于数据可靠性和业务逻辑,职责清晰,易于扩展。

3. 消息队列层(RabbitMQ)

RabbitMQ 作为核心的消息中间件,承担着系统“缓冲区”和“调度中心”的角色。API 层把用户请求作为消息发送到 MQ,后端有专门的消费者服务监听并消费这些消息,实现异步处理和服务解耦。

  • 高效调用:MQ 消费者服务在处理消息时,利用 Go 的反射机制动态调用对应的微服务方法,极大减少了代码复杂度,提高了系统的灵活性和可维护性。

4. 微服务层(gRPC + etcd)

后端的业务逻辑被拆分为多个微服务(如用户、消息、好友等),每个服务都通过 gRPC 提供高效的远程调用接口。所有微服务启动时会自动向 etcd 注册自己的地址,实现服务注册与发现、负载均衡和故障转移。

  • 消息微服务:负责消息的持久化、历史记录、消息查询等,采用合理的分片键进行水平分表,提升查询效率。
  • 用户/好友微服务:负责用户注册、登录、好友管理等。

5. 基础设施层(MySQL、Redis等)

所有服务共享底层的数据库和缓存,用于数据持久化和高效访问。

  • MySQL:存储用户信息、消息内容、好友关系等核心数据,消息表采用分片键进行水平分表。
  • Redis:缓存用户会话、在线状态、热点数据等,采用分布式锁保障用户登录唯一性,并用 list 结构快速查询消息。

架构设计思考

  • WebSocket 微服务独立化:让连接管理和消息推送弹性扩展,避免单点瓶颈。
  • gRPC+etcd 服务治理:高效通信、自动注册发现,适合微服务动态扩缩容。
  • RabbitMQ 异步解耦:天然流量削峰,提升系统弹性和可维护性。
  • 分层解耦,职责单一:每一层专注自身领域,便于后续横向扩展和服务治理。
  • 多层安全与流控:JWT 鉴权、布隆过滤器唯一性校验、令牌桶限流、分布式锁等多重保障系统安全与稳定。

系统架构图

graph TD
  A[前端/用户] -- HTTP/WebSocket --> B[API 网关]
  B -- 获取WS连接URL --> A
  A -- 连接 --> W[WebSocket微服务]
  W -- gRPC持久化消息 --> F2[消息微服务]
  B -- 消息投递 --> D[RabbitMQ]
  D -- 消费消息 --> E[消息消费者服务]
  E -- gRPC --> F1[用户微服务]
  E -- gRPC --> F2
  E -- gRPC --> F3[好友微服务]
  F1 -- etcd 注册/发现 --> G[etcd]
  F2 -- etcd 注册/发现 --> G
  F3 -- etcd 注册/发现 --> G
  W -- etcd 注册/发现 --> G
  W -- 消息下发 --> A
  F1 -- MySQL/Redis --> H[存储]
  F2 -- MySQL/Redis --> H
  F3 -- MySQL/Redis --> H

通过这样的架构设计,GoChat 能够高效地支持大规模用户的实时通信需求,同时具备良好的可维护性和扩展性。无论是消息的可靠存储、实时推送,还是服务的弹性扩容,都能灵活应对业务增长和技术演进。

三、后续专题预告

由于 GoChat 项目功能丰富、架构复杂,一篇博客难以面面俱到。后续我会针对以下专题分别撰写详细文章:

  • WebSocket 多用户实时通信与断线重连机制
  • 微服务拆分与 gRPC 通信实践
  • RabbitMQ 消息解耦与异步处理
  • etcd 服务注册与发现的实现
  • 业务模块设计与扩展性思考
  • 性能优化与高可用实践

欢迎持续关注 GoChat 系列博客,和我一起深入探索分布式聊天系统的设计与实现!

自研基础组件与工程实践

在 GoChat 的开发过程中,除了集成主流中间件和微服务框架,我还动手实现了一些关键的基础组件,进一步提升了系统的性能和可维护性:

  • 自研协程池 routinePool(借鉴 ants)
    为了高效地处理高并发下的任务调度和资源复用,我参考了 ants 的设计思想,实现了名为 routinePool 的简易协程池组件。这样可以有效避免频繁创建和销毁 goroutine 带来的性能损耗,提升了系统的吞吐量和资源利用率。

  • 责任链式中间件机制(借鉴 gin)
    在 API 层和部分微服务内部,我实现了类似 gin 框架的责任链式调用机制(MyHandlerFunc)。这样每个中间件只关注自己的职责,多个中间件可以灵活组合、按需插拔,极大提升了代码的可读性和可维护性。例如,鉴权、限流、日志、参数校验等都可以作为独立的中间件链式调用。

  • 自研布隆过滤器
    为了在高并发场景下高效校验用户名等唯一性,我实现了自研布隆过滤器组件。相比传统查库校验,布隆过滤器能大幅减少数据库压力,提升系统性能和健壮性,尤其适合大规模用户注册、唯一性校验等场景。

  • 日志记录与配置管理
    项目日志系统采用高性能的 zap 包,支持结构化日志输出,便于后期排查问题和系统可观测性。配置管理则采用 viper 包,支持多环境配置热加载和灵活的参数管理,极大提升了项目的可维护性和部署灵活性。

这些自研“轮子”与工程实践不仅让项目更贴合实际业务需求,也锻炼了我对 Go 语言并发模型和高可用架构的理解与实践能力。