news 2026/9/13 11:09:30

Zulip 备份、导出与导入全指南:从整机恢复、组织迁移到合规导出

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zulip 备份、导出与导入全指南:从整机恢复、组织迁移到合规导出

Zulip 备份、导出与导入全指南:从整机恢复、组织迁移到合规导出

【免费下载链接】zulipZulip server and web application. Open-source team chat that helps teams stay productive and focused.项目地址: https://gitcode.com/GitHub_Trending/zu/zulip

Zulip 提供了两套互为补充的高质量数据工具:备份(Backup)工具用于精确恢复整个 Zulip 服务器的运行状态(灾备恢复、硬件迁移、生产数据测试),而逻辑数据导出(Data Export)工具用于在 Zulip Cloud 与自托管服务器之间迁移组织、以及各类审计与合规场景。本文以docs/production/export-and-import.md为主线,结合仓库源码(zerver/management/commands/backup.pyscripts/setup/restore-backupzerver/lib/export.pyzerver/management/commands/export_search.py等)逐层拆解:读完你将掌握备份的创建与恢复、组织的导出与导入、合规检索导出,以及基于 wal-g 的连续时间点数据库备份方案,并理解每一步背后的实现原理与适用边界。

工具选型:先分清“备份”与“导出”的适用场景

在动手之前,必须先理解 Zulip 中“备份”与“逻辑导出”是两类目的截然不同的工具,选错会导致不必要的用户干扰或数据形态不匹配。

备份工具(Backup)的设计目标是精确还原一台 Zulip 服务器的状态,适合灾难恢复、使用生产数据做测试、硬件迁移等场景。官方强烈推荐在适用场景下优先使用它,因为:

  • 快速、健壮,对用户的中断最小;
  • 产出的是一个包含数据库、配置、密钥、上传文件的.tar.gz归档,还原后服务器即恢复原状。

但备份工具有如下限制:

  • 备份必须恢复到运行相同 Zulip 版本的服务器上(精确地说,是manage.py showmigrations输出完全一致的版本);
  • 备份必须恢复到相同 PostgreSQL 版本的服务器上。安装时可通过--postgresql-version参数(详见 部署文档中的安装器选项)指定与备份时一致的 PostgreSQL 版本。注意 PostgreSQL 可以独立于 Zulip 其余部分进行升级;
  • 备份不适合在自托管与 Zulip Cloud 之间迁移组织(这种迁移可能需要对所有用户/消息等重新编号)。

逻辑数据导出工具(Data Export)的设计目标是在 Zulip Cloud 与其他 Zulip 服务器之间迁移数据,以及各类审计用途。推荐在备份工具不适用时使用它,尤其是需要易于机器解析的导出格式时。它的限制与注意事项:

  • 与备份工具类似,逻辑导出也必须在相同 Zulip 版本的服务器上导入;但逻辑导出可以导入到PostgreSQL 版本不同、或托管着不同组织集合的服务器上;
  • 通过导出工具转移组织会带来显著的用户可见中断:所有用户会被登出账号并要求重置密码。

逻辑导出工具产出一个.tar.gz归档,其中大部分 Zulip 数据库数据以 JSON 文件编码——这一格式与 Zulip 面向第三方服务(如 Slack)的数据导入工具共用。

此外 Zulip 生态还包含:

  • 合规导出(Compliance exports):允许服务器管理员按搜索条件导出消息(详见下文专属小节);
  • HTML 归档工具zulip-archive,独立仓库):主要用于公开归档,也可在解散组织时以低成本保留公开频道对话;
  • 高可用环境:可组合使用 PostgreSQL 流式复制 与 S3 文件上传后端 搭建高可用架构。

需要说明的是,本文所有命令均针对标准的 tar.gz 自托管安装。若你使用 Docker 部署,推荐的备份单元是包含近期app:backup数据库转储的/data卷快照;manage.py backup工具虽也支持 Docker 与标准安装之间的双向迁移,但不是Docker 部署日常备份的推荐方式。

备份工具:一条命令打包整台服务器

Zulip 服务器内置了备份命令,以zulip用户身份执行:

# 以 zulip 用户身份 /home/zulip/deployments/current/manage.py backup # 或作为 root su zulip -c '/home/zulip/deployments/current/manage.py backup'

该命令支持的选项(与源码 zerver/management/commands/backup.py 中的add_arguments完全对应):

