Hotdry.

Article

Chatwoot 全渠道客服架构解析:Rails + ActionCable 实时通信与会话路由

深入剖析 Chatwoot 开源客服平台的技术架构,涵盖 Ruby on Rails 多租户设计、ActionCable WebSocket 实时通信机制、Sidekiq 异步任务处理及全渠道消息路由策略。

2026-06-11systems

在客户支持领域,Intercom、Zendesk 等商业方案长期占据主导地位,但其封闭的生态和高昂的订阅成本促使许多团队寻求开源替代方案。Chatwoot 作为一个基于 Ruby on Rails 构建的开源客服平台,提供了从实时聊天到邮件支持的全渠道解决方案,其架构设计对于构建类似的企业级通信系统具有重要参考价值。

本文将从工程实现角度,深入解析 Chatwoot 的核心技术架构,包括多租户隔离机制、WebSocket 实时通信实现、会话路由策略以及异步任务处理等关键模块。

技术栈与整体架构

Chatwoot 采用经典的全栈架构模式:

  • 后端:Ruby on Rails(占比 47%)提供 API 服务与业务逻辑
  • 前端:Vue.js(27.4%)+ JavaScript(22.5%)构建响应式管理界面
  • 数据层:PostgreSQL 持久化存储,Redis 负责缓存与消息队列
  • 实时通信:Rails 内置的 ActionCable 提供 WebSocket 支持
  • 后台处理:Sidekiq 基于 Redis 实现异步任务队列

这种技术选型体现了 Rails 生态在快速开发企业级应用时的优势 —— 约定优于配置的理念使得团队能够专注于业务逻辑而非基础设施搭建。

WebSocket 实时通信机制

Chatwoot 的实时通信能力建立在 Rails ActionCable 之上,通过 WebSocket 连接实现客户端与服务器的双向通信。

连接建立与认证

WebSocket 服务端点位于 /cable,客户端连接时需要提供 PubSub Token 进行身份验证。Chatwoot 支持两种令牌类型:

  • User PubSub Token:面向客服代理 / 管理员,通过 Profile API 获取,具有完整的系统事件访问权限
  • Contact PubSub Token:面向终端客户,每个会话生成唯一令牌,仅接收与该会话相关的事件

连接建立后,客户端订阅 RoomChannel 频道,通过 account_iduser_id(或仅 pubsub_token)标识身份:

const connection = new WebSocket("wss://app.chatwoot.com/cable");
connection.send(JSON.stringify({
  command: "subscribe",
  identifier: JSON.stringify({
    channel: "RoomChannel",
    pubsub_token: pubSubToken,
    account_id: accountId,
    user_id: userId
  })
}));

实时事件类型

Chatwoot 通过 WebSocket 推送多种业务事件,覆盖客服交互的核心场景:

事件类型 触发场景 接收方
conversation.created 新会话创建 代理 / 客户
message.created 新消息到达 会话参与者
conversation.typing_on/off 输入状态变化 会话参与者
assignee.changed 会话分配变更 相关代理
presence.update 在线状态更新 代理 / 客户

这种细粒度的事件设计使得前端能够精确响应状态变化,而无需频繁轮询服务器。

在线状态维护

为保持用户在线状态,客户端需每 30 秒发送一次 presence 更新:

connection.send(JSON.stringify({
  command: "message",
  identifier: channelIdentifier,
  data: JSON.stringify({ action: "update_presence" })
}));

服务器据此维护用户活跃状态,用于显示 "在线" 标识及会话路由决策。

多租户与会话路由

Account 作为租户边界

Chatwoot 采用多租户架构,每个客户组织对应一个 Account 实体。用户、代理、会话、消息等数据均按 Account 隔离,确保数据安全性。在应用层通过 RBAC(基于角色的访问控制)实施权限校验,防止跨租户数据泄露。

会话路由策略

Chatwoot 支持多种会话分配机制:

  1. 自动分配(Auto-Assignment):根据代理负载和可用性自动路由会话
  2. 团队分配(Team Assignment):将会话分配给特定客服团队
  3. 手动分配:管理员或代理手动接管会话

会话状态流转包括 openresolvedpending 等,状态变更通过 WebSocket 实时同步给相关方。

邮件与 Webhook 集成

Sidekiq 异步处理架构

对于邮件发送、Webhook 投递等耗时操作,Chatwoot 采用 Sidekiq 进行异步处理。典型部署模式包含两个独立服务:

  • Web 服务:处理 HTTP 请求与 WebSocket 连接
  • Sidekiq 服务:执行后台任务队列

两者共享 PostgreSQL 和 Redis 实例,Redis 作为 Sidekiq 的任务队列后端。

邮件渠道配置

邮件集成需要配置 SMTP 提供商(如 Brevo、Resend),关键环境变量包括:

  • SMTP_ADDRESSSMTP_PORTSMTP_USERNAMESMTP_PASSWORD
  • MAILER_SENDER_EMAIL

这些配置需同时应用于 Web 和 Sidekiq 服务,确保邮件任务能够正确投递。

Webhook 投递机制

外部集成通过 Webhook 实现,Chatwoot 将 webhook 投递任务入队 Sidekiq,支持重试和退避策略。建议实现幂等性处理,防止重复通知导致业务异常。

工程实践建议

部署模式

生产环境推荐采用容器化部署,通过 Docker Compose 或 Kubernetes 编排以下组件:

  • Rails 应用容器(Web + Sidekiq 可分离部署)
  • PostgreSQL 数据库
  • Redis 实例
  • Nginx 反向代理(处理 WebSocket 升级)

性能优化要点

  1. Redis 作为 ActionCable 适配器:高并发场景下,使用 Redis Pub/Sub 替代内存适配器,支持多实例间的消息广播
  2. WebSocket 连接池管理:监控连接数与内存占用,设置合理的连接超时
  3. Sidekiq 队列分级:将任务按优先级分配到不同队列(如 mailersdefaultlow

监控指标

  • WebSocket 连接数与消息吞吐量
  • Sidekiq 队列深度与处理延迟
  • 邮件发送成功率与 Webhook 响应时间
  • 各 Account 的会话量分布(识别热点租户)

总结

Chatwoot 的架构设计展现了 Rails 生态在构建实时通信系统时的工程成熟度。通过 ActionCable 实现低延迟消息推送,借助 Sidekiq 处理异步任务,配合 Account 级别的多租户隔离,形成了一套可扩展的客服平台方案。

对于需要自建客服系统的团队,Chatwoot 提供了可 fork 的代码基础和清晰的扩展接口。在实际落地时,需重点关注 WebSocket 连接的稳定性、多租户数据隔离的完备性,以及异步任务的可靠性保障。

参考资料

systems

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com