Zulip 架构总览与技术指南:开源团队聊天服务器的组件设计与发布生态
【免费下载链接】zulipZulip server and web application. Open-source team chat that helps teams stay productive and focused.项目地址: https://gitcode.com/GitHub_Trending/zu/zulip
本文基于 docs/overview/index.md 及其下辖的五个子文档(项目概览、架构总览、发布生命周期、路线图、版本历史)整理而成。Zulip 是一款开源的组织化团队聊天应用,其核心特色是独特的「话题式线程」(topic-based threading)机制,将电子邮件的异步沟通效率与即时聊天的实时性结合在一起。读完本文,你将完整掌握 Zulip 的服务端组件架构(Django + Tornado + nginx + 消息队列 + 缓存)、多组织(realm)模型、发布与升级策略,以及客户端兼容性设计,并能在仓库源码中定位每一层组件的真实实现。
Zulip 是什么
Zulip 是一款开源的组织化团队聊天应用,通过独特的话题式线程模型把「邮件的最佳体验」与「聊天的最佳体验」融合在一起,让远程工作既高效又愉悦。财富 500 强企业、领先的开源项目以及数以千计的其他组织每天都在使用 Zulip。它也是唯一一款同时为实时对话与异步对话而设计的现代团队聊天应用。
Zulip 由来自世界各地的分布式开发者社区构建,社区中有 99+ 位成员每人贡献了 100+ 次提交;整个项目拥有超过 1,500 名贡献者,每月合并超过 500 次提交。项目采用 Apache 2.0 许可证分发。
关键代码库生态
Zulip 官方维护的核心代码库即本仓库,它同时包含三大部分:
- 服务端后端:使用 Python 3.x 与 Django 编写;
- Web 应用前端:使用 JavaScript 与 TypeScript 编写;
- Webhook 集成库:面向其他服务与应用的大量入站集成(各集成实现位于 zerver/webhooks 目录下,共有 278 个 Python 集成文件与配套的 1052 个 JSON 测试样例)。
除此之外,官方还维护了多个独立的配套仓库:基于 Flutter 构建的移动端客户端(支持 iOS 与 Android)、基于 Electron 的桌面客户端(macOS/Linux/Windows)、终端客户端,以及 Python API 绑定、JavaScript API 绑定、Hubot 适配器、Jenkins/Puppet/Redmine/Trello 等第三方集成。翻译工作通过 Weblate 平台协作完成。本仓库的详细目录组织可参考 目录结构指南。
核心使用模型:多 Realm(组织)架构
Zulip 是一个实时团队聊天应用,面向从几人的小团队到数万用户的组织提供服务,并支持 iOS、Android、Linux、Windows、macOS 的专用客户端、所有现代 Web 浏览器、多种跨协议聊天客户端以及大量基于 Zulip API 的专用客户端(如机器人)。
一个 Zulip 服务器可以同时托管多个realm(即组织),每个 realm 拥有独立的(子)域名。大多数安装只托管一个组织,但有些服务器托管数千个组织(例如 zulip.com)。每个组织都是一个独立的私密空间,拥有自己的用户、频道、定制设置等;因此一个人可能是多个 Zulip realm 的用户。组织管理员对谁可以注册账号、新用户拥有什么权限等拥有很大控制权。安全相关的考量与选项可参考 加固你的 Zulip 服务器。
整体架构组件图
组件详解
Django 与 Tornado:双 Web 服务器分工
Zulip 主要基于 Django Python Web 框架实现,同时使用 Tornado 异步框架承担实时推送系统。两者分工明确:
- Django是主 Web 应用服务器,处理相对低频的操作(例如用户打字或点击触发的请求);
- Tornado专门运行服务端到客户端的实时推送系统,负责事件(消息)投递。
应用服务器的启动方式由 Supervisor 配置定义,而哪些 HTTP 请求被路由到哪个应用服务器则由 nginx 配置定义(详见下文)。
Tornado 是异步服务器,其设计目标是维持成千上万个长期存活(长轮询)的开放连接——即与每个运行中的客户端保持持久连接的路线。因此它只负责事件投递,而几乎不做其他事情。Zulip 刻意避免在 Tornado 代码路径中执行缓存或数据库查询,因为这些阻塞式请求对单线程异步服务器系统而言性能代价极高;延迟投递会拖慢其他数千个连接,使 Zulip 不再「实时」。事件队列系统的代码集中在 zerver/tornado 目录(核心文件包括event_queue.py、handlers.py、application.py、sharding.py等),详细机制见 实时推送与事件队列系统。
HTML 模板:Jinja2 与 Handlebars
Zulip 的 HTML 主要由两类模板实现:
- 后端模板:由 Jinja2 模板引擎驱动,用于未登录("portico")页面以及 Web 应用的基础内容;
- 前端模板:由 Handlebars 驱动,用于从 JavaScript 实时渲染 HTML,例如主消息流。
前端相关的细节可参考 翻译、模板与静态资源管线 以及 目录结构指南。本仓库的web/templates/目录下存放着 461 个.hbs前端模板文件。
nginx:前端 Web 服务器
nginx 是所有 Zulip 流量的前端 Web 服务器:它负责服务静态资源,并将请求代理给 Django 和 Tornado。其路由规则由puppet/zulip/files/nginx/和puppet/zulip/templates/nginx/下的众多配置文件定义(本仓库中实际存在zulip-include-frontend/app、zulip-include-common/、zulip-include-app.d/等目录与文件)。
其中最重要的文件是puppet/zulip/files/nginx/zulip-include-frontend/app,它定义了外部请求进入时的行为:
- 生产环境中,所有以
/static/开头的 URL 请求都从/home/zulip/prod-static/下对应的文件提供;生产构建过程(tools/build-release-tarball)负责编译、压缩并把静态资源安装到prod-static/目录树中。开发环境则直接从 Git 仓库的/static/提供文件。 - 对
/json/events与/api/v1/events的请求(即实时推送系统)被发送到 Tornado 服务器。 - 对其它所有路径的请求,经
uWSGI通过unix:/home/zulip/deployments/uwsgi-socket发送给 Django 应用。 - 默认情况下(即设置了
LOCAL_UPLOADS_DIR时),nginx 直接提供用户上传的内容(头像、自定义表情、上传文件);也可以配置 Zulip 把上传内容存储在 Amazon S3 等云存储服务中。
需要特别注意的是:开发环境不使用 nginx,而是采用一个基于 Tornado 的简单代理。
Supervisor:进程守护与日志
Zulip 使用 supervisord 启动服务器进程、在进程崩溃时自动重启,并管理日志定向。配置文件为puppet/zulip/templates/supervisor/zulip.conf.template.erb(本仓库还存在supervisord.conf.erb、zulip-once.conf.template.erb、email-mirror.conf.template.erb、go-camo.conf.erb、smokescreen.conf.erb等配套模板)。这里同时设置了 Tornado 和 Django,以及一批负责处理事件队列的后台进程。
Zulip 使用事件队列处理「适合在后台运行」的任务——这些任务代价高昂(对性能而言)且不必同步完成,例如发送邮件或更新分析数据。详见 队列指南。队列消费者进程定义在 zerver/worker 目录中(如queue_processors.py、email_senders.py、missedmessage_mobile_notifications.py、embed_links.py、user_activity.py等 18 个进程模块)。
memcached:数据库模型对象缓存
memcached 用于缓存数据库模型对象。zerver/lib/cache.py 与 zerver/lib/cache_helpers.py 负责把对象放入 memcached,并在值变化时使缓存失效。memcached 配置位于puppet/zulip/templates/memcached.conf.template.erb,工作机制详见 缓存指南。
Redis:短生命周期数据与限流
Redis 用于少数几种极短生命周期的数据存储,主要是限流系统。其配置位于puppet/zulip/templates/zulip-redis.template.erb,核心内容是通过以下配置关闭持久化以优化性能:
# Disable saving to disk to optimize performance save ""文档中还专门回答了社区常问的问题:能否用 Redis 替换 memcached(或替换 RabbitMQ)?答案是「或许可以,但不会让 Zulip 变得更好」:
- 缓存会占用大量内存,但用 Redis 替代 memcached 后内存占用基本不变;
- 这些服务的低内存需求都很小,即使在大规模下 Zulip 对 Redis 和 RabbitMQ 的应用也不占用显著内存;
- 若全部改用 Redis,很可能需要运行多个不同配置的 Redis 实例,以确保纯 LRU 用例(memcached 角色)不会把希望持久保存到期的数据(Redis 限流)或待消费的数据(RabbitMQ 延迟工作队列)挤出内存。
RabbitMQ:可靠的消息队列
RabbitMQ 是 Zulip 的队列系统,配置文件位于puppet/zulip/files/rabbitmq,初始配置由scripts/setup/configure-rabbitmq完成(两者在仓库中均真实存在)。
Zulip 用 RabbitMQ 来排队「昂贵的工作」,例如消息触发的邮件发送、推送通知、部分分析任务等——这些任务需要可靠投递,但又不能占用主线程。它还用于应用服务器与 Tornado 推送系统之间的通信。
pika:一个供 Tornado 使用的异步客户端,以及一个供其它场景使用的通用客户端。Supervisor 启动的大部分进程都是队列处理器,它们不断从 RabbitMQ 队列中拉取任务并处理,具体定义在 zerver/worker 目录。
PostgreSQL:持久化数据库
PostgreSQL 存储所有持久化数据——即期望在用户当前会话结束后依然存活的数据。自 Zulip 3.0 起,新安装会使用现代 PostgreSQL 发行版,而非操作系统自带的版本。
- 生产环境:PostgreSQL 以默认配置安装。本应存放配置文件的目录
puppet/zulip/files/postgresql中只有实用脚本和一个自定义停用词列表(供某个 PostgreSQL 扩展使用)。 - 开发环境:该 PostgreSQL 扩展的配置由
tools/postgresql-init-dev-db处理(由tools/provision调用),该脚本还负责创建开发用 PostgreSQL 用户;tools/provision还会调用tools/rebuild-dev-database来创建带完整 schema 的数据库。
Nagios:可选监控告警
Nagios 是可选组件,用于在发生故障等情况下向系统管理员发送通知。puppet/zulip/manifests/nagios_plugins.pp从puppet/zulip/files/nagios_plugins/安装 Nagios 插件。这些插件设计为运行在 Nagios 服务器上;而大多数 Zulip Nagios 插件设计为运行在 Zulip 服务器自身之上,随服务器相应组件一起分发(例如puppet/zulip/manifests/app_frontend_base.pp会在/usr/lib/nagios/plugins/zulip_app_frontend下安装若干个插件)。
发布生命周期
发布生命周期文档 明确建议自托管组织运行最新的稳定版服务器(本仓库 version.py 中LATEST_MAJOR_VERSION = "12.0"、LATEST_RELEASE_VERSION = "12.2"),并承诺升级流程「开箱即用」。新版本通过低流量的 zulip-announce 邮件列表发布通知,安全版本发布尤其值得订阅。
服务器与 Web 应用版本
Zulip 服务器与 Web 应用在同一个仓库中共同开发。版本号第一位代表主发布系列(例如 9.4 属于 9.x 系列):
- 主版本(如 Zulip 9.0):每年发布两次,包含数百个新功能、缺陷修复与内部改进;
- 维护版本(如 9.4):大约每月发布一次,设计为无风险改动、易于回退,以最大限度降低管理员升级压力。
升级到新的主版本系列时,官方建议始终升级到该系列最新的维护版本,以使用最新版本的升级代码。
安全版本
发现安全问题后,Zulip 会发布安全与缺陷修复版本,并通过行业标准的 CVE 通告流程透明地记录问题。新安全版本发布时,修复会同时发布到main分支与当前主版本系列的发布分支。仓库的 docs/overview/changelog.md 中记录了历次 CVE(例如 12.2 中的 GHSA 系列通告、11.x 中的 CVE-2026 系列等)。
Git 版本
许多 Zulip 服务器运行的是尚未发布为稳定版的 Git 版本:
- 可以升级到
main分支获取最新变更; - 官方维护形如
9.x的 Git 分支,包含从main回移植的、计划进入下一维护版本的提交,并像对待稳定版一样支持这些分支; - 开发社区服务器(chat.zulip.org)运行
chat.zulip.org分支,每周多次同步到main,还常把尚未进入main的改动「测试部署」到该分支以收集设计反馈; - Zulip Cloud 运行
zulip-cloud-current分支并附加一些精选改动,通常比main延迟一到两周,以便在部署给客户前对近期改动做进一步验证; - 也可以在这些分支之上运行 Zulip 的分支(fork)。Git 升级方式详见 从 Git 仓库升级。
如何查看当前版本
Zulip Web 应用会在齿轮菜单中显示当前服务器版本,也可以通过 API 获取(GET /api/v1/server_settings)。
版本化文档
为了确保能访问与服务器版本匹配的文档,帮助中心、API 文档与集成文档都会随 Zulip 服务器一起分发(例如https://zulip.example.com/help/)。这套 ReadTheDocs 文档在左上角提供版本切换控件,可查看其它版本的文档。
客户端应用与兼容性
Zulip 的官方客户端应用支持最近 18 个月内发布的所有服务器版本,且设计为与「最老受支持服务器版本到当前main分支之间」的中间 Git 提交兼容,这让服务器管理员可以放心升级到 Git 版本而不破坏客户端。API 变更日志(docs/overview/changelog.md 之外另有tools/merge-api-changelogs与tools/create-api-changelog维护的 API 特性级别,见 version.py 中API_FEATURE_LEVEL = 511)帮助第三方客户端开发者维持同等兼容水平。
移动端 / 桌面端 / 终端
- 移动端:从开发分支频繁发布新版本(通常每两周一次);除修复关键缺陷外,新版本先发布到 beta 频道。移动端与桌面端默认自动更新。
- 桌面端:基于 Electron 实现。桌面端 UI 由 Zulip 服务器提供(因此连接到不同服务器的标签页之间 UI 可能不同)。桌面端新版本很少包含新功能(功能继承自服务器/Web 应用),但必须及时升级,因为它们常包含上游 Chromium 项目的安全与操作系统兼容性修复。服务器端支持阻止或警告使用极旧/已知不安全的桌面端与移动端版本的访问。
- 终端:beta 阶段的终端应用目标支持与其它客户端相同的服务器版本范围;但不支持用旧版本终端应用连接最新服务器——服务器升级到新主版本后,终端用户通常需要同步升级。
服务器与客户端兼容性策略
Zulip 设计上保证可以始终运行最新服务器版本,一般不会把改动回移植到旧的稳定版本系列(除非刚发布主版本后不久发现安全问题或关键缺陷)。服务器在 API 上保持向后兼容,以支持最近 12 个月内发布的移动端与桌面端版本;由于这些客户端会自动更新,到停止支持某个版本时绝大多数活跃客户端早已完成升级。
升级提示横幅(Upgrade nag)
当服务器运行的 Zulip 版本超过 18 个月、不再受移动端与桌面端官方支持时,Web 应用会显示横幅警告:截止日期前一个月只对组织管理员显示,之后对所有用户显示。可通过在/etc/zulip/settings.py中设置例如SERVER_UPGRADE_NAG_DEADLINE_DAYS = 30 * 21来调整截止期限,然后重启服务器(见 设置文档)。
警告:运行超过 18 个月的服务器很可能受 Zulip 或其上游依赖中安全缺陷的影响。
操作系统支持
对于 Debian、Ubuntu 等受支持平台,Zulip 目标支持厂商完全支持的所有上游操作系统版本;文档说明了如何正确升级 Zulip 服务器的操作系统(包括当最新 Zulip 版本不再支持当前 OS 时如何正确串联升级)。Ubuntu 临时版本(interim releases,仅有 8 个月安全支持)被视为 beta 而非正式版本,不支持在生产环境运行。
API 绑定
Zulip API 绑定及 Python、JavaScript 绑定等相关项目按需独立发布。
路线图
路线图文档 欢迎用户社区参与影响 Zulip 的路线图:如果某个缺陷或缺失功能造成明显困扰,可以在开发社区聊天或相关 GitHub issue 中反馈,并附上使用场景说明——这样的细节对设计通用的解决方案极有帮助(参见 建议新功能指南)。
服务器与 Web 应用的优先级管理使用 GitHub projects 与标签:
- GitHub 项目看板公开跟踪主版本的目标:「Done」状态的项目会进入下一主版本;否则项目看板应视为「正在考虑」的优先级列表而非功能承诺,临近发布时未达成的功能会不断从看板移除。
- 高优先级(priority: high)标签标记被认为重要的 issue,在发布周期的规划阶段被评审以确定下一版本的优先级;
- Help wanted 标签标记开放给贡献者认领的 issue。
社区普遍认为所有小问题合在一起与大问题同样重要,许多已解决的 issue 从未被显式标记为发布目标。移动端路线图同样通过公开项目看板跟踪下一代移动应用(Flutter 重写版)的里程碑。
版本历史概览
版本历史文档 完整记录了 Zulip 服务器各版本的发布历史(全文约 5,600 行),当前包含 13.x 开发系列与 12.x、11.x、10.x 及更早系列的条目,每版均列出安全通告(CVE/GHSA)、新功能亮点、完整变更列表与升级注意事项。以近期版本为例:
- Zulip Server 12.0(2026-04-27 发布)引入移动推送通知端到端加密(E2EE)正式可用、Jdenticon 默认头像、媒体预览尺寸组织设置、演示组织(demo organizations)、Microsoft Teams 数据导入工具、Docker 容器重构(发布为 ghcr.io/zulip/zulip-server)等;
- Zulip Server 11.0(2025-08-13 发布)引入移动推送通知 E2EE 服务器端支持、频道文件夹(channel folders)、消息提醒调度、SCIM 群组成员同步、Debian 13 支持、翻译平台迁移到 Weblate 等;
- Zulip Server 10.0(2025-03-20 发布)引入基于用户组的全新权限系统、TUS 分块上传协议支持大文件、归档频道功能重构等。
每次主版本还附带升级注意事项(例如 11.0 起不再支持 PostgreSQL 13,12.0 起AUTH_LDAP_USERNAME_ATTR为 LDAP 配置必填项),自托管管理员在升级前应仔细阅读对应版本的「Upgrade notes」。最新开发中的 13.x 系列内容见文档开头的 13.0-dev 小节与仓库提交历史。
延伸阅读
- 项目概览:docs/overview/readme.md
- 架构总览:docs/overview/architecture-overview.md
- 发布生命周期:docs/overview/release-lifecycle.md
- 路线图:docs/overview/roadmap.md
- 版本历史:docs/overview/changelog.md
- 实时推送与事件队列:docs/subsystems/events-system.md
- 队列系统:docs/subsystems/queuing.md
- 缓存系统:docs/subsystems/caching.md
- 目录结构:docs/subsystems/directory-structure.md
【免费下载链接】zulipZulip server and web application. Open-source team chat that helps teams stay productive and focused.项目地址: https://gitcode.com/GitHub_Trending/zu/zulip
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考