选项说明
--output=/tmp/backup.tar.gz指定备份 tarball 的输出文件名(默认写入/tmp下的文件)。成功时控制台会输出 tarball 路径
--skip-db跳过数据库备份。适用于使用自带备份体系的远程 PostgreSQL 主机,只需备份非数据库状态时
--skip-uploads若设置了LOCAL_UPLOADS_DIR,忽略该目录下用户上传的文件

执行后会生成一个.tar.gz归档,包含在另一台机器上完美还原 Zulip 服务器状态所需的全部数据。

从源码看备份归档是如何组装的

阅读 zerver/management/commands/backup.py 的实现可以发现几个值得注意的细节:

  • 版本标识文件:归档内会写入zulip-backup/zulip-version(来自version.pyZULIP_VERSION,若为 git 部署还会追加try_git_describe()的版本描述)、zulip-backup/os-version(来自platform.freedesktop_os_release(),形如ID VERSION_ID)与zulip-backup/postgres-version(来自 PostgreSQL 的server_version)。这正是后文“检查备份归档”一节中读取这些文件的来源。
  • 数据库转储方式:使用/usr/lib/postgresql/<major_version>/bin/pg_dump--format=directory目录格式导出,并自动注入settings.DATABASES["default"]中的用户名、库名、主机与端口,通过环境变量PGPASSWORD传入密码。
  • 配置与密钥:生产环境下打包整个/etc/zulipsettings.pyzulip-secrets.conf等);开发环境下则打包zproject/目录。
  • 上传文件:仅当LOCAL_UPLOADS_DIR已配置且目录存在时,才将该目录纳入归档(配合--skip-uploads跳过)。
  • 打包过程:使用tar -cPhzf生成,内部通过--transform规则把上述路径统一映射到zulip-backup/前缀下,方便恢复脚本按固定布局解包。

恢复备份

恢复备份的标准流程:

  1. 安装与备份时相同的基础操作系统。若之后想升级操作系统,应在恢复完成后再进行。

  2. 安装一台新的 Zulip 服务器(进行到安装流程的 Step 3 为止),通过--postgresql-version参数安装与备份时相同版本的 PostgreSQL。若之后想升级 PostgreSQL 版本,应在恢复完成后再进行。安装指南见 install.md。

  3. 以 root 身份导入备份:

    /home/zulip/deployments/current/scripts/setup/restore-backup /path/to/backup

完成后,Zulip 服务器应完全恢复运行。

更换主机名(测试恢复时的常见场景)

测试恢复备份时,为避免干扰线上服务,常用与原始服务器不同的对外主机名(例如用zuliptest.example.com代替zulip.example.com)。此时和任何一次修改主机名一样,需要更新 EXTERNAL_HOST 配置 并在备份恢复完成后重启 Zulip 服务器。否则服务器仍认为其对外主机名是zulip.example.com,通过zuliptest.example.com访问时会返回 HTTP400 BAD REQUEST

修改数据库设置

如果目标是一台配置差异很大的主机(例如REMOTE_POSTGRES_HOST指向不同值),可先编辑/etc/zulip/settings.py适配新主机,再用--keep-settings恢复:

/home/zulip/deployments/current/scripts/setup/restore-backup --keep-settings /path/to/backup

若还想保留本机的/etc/zulip/zulip.conf,可追加--keep-zulipconf参数。

检查备份归档内容

如果不确定某份备份创建时的版本信息,可以直接读取归档内的postgres-versionos-versionzulip-version三个文件,无需解包整个归档:

tar -Oaxf /path/to/archive/zulip-backup-rest.tar.gz zulip-backup/zulip-version

恢复脚本做了什么:restore-backup 源码解析

恢复入口是 scripts/setup/restore-backup(Python 脚本),其内部流程与manage.py backup正好对称:

  1. 要求以 root 运行,随后su_to_zulip(save_suid=True)切换身份;
  2. 先把归档中的zulip-backup/settings(即/etc/zulip的配置)解包到/etc/zulip——这样后续才能加载真实配置;--keep-settings--keep-zulipconf分别通过--exclude=settings.py--exclude=zulip.conf实现;
  3. 依据配置确定LOCAL_UPLOADS_DIRzproject/(开发环境)路径并解包上传文件;
  4. 重建数据库:调用terminate-psql-sessions终止现存会话、dropdb --if-exists删除旧库、createdb --owner=zulip --template=template0创建全新空库;
  5. 生产环境下依次执行generate_secrets.py(兼容旧版本备份缺失的新密钥)、configure-rabbitmq(当RABBITMQ_HOST为本地地址时,同步 RabbitMQ 密码与zulip-secrets.conf)、zulip-puppet-apply -f(应用zulip.conf中记录的配置);
  6. pg_restore恢复数据库——注释特别说明它必须放在zulip-puppet-apply之后,以确保全文检索扩展已安装可用;
  7. 生产环境执行scripts/restart-server,最后flush-memcached刷新缓存。

备份包含什么、不包含什么

备份包含完整还原 Zulip 服务器所需的全部内容:数据库、设置、/etc/zulip中的密钥、以及存储在服务器上的用户上传文件

以下数据不包含在备份归档中,需要你另行备份:

  • 服务器访问/错误日志/var/log/zulip)。Zulip 服务器只追加日志,其体积可能远超其他数据。
  • 通过 Zulip S3 上传后端 上传的文件。原因有二:S3 中的上传文件体积可能比备份其余部分大出数倍,下载到备份服务器可能超出其磁盘容量;且 S3 本身是可靠的持久存储,自带高质量备份工具。
  • SSL 证书。证书尤其敏感,要么可由 Certbot 轻松重新生成,要么由系统管理员自行提供。

另外,备份也不包含 Zulip 不存入数据库的高度瞬时状态,例如:输入状态数据、API 限流计数器、以及健康服务器上基本恒空的 RabbitMQ 队列(如待发送邮件)。可用rabbitmqctl list_queues检查这些队列是否为空。

在 Docker 部署中,包含清单有所不同——备份单元是/data卷而非manage.py backuptarball,详见 Docker 部署文档 中的卷布局与快照方案。

手动备份细节(Backup details)

本节主要面向自行管理备份的管理员(例如使用远程 PostgreSQL 且已有备份策略),同时也说明了 Zulip 标准工具生成的备份究竟包含哪些数据:

  • PostgreSQL 数据库:可用任何标准数据库导出/备份工具备份;Zulip 对持续时间点备份的内置支持见下文“仅数据库备份工具”。
  • 任何用户上传文件:若使用 S3 存储上传文件,则由 S3 负责备份;若设置了LOCAL_UPLOADS_DIR,用户上传的所有文件(包括头像)会存放在该目录,需要你备份它。
  • /etc/zulip/下的 Zulip 配置(含密钥)。举例说明其重要性:
    • 若丢失secret_key,替换服务器上将无法校验用户 Cookie,所有用户都必须重新登录;
    • 若丢失avatar_salt,所有用户上传的头像都需要重新上传(因为头像文件名是由avatar_salt与用户邮箱的哈希计算得出的),以此类推。

从手动备份恢复

若你之前是手动备份(而非manage.py backup),恢复流程基本是上述过程的逆向操作:

  • 按常规方式下载 Zulip 发布 tarball 并运行scripts/setup/install安装新服务器,务必传入--no-init-db,因为我们不需要创建新数据库;
  • 从备份中把settings.pyzulip-secrets.conf解包到/etc/zulip
  • 从备份中恢复数据库;
  • 以 root 运行scripts/setup/configure-rabbitmq,让 RabbitMQ 使用secrets.conf中的密码;
  • 若使用本地文件上传,将文件恢复到settings.LOCAL_UPLOADS_DIR指定的路径(以及合适的话,恢复日志);
  • scripts/restart-server启动服务器。

这套恢复流程也可用于把 Zulip 安装迁移到另一台服务器。官方建议在配置好备份后进行一次灾难恢复演练,以确认备份确实可用。

逻辑数据导出:把整个组织搬去新服务器

Zulip 的数据导出工具专为在不同 Zulip 安装之间迁移组织而设计;因此这类导出包含一个 Zulip 组织的全部非瞬时数据,唯一例外是密钥类信息(如密码和 API key)

在适用场景下官方仍推荐优先使用备份工具,因为数据导出流程相对有以下缺点:

  • 所有用户的密码会被随机化、并被登出账户(Web 与移动端均如此);
  • 所有机器人(bot)与集成都需要更新新的 API key;
  • 用户、频道、消息通常会被重新编号,外部程序引用这些对象的链接大多会失效。

导出前考虑升级

官方建议在导出前把服务器升级到最新维护版本,至少是本大版本的最新维护版。

针对导入 Zulip Cloud 的场景:若你从自托管服务器导出数据、准备导入 Zulip Cloud,应先把服务器升级到zulip-cloud-current分支:

/home/zulip/deployments/current/scripts/upgrade-zulip-from-git zulip-cloud-current

仅停留在最新稳定版是不够的——Zulip Cloud 运行的是预发布版本,往往领先最新发布版数月开发进度。(该命令对应的升级机制详见 upgrade.md 中“从 git 仓库升级”。)

导出期间防止数据变更

为了获得最佳结果,导出前应关闭对组织的访问,避免导出过程中有人发送新消息等。有两种方式:

  1. ./scripts/stop-server停止整台服务器。若你没有托管多个组织,这是首选——除在持续时间内禁用 Zulip 服务器外没有任何副作用。
  2. ./manage export--deactivate:先停用目标组织,登出所有活跃登录会话,并阻止所有账户登录或访问 API。这适合 Zulip Cloud 这类环境:只想导出单个组织而不干扰其他用户,且本意就是转移该组织的托管(迁移托管本来也要求用户重新登录)。

下方导出命令中两种选项都以#注释形式给出,需要时去掉对应行的#即可。

执行导出

zulip用户登录服务器 shell,运行:

cd /home/zulip/deployments/current # ./scripts/stop-server # export DEACTIVATE_FLAG="--deactivate" # 停用该组织 ./manage.py export -r '' $DEACTIVATE_FLAG # 导出数据

-r用于指定要导出的组织;''表示托管在 Zulip 服务器根域名的默认组织。)

命令会生成一个形如/tmp/zulip-export-2026-05-25-09-30-45-zcmpxfm6.tar.gz的压缩归档,内含多个 JSON 文件(组织的 Zulip 数据)以及组织全部上传文件的归档。

导出命令的更多选项与源码实现

从 zerver/management/commands/export.py 的add_arguments可以看到,除了-r--deactivate,该命令还支持:

选项说明
--output <dir>指定导出数据写入的目录(默认在临时目录创建)
--parallel N并行导出 UserMessage 的进程数(默认取settings.DEFAULT_DATA_EXPORT_IMPORT_PARALLELISM
--public-only只导出公开频道消息及关联附件
--export-full-with-consent导出已同意用户的私密数据(与--public-only互斥)
--upload导出完成后把 tarball 上传到 S3 或LOCAL_UPLOADS_DIR

help文本清晰列出了导出内容与不导出内容:导出所有用户可访问的数据库数据(消息、频道、UserMessage、RealmEmoji 等)与上传文件/头像及还原所需元数据;不导出确认码与预注册用户表(瞬时表)、会话(导出后人人需重新登录)、用户密码与 API key(需 SSO 或重置密码)、APNS/GCM 移动推送令牌、ScheduledEmail、RemoteZulipServer,以及第三方 API 结果缓存。同时也提示了导出后的影响:密码不会迁移、桌面端/移动端需重新登录、所有 bot 因服务器 URL 与 API key 变更而需重新配置。

底层导出由 zerver/lib/export.py 驱动:export.py命令会创建一条RealmExport记录(状态依次为 REQUESTED → STARTED → SUCCEEDED,异常时为 FAILED),再调用export_realm_wrapper(),内部执行do_export_realm(),完成后计算并打印 tarball 的SHA-256 校验和与字节大小,并写入RealmAuditLog(事件类型REALM_EXPORTED);若传了--upload,还会调用upload_export_tarball()上传并输出公开 URL。归档命名前缀由export_tarball_prefix(realm)生成,即zulip-export-<string_id>-<时间戳>-,与文档中的示例文件名一致。若导出时传了--deactivate,命令会先通过do_deactivate_realm(..., deactivation_reason="self_hosting_migration", email_owners=False)停用组织,而导出的数据仍会以“组织处于活跃状态”的形式呈现(export_as_active=True)。

导入到新的 Zulip 服务器

  1. 安装一台新的 Zulip 服务器,跳过 Step 3(你的 Zulip 组织将通过数据导入工具创建)。

    • 确保导入目标服务器的 Zulip 版本与导出源服务器相同

    • 若导出来自 Zulip Cloud(zulip.com),需要先升级到zulip-cloud-current(即 Zulip Cloud 当前运行的版本,通常是main延迟一到两周):

      /home/zulip/deployments/current/scripts/upgrade-zulip-from-git zulip-cloud-current

      仅停留在最新稳定版不够——zulip.com 运行的预发布版本往往领先最新发布版数月。

    • 若服务器可用内存有限,导入期间建议先./scripts/stop-server停掉 Zulip 服务器,因为官方最低系统需求并未为运行数据导入工具预留额外内存。

  2. 如果新服务器将完全取代旧服务器,复制/etc/zulip/settings.py/etc/zulip/zulip.conf是安全且推荐的,可避免重复配置工作。 复制/etc/zulip/zulip-secrets.conf同样安全且推荐,但有以下重要例外与注意事项:

    • 不建议复制avatar_salt。Zulip 会自动按新用户 ID 重写合适 URL 的头像;导入后仍用相同 avatar salt(且服务器 URL 相同),可能因浏览器缓存导致 ID 被重新编号的用户头像显示异常。
    • 推荐复制zulip_org_idzulip_org_key,以免服务器与 移动推送通知服务 的注册断开。
    • 若复制了zulip-secrets.conf中的rabbitmq_password,需要以 root 运行scripts/setup/configure-rabbitmq,让本地 RabbitMQ 使用 secrets 文件中的密码。
    • 复制camo_key是必须的,否则消息里指向外部托管图片的链接会失效。
    • 若服务器是早于 Zulip 5.0 的旧版本、且使用移动推送通知服务,应尽可能在导出/导入前升级,并视需要联系官方支持。
  3. zulip用户登录服务器 shell,把文件名替换为你的导出 tarball 路径,运行:

    cd ~ tar -xf /path/to/export/file/zulip-export-2026-05-25-09-30-45-zcmpxfm6.tar.gz cd /home/zulip/deployments/current ./manage.py import '' ~/zulip-export-2026-05-25-09-30-45-zcmpxfm6 ./scripts/start-server

导入耗时取决于数据量,可能长达数分钟。

导入选项:子域名与更多参数

上述命令把导入的组织创建在 Zulip 安装的根域名(EXTERNAL_HOST)下。如果你希望在自定义子域名下导入(例如根域名已存在组织),把最后两行替换为:

./manage.py import <subdomain> ~/zulip-export-2026-05-25-09-30-45-zcmpxfm6 ./scripts/start-server

其中<subdomain>换成想要的子域名。从 zerver/management/commands/import.py 的源码看,import命令还支持:

  • --destroy-rebuild-database:导入前销毁并重建数据库(内部调用 Djangoflushscripts/setup/flush-memcached);
  • --import-into-nonempty:导入到已非空的数据库(源码注释表明这已是默认行为);
  • --allow-reserved-subdomain:允许使用保留子域名;
  • --processes N:并行上传头像到 S3 的进程数(默认同样取DEFAULT_DATA_EXPORT_IMPORT_PARALLELISM);
  • 命令接受多个导出目录export_pathsnargs="+"),可一次导入多个导出;导入前会校验目录存在、子域名可用,并提示“若是 tarball 请先解包”。

导入后登录

导入完成后,所有用户都在新组织中拥有账户,但这些账户还没有密码(出于安全考虑,密码不导出)。用户要么通过 Google auth 等方式认证,要么从重置密码开始。

可使用./manage.py send_password_reset_email向用户发送密码重置邮件。建议先给自己发一封测试:

./manage.py send_password_reset_email -u username@example.com

准备就绪后,再向所有人发送,例如:

./manage.py send_password_reset_email -r '' --all-users

(使用子域名时把''换成你的子域名。)

删除测试导入与重新导入

如果做过一次测试导入,你可能希望在最终导入前删除测试数据。可用以下命令永久删除一个 Zulip 组织的全部数据(若在子域名托管组织,把''换成子域名):

./manage.py delete_realm -r ''

假设使用本地文件上传后端,还可删除服务器上所有组织的文件上传、头像与自定义表情:

rm -rf /home/zulip/uploads/*/*

若托管多个组织、只想删除单个组织的上传,需要在删除数据库中的组织前,在管理 shell 中取得realm.id(Zulip 服务器上第一个创建的组织为2,见下例):

rm -rf /home/zulip/uploads/*/2/

完成后即可重新运行导入流程。(命令实现见 zerver/management/commands/delete_realm.py。)

合规导出:按检索条件导出消息

某些情况下,公司或法律合规要求进行选择性数据导出。这可以通过export_search命令行工具完成,导出消息时可指定以下参数:

  • 消息文本中的搜索关键词
  • 消息的发送者或接收者
  • 消息发送的时间范围

例如,搜索alice@example.com在 11 月 1 日至 6 日之间发送的、包含 "wonderland" 一词的消息:

$ /home/zulip/deployments/current/manage.py export_search --output compliance-export.json \ -r zulip \ --after '2022-11-01 00:00:00' --before '2022-11-06 14:00:00' \ --sender alice@example.com \ wonderland

结果写入 JSON 或 CSV 文件。已编辑消息的旧版本内容不会被搜索到,已删除消息也不会。与结果消息关联的附件可选地一并导出。

更多支持的选项参见/home/zulip/deployments/current/manage.py export_search --help

源码视角:export_search 的过滤与输出实现

从 zerver/management/commands/export_search.py 可以看到完整参数面与实现:

  • 关键词匹配:对消息contenticontains不区分大小写包含匹配,频道消息同时匹配subject(主题/话题);关键词既可通过位置参数传入,也可用--file <path>从文件按行读取;
  • 时间过滤--after/--before接收 ISO 格式 datetime,统一按 UTC 处理(源码中datetime.fromisoformat(...).astimezone(timezone.utc)),分别映射为date_sent__gt/date_sent__lt
  • 人员过滤(互斥组)--sender(按发件邮箱iexact匹配)、--recipient(通过 UserMessage 判断某用户是否收到,可多次指定,是--sender的超集)、--dm(限定于给定用户集合之间的私信,1 人/2 人/多人三种分支分别处理)、--channel(按频道名限定);
  • 输出格式--output必须以.json.csv结尾,默认拒绝覆盖已存在文件(除非--force);--write-attachments <dir>可把引用到的附件并行下载到指定目录(默认 5 个线程,--threads可调),transform_message会输出消息 id、UTC 时间戳、发件人、收件人(含频道#频道名 > 主题格式)、内容与编辑历史,有附件时附上path_id列表。

仅数据库备份工具:基于 wal-g 的连续时间点备份

前面介绍的 Zulip 专用备份工具是完美的“一体化”备份方案,适合每日夜间备份。若需要连续时间点备份,Zulip 内置了每日备份快照 + 使用wal-g流式预写日志(WAL)备份支持,默认保留 30 天。

注意:这些数据库备份本身并不构成 Zulip 系统的完整备份!系统级备份还需要上文“备份细节”一节中列出的其他部分(配置、密钥、上传文件等)。

每日全量数据库备份在0200 UTC进行,每份 WAL 归档文件在 PostgreSQL 保存时即被备份(WAL 每写满 16KiB 生成一份)。这意味着在低活跃时段,备份可能需要几分钟才会写入 S3——可通过 PostgreSQL 的archive_timeout参数设置该时延的上限。

如果需求是“始终最新”的备份可用性,Zulip 还提供内置数据库复制支持。

你应该(也应该)定期监控备份是否正常运行,例如通过puppet/zulip/files/postgresql/wal-g-exporter中的 Prometheus 导出器。

流式备份到 S3

这提供了持久可靠的异地数据库备份,官方建议采用此配置以抵御磁盘故障。由于备份随 WAL 写入实时进入 S3,活跃的 Zulip 服务器每天会向 S3 发送大量 PutObject 请求(可能每天数千次)。

  1. 编辑 PostgreSQL 服务器上的/etc/zulip/zulip-secrets.conf,添加:

    s3_region = # 要写入 S3 的区域;默认为 EC2 主机所在区域 s3_backups_key = # aws 公钥;可选,如果不通过角色访问 s3_backups_secret_key = # aws 密钥;可选,如果不通过角色访问 s3_backups_bucket = # S3 备份桶名称
  2. 运行:

    /home/zulip/deployments/current/scripts/zulip-puppet-apply

此外还可以调整并发数backups_disk_concurrency、S3 存储类别backups_storage_class与增量备份backups_incremental等配置(均位于zulip.conf[backups]相关配置项,详见 system-configuration.md)。

流式备份到本地磁盘

作为 S3 的替代方案,也可以把备份存到本地磁盘。不建议用它做灾难恢复——除非该目录与数据库位于不同磁盘,否则数据库丢失时备份通常也会一起丢失。此方案适合目录挂在 NAS 挂载点、或有其他进程把数据拷离磁盘、或备份仅用于近期应用层数据变更的时间点历史分析等场景。

  1. 编辑 PostgreSQL 服务器上的/etc/zulip/zulip.conf,在已有的[postgresql]段中添加:

    # 调整为你想要的存储位置;应放在与存放数据库的 /var/lib/postgresql/ 不同的磁盘上 backups_directory = /srv/zulip-db-backups
  2. 运行:

    /home/zulip/deployments/current/scripts/zulip-puppet-apply

同样可以调整增量备份配置。

从 wal-g 备份恢复

以下步骤从最新备份恢复数据库。注意:该过程会删除你当前的数据库

  1. 以 root 身份在数据库主机上查看备份列表;最新备份列在底部,正是下面命令要恢复的:

    env-wal-g backup-list --pretty
  2. 若 Zulip 正在运行,先停止它。在应用主机上(取决于配置,可能与数据库主机相同或不同):

    /home/zulip/deployments/current/scripts/stop-server
  3. 以 root 身份在数据库主机上停止 PostgreSQL:

    service postgresql stop
  4. 以 root 身份在数据库主机上删除当前数据库并从备份恢复。耗时取决于数据库大小与到备份存储的连接:

    pg_version=$(crudini --get /etc/zulip/zulip.conf postgresql version) rm -rf "/var/lib/postgresql/$pg_version/main" env-wal-g backup-fetch "/var/lib/postgresql/$pg_version/main" LATEST chown -R postgres.postgres "/var/lib/postgresql/$pg_version/main" touch "/var/lib/postgresql/$pg_version/main/recovery.signal" service postgresql start

    其中的recovery.signal文件指示 PostgreSQL 以恢复模式启动,重放备份后的 WAL 记录直至最新状态。

  5. 以 root 身份在应用主机上刷新缓存并启动 Zulip:

    /home/zulip/deployments/current/scripts/setup/flush-memcached /home/zulip/deployments/current/scripts/start-server

实践建议小结

  • 日常灾备首选备份工具:一条manage.py backup即可产出完整还原单元,配合scripts/setup/restore-backup恢复;务必在正式环境外做一次恢复演练,并验证zulip-version/os-version/postgres-version三个版本标识与目标环境一致。
  • 跨环境/跨服务商迁移走逻辑导出manage.py export -r ''导出 → 新服务器manage.py import导入;导出前停服或--deactivate防止数据变更,导入前核对 Zulip 版本(Cloud 场景需zulip-cloud-current分支),并按需复制/排除zulip-secrets.conf中的各项密钥。
  • 合规检索用export_search:按关键词、时间、发件人/收件人/私信/频道精确圈定消息集,输出 JSON/CSV,可附带附件。
  • 高可用与时间点恢复叠加 wal-g:在 PostgreSQL 主机配置 S3 或本地目录流式备份,配合每日 0200 UTC 快照与 WAL 归档实现连续时间点恢复;监控脚本位于puppet/zulip/files/postgresql/wal-g-exporter

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 11:09:29

Java集合框架深度解析:从ArrayList到HashMap底层原理

1. 为什么JAVA集合是绕不过去的一道坎不管你是刚接触Java的新人&#xff0c;还是已经在写业务代码的初级工程师&#xff0c;集合框架迟早会找上你。我第一次面试的时候&#xff0c;被问了一个到现在都记得很清楚的问题&#xff1a;"ArrayList和LinkedList到底该用哪个&…

作者头像 李华
网站建设 2026/9/13 11:09:27

WorkBuddy Work Duo:双人实时协作文档技术解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 11:09:13

国际关系理论与战略分析方法论探讨

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 11:08:18

ToolJet 使用 Base64 字符串上传并展示图片与 PDF 的完整指南

ToolJet 使用 Base64 字符串上传并展示图片与 PDF 的完整指南 【免费下载链接】ToolJet Open-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, …

作者头像 李华
网站建设 2026/9/13 11:07:33

SQL Server DATEADD 深度解析:日期计算的底层逻辑与实战技巧

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 11:07:32

数学-傅里叶级数的推导

目录&#xff1a; 1、矢量的正交分解 2、信号的正交分解 3、傅里叶级数推导★ 本篇摘录“信号与系统3-傅里叶变换与频域分析”的小部分内容。 1、矢量的正交分解 ▼两矢量V1与V2正交&#xff0c;夹角为90&#xff0c;那么两正交矢量的内积为零&#xff0c;如下图所示。 图4…

作者头像 李华