feat:昵称重复、显示分销人分销tree
This commit is contained in:
1 parent
4518856ccd
commit
074307b07b
50 files changed
+3386
-116
No files matched your search
@@ -0,0 +1,309 @@
|
||||
# 聊天用户同步修复发布与数据处理
|
||||
|
||||
## 本次修复与发布范围
|
||||
|
||||
业务会员 ID 成为聊天身份,普通会员 IM 用户名固定为 `u<ID>`,昵称独立展示。同昵称会员按各自原 ID 保留历史。已删除、禁用、孤立账号通过会员状态管理,IM 人工封禁由原字段独立管理。
|
||||
|
||||
业务事务保存同步任务,提交后通过专用执行队列尝试同步。每分钟定时对账和补偿覆盖逻辑删除及绕过业务入口的资料变化。接口通过版本防止旧请求覆盖新资料。状态变更版本随最新任务保留,覆盖 IM 故障期间先禁用再恢复的情况。
|
||||
|
||||
IM 统一检查会员状态、人工封禁和 JWT 撤销版本。Redis 保存连接可用状态,在线节点登记心跳,停用控制消息广播至所有在线连接节点。WebSocket 登录与心跳均检查版本。
|
||||
|
||||
本次同时修正中文正文读取依赖 JVM 默认字符集的问题。请求声明编码优先,JSON 无编码声明时使用 UTF-8。
|
||||
|
||||
发布包包含以下内容。
|
||||
|
||||
| 位置 | 内容 |
|
||||
| --- | --- |
|
||||
| `jars/yudao-server.jar` | 业务 API,使用 Java 8 |
|
||||
| `jars/im-platform.jar` | IM HTTP 接口,使用 Java 17 |
|
||||
| `jars/im-server.jar` | IM 连接节点,使用 Java 17 |
|
||||
| `migrations/business.sql` | 业务同步任务、持久化编号水位、停用状态的定时任务配置 |
|
||||
| `migrations/im.sql` | IM 会员状态、同步版本、撤销版本及有效限制字段 |
|
||||
| `repair-im-users/` | 数据修复工具及锁定依赖 |
|
||||
| `client-h5/` | 当前 UniApp 源码配置构建的 H5 产物 |
|
||||
| `docs/` | 发布操作、核验报告 |
|
||||
| `SHA256SUMS` | 发布文件校验值 |
|
||||
|
||||
业务 JAR 使用当前工作区构建,包含工作区同期已有的会员分销关系相关改动。发布前将这部分内容一起纳入版本审核。UniApp 原生 App 应由现有 HBuilder/打包流程发布包含本次客户端改动的版本。
|
||||
|
||||
## 1. 确认环境并准备备份
|
||||
|
||||
本次只读核验的业务库为 `chat_v1`,IM 库为 `im_platform`,地址为 `139.224.25.207`。两库位于同一 MySQL 5.7.43-log 实例。正式操作时重新确认连接与线上服务对应。
|
||||
|
||||
在有数据库访问权限的运维机器解压发布包,检查文件校验。
|
||||
|
||||
```bash
|
||||
cd /实际解压目录/chat-sync-release-20261109
|
||||
sha256sum -c SHA256SUMS
|
||||
# macOS 可使用 shasum -a 256 -c SHA256SUMS
|
||||
```
|
||||
|
||||
使用 MySQL 自带凭据文件保存连接信息,命令会交互输入密码。
|
||||
|
||||
```bash
|
||||
mysql_config_editor set --login-path=chat-business --host=139.224.25.207 --port=3306 --user=chat_v1 --password
|
||||
mysql_config_editor set --login-path=chat-im --host=139.224.25.207 --port=3306 --user=im_platform --password
|
||||
|
||||
mysql --login-path=chat-business -D chat_v1 -e 'SELECT DATABASE(),@@server_uuid,@@hostname,VERSION();'
|
||||
mysql --login-path=chat-im -D im_platform -e 'SELECT DATABASE(),@@server_uuid,@@hostname,VERSION();'
|
||||
```
|
||||
|
||||
预先配置修复工具,安装依赖并生成只读预检查清单。密码输入方法见工具 README。
|
||||
|
||||
```bash
|
||||
cd repair-im-users
|
||||
npm ci --omit=dev
|
||||
cp config.example.json config.local.json
|
||||
chmod 600 config.local.json
|
||||
# 编辑 config.local.json,填写两个实际数据库连接
|
||||
node repair-im-users.mjs plan --config config.local.json --out runs/preflight.plan.json
|
||||
cd ..
|
||||
```
|
||||
|
||||
结构迁移前 `schemaReady=false` 符合当前线上状态。正式执行清单须在结构迁移完成后重新生成。
|
||||
|
||||
## 2. 进入维护窗口并停写
|
||||
|
||||
在网关启用维护页面,暂停 App、管理后台、第三方入口和运营脚本的会员及聊天写入。停止业务同步任务、所有旧业务实例、所有旧 IM 接口实例和所有聊天连接节点。同步暂停守护程序的自动拉起和容器编排自动恢复。
|
||||
|
||||
先检查现有服务和启动配置。下面提供 systemd 部署示例,服务名和 JAR 路径按当前服务器实际配置填写。采用容器或其他进程管理方式时执行相应的停止、替换、启动操作。
|
||||
|
||||
```bash
|
||||
systemctl list-units --type=service --all | grep -Ei 'yudao|im-platform|im-server|chat'
|
||||
pgrep -af 'yudao-server|im-platform|im-server'
|
||||
|
||||
BUSINESS_SERVICE='实际业务服务名'
|
||||
IM_PLATFORM_SERVICE='实际IM接口服务名'
|
||||
IM_SERVER_SERVICE='实际聊天连接服务名'
|
||||
BUSINESS_JAR='/实际业务目录/yudao-server.jar'
|
||||
IM_PLATFORM_JAR='/实际IM接口目录/im-platform.jar'
|
||||
IM_SERVER_JAR='/实际聊天连接目录/im-server.jar'
|
||||
|
||||
systemctl cat "$BUSINESS_SERVICE" "$IM_PLATFORM_SERVICE" "$IM_SERVER_SERVICE"
|
||||
sudo systemctl stop "$BUSINESS_SERVICE" "$IM_PLATFORM_SERVICE" "$IM_SERVER_SERVICE"
|
||||
```
|
||||
|
||||
多机、多实例环境对每个实例执行停止。确认全部旧进程停止后保存完整备份。
|
||||
|
||||
```bash
|
||||
umask 077
|
||||
CHAT_BACKUP_DIR="/实际备份目录/chat-sync-$(date +%Y%m%d-%H%M%S)"
|
||||
mkdir -p "$CHAT_BACKUP_DIR"
|
||||
|
||||
mysqldump --login-path=chat-business --default-character-set=utf8mb4 --single-transaction \
|
||||
--routines --triggers --events --hex-blob --no-tablespaces --set-gtid-purged=OFF \
|
||||
chat_v1 > "$CHAT_BACKUP_DIR/chat_v1.sql"
|
||||
mysqldump --login-path=chat-im --default-character-set=utf8mb4 --single-transaction \
|
||||
--routines --triggers --events --hex-blob --no-tablespaces --set-gtid-purged=OFF \
|
||||
im_platform > "$CHAT_BACKUP_DIR/im_platform.sql"
|
||||
|
||||
cp -p "$BUSINESS_JAR" "$CHAT_BACKUP_DIR/yudao-server.jar"
|
||||
cp -p "$IM_PLATFORM_JAR" "$CHAT_BACKUP_DIR/im-platform.jar"
|
||||
cp -p "$IM_SERVER_JAR" "$CHAT_BACKUP_DIR/im-server.jar"
|
||||
sha256sum "$CHAT_BACKUP_DIR"/*.sql "$CHAT_BACKUP_DIR"/*.jar > "$CHAT_BACKUP_DIR/SHA256SUMS"
|
||||
```
|
||||
|
||||
同时保存外置配置、JVM 参数、服务定义及客户端旧版本。核对两份数据库备份命令成功退出,文件大小与备份内容符合预期。
|
||||
|
||||
## 3. 执行两侧结构迁移
|
||||
|
||||
```bash
|
||||
mysql --login-path=chat-business --default-character-set=utf8mb4 -D chat_v1 < migrations/business.sql
|
||||
mysql --login-path=chat-im --default-character-set=utf8mb4 -D im_platform < migrations/im.sql
|
||||
```
|
||||
|
||||
IM 的 ALTER 脚本按一次迁移执行。若运行中断,先检查列是否存在,依据实际完成情况处理后再继续。
|
||||
|
||||
```sql
|
||||
SELECT TABLE_NAME,COLUMN_NAME,COLUMN_TYPE
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA='im_platform' AND TABLE_NAME='im_user'
|
||||
AND COLUMN_NAME IN ('member_state','sync_version','auth_version','access_disabled');
|
||||
|
||||
SELECT id,name,status,handler_name,cron_expression
|
||||
FROM chat_v1.infra_job
|
||||
WHERE handler_name='memberChatSyncJob' AND deleted=b'0';
|
||||
```
|
||||
|
||||
新任务配置初始 `status=2`,保持停用,待服务启动后注册和启用。
|
||||
|
||||
## 4. 重新生成正式清单并修复历史资料
|
||||
|
||||
```bash
|
||||
cd repair-im-users
|
||||
node repair-im-users.mjs plan --config config.local.json --out runs/maintenance.plan.json
|
||||
```
|
||||
|
||||
检查输出 `schemaReady=true`、两库身份、用户数量、状态分类、同昵称清单和安全编号起点。归属异常、字段长度、保留用户名占用或结构异常会直接终止,输出对应明细。
|
||||
|
||||
保持停写并执行。
|
||||
|
||||
```bash
|
||||
node repair-im-users.mjs apply --config config.local.json --plan runs/maintenance.plan.json --maintenance
|
||||
node repair-im-users.mjs verify --config config.local.json --plan runs/maintenance.plan.json
|
||||
```
|
||||
|
||||
`phase=complete` 且核验 `verified=true` 后继续。原用户 ID、密码哈希、好友关系、群关系、群备注与历史消息数量均参与核验。
|
||||
|
||||
出现中断时保留清单与 journal,在停写状态使用同一条 `apply` 命令重跑。两库分别提交,每个阶段保存断点,重跑会校验实际快照并补齐后续阶段。
|
||||
|
||||
将 `runs/maintenance.plan.json*` 复制到本批次备份目录。
|
||||
|
||||
## 5. 替换发布包和核对配置
|
||||
|
||||
三个服务仍处于停止状态时替换 JAR。
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
sudo cp jars/yudao-server.jar "$BUSINESS_JAR"
|
||||
sudo cp jars/im-platform.jar "$IM_PLATFORM_JAR"
|
||||
sudo cp jars/im-server.jar "$IM_SERVER_JAR"
|
||||
```
|
||||
|
||||
沿用现场服务定义中的用户、目录、权限、端口、数据库连接和有效密钥配置。IM 数据库密码使用当前有效凭据。业务服务的 IM 签名配置须与 IM 接口一致,两个 IM 服务的 accessToken 密钥须一致。
|
||||
|
||||
IM 接口的有效外置配置应包含以下选项。
|
||||
|
||||
```yaml
|
||||
im:
|
||||
auth:
|
||||
business-only: true
|
||||
```
|
||||
|
||||
核对业务与 IM 的 Redis 连接。IM 接口与全部连接节点使用相同 Redis 实例和库号。新增状态采用字符串 Hash,控制消息沿用原 Redis 队列配置。保留 IM 连接节点心跳注册所需的 ZSET 权限。
|
||||
|
||||
## 6. 按顺序启动服务和同步任务
|
||||
|
||||
1. 启动新版 IM 接口,等待启动完成及账号状态全量预热成功。
|
||||
2. 启动全部新版 IM 连接节点,确认节点初始化成功并注册在线心跳。
|
||||
3. 启动新版业务服务,专用初始化会核验消息通知和客服账号。
|
||||
|
||||
systemd 部署可按顺序执行,并在每一步检查日志。
|
||||
|
||||
```bash
|
||||
sudo systemctl start "$IM_PLATFORM_SERVICE"
|
||||
sudo journalctl -u "$IM_PLATFORM_SERVICE" -n 100 --no-pager
|
||||
|
||||
sudo systemctl start "$IM_SERVER_SERVICE"
|
||||
sudo journalctl -u "$IM_SERVER_SERVICE" -n 100 --no-pager
|
||||
|
||||
sudo systemctl start "$BUSINESS_SERVICE"
|
||||
sudo journalctl -u "$BUSINESS_SERVICE" -n 100 --no-pager
|
||||
```
|
||||
|
||||
每个 IM 用户状态预热失败会记录 `刷新聊天账号状态失败`。在启动异常得到修复并完成预热后继续。保留网关维护页,仅开放运维管理与验收访问。
|
||||
|
||||
在管理后台进入定时任务页面,先执行“同步”,将数据库中的任务配置注册到 Quartz,再启用处理器 `memberChatSyncJob`,确认每分钟执行。可手动执行一次以加快首次补偿。
|
||||
|
||||
现有“同步”操作会重建全部任务的 Quartz 注册,并按数据库状态恢复各任务。按现场维护范围控制其他任务的启用状态。
|
||||
|
||||
对应接口与参数如下,沿用后台既有登录与租户请求头。
|
||||
|
||||
```text
|
||||
POST /admin-api/infra/job/sync
|
||||
PUT /admin-api/infra/job/update-status?id=<任务ID>&status=1
|
||||
PUT /admin-api/infra/job/trigger?id=<任务ID>
|
||||
```
|
||||
|
||||
每轮最多发送 200 个待补偿任务,后台发送时间预算约 45 秒。失败按 1、5、15、30 分钟退避,后续保持 30 分钟重试。全部任务可能需要多轮完成。
|
||||
|
||||
业务库检查待补偿及错误明细。
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) AS pending_profiles
|
||||
FROM member_chat_sync
|
||||
WHERE deleted=b'0' AND synced_version<version;
|
||||
|
||||
SELECT COUNT(*) AS pending_initialization
|
||||
FROM member_chat_sync
|
||||
WHERE deleted=b'0' AND member_state=0 AND initialized=b'0';
|
||||
|
||||
SELECT member_id,member_state,version,synced_version,retry_count,next_retry_time,last_error
|
||||
FROM member_chat_sync
|
||||
WHERE deleted=b'0' AND (synced_version<version OR (member_state=0 AND initialized=b'0'))
|
||||
ORDER BY next_retry_time,member_id LIMIT 100;
|
||||
```
|
||||
|
||||
修复实际故障后,如需提前重试已退避任务,可在业务库执行下面的定向操作,再手动触发任务。
|
||||
|
||||
```sql
|
||||
UPDATE member_chat_sync SET next_retry_time=CURRENT_TIMESTAMP
|
||||
WHERE deleted=b'0' AND (synced_version<version OR (member_state=0 AND initialized=b'0'));
|
||||
```
|
||||
|
||||
## 7. 完成数据核验和真实账号验收
|
||||
|
||||
首次补偿完成后,在开放用户写入前执行。
|
||||
|
||||
```bash
|
||||
cd repair-im-users
|
||||
node repair-im-users.mjs verify --config config.local.json --plan runs/maintenance.plan.json --ready
|
||||
cd ..
|
||||
```
|
||||
|
||||
要求输出 `verified=true`、`ready=true`、两个 pending 计数均为 0。保存核验报告后进行真实账号操作,避免验收操作影响快照比对。
|
||||
|
||||
IM 库检查关键样本与全量用户名。
|
||||
|
||||
```sql
|
||||
SELECT id,user_name,nick_name,member_state,is_banned,sync_version,auth_version
|
||||
FROM im_user WHERE id IN (-200,-100,100,131) ORDER BY id;
|
||||
|
||||
SELECT id,user_name FROM im_user
|
||||
WHERE id>0 AND BINARY user_name<>BINARY CONCAT('u',id);
|
||||
|
||||
SELECT user_name,COUNT(*) FROM im_user GROUP BY user_name HAVING COUNT(*)>1;
|
||||
```
|
||||
|
||||
100 应为 `u100`、昵称“老芋头”、会员状态 2。131 应为 `u131`、昵称“老芋头”、会员状态 0。后两个全量查询应返回 0 行。
|
||||
|
||||
真实客户端按以下顺序验收。
|
||||
|
||||
- 使用 131 的业务账号登录,调用 `POST /app-api/member/auth/chat-token`,确认业务返回 `code=0` 并带有完整聊天凭证,验证收发消息。
|
||||
- 按正式清单中的同昵称用户逐一核验,展示昵称保持业务资料,聊天身份分别对应原 ID。
|
||||
- 对专用测试会员执行禁用,确认在线连接关闭,客户端展示服务端原因,旧 accessToken、refreshToken 和 WebSocket 重连均失败。
|
||||
- 恢复该会员,从业务入口取得新凭证。新凭证可用,旧凭证持续失效。
|
||||
- 对测试会员设置独立 IM 封禁,确认业务恢复资格时该封禁仍生效。保留其封禁原因和原密码。
|
||||
- 修改测试会员昵称头像,确认好友和群成员资料更新,个人群备注符合既有语义。
|
||||
- 确认独立 IM 登录、注册、改密码和改资料入口返回统一业务入口提示,聊天凭证刷新正常服务业务客户端。
|
||||
|
||||
发布包含本次变更的 H5 和原生 App 客户端,完成停用原因展示及停止重连验收,再按现场发布流程恢复流量。
|
||||
|
||||
## 8. 发布后观察
|
||||
|
||||
持续查看任务积压、重试错误、用户名冲突和聊天凭证签发日志。对账每分钟分页扫描会员资料,支持逻辑删除、物理缺失与手工改库后的当前状态修正。
|
||||
|
||||
本次新增永久编号水位表。会员注册事务在全局行锁下预留编号,跨租户共享编号空间。数据库重启后该水位仍有效。
|
||||
|
||||
IM 返回的账号不可用码为 `10005`,业务聊天凭证接口对应 `1004018005`,保留服务端原因。同步失败或临时故障沿用 `1004018002`。客户端收到账号不可用后停止该业务登录上下文的聊天刷新和重连,新业务登录后可重新获取资格。
|
||||
|
||||
## 9. 回滚与异常恢复
|
||||
|
||||
### 尚未完成迁移
|
||||
|
||||
保持维护状态。先检查 journal,优先使用同一清单重跑 `apply`。源数据发生变化时工具会拒绝继续,应先依据差异与备份确定修复方式。
|
||||
|
||||
### 回滚本批次资料
|
||||
|
||||
重新停写,暂停同步任务及三类服务,备份当前数据库后执行。
|
||||
|
||||
```bash
|
||||
cd repair-im-users
|
||||
node repair-im-users.mjs rollback --config config.local.json --plan runs/maintenance.plan.json --maintenance
|
||||
```
|
||||
|
||||
`phase=rolledBack` 表示本批次资料字段恢复完成。工具保留当前会员停用状态和人工封禁,递增撤销版本及同步版本,保留安全编号水位,并重新生成待补偿任务。
|
||||
|
||||
回滚后保持维护页,核验原用户名、昵称头像、关系与消息。使用新版 IM 接口重新建立 Redis 状态,再启动新版连接节点。业务任务运行后会重新采用 `u<ID>`,因此需要先确定重新迁移方案,再开放流量。
|
||||
|
||||
已经发生后续资料编辑、默认好友初始化、新消息或群变动时,自动回滚会终止并打印差异。使用本批次完整备份与差异记录制定定向恢复步骤。
|
||||
|
||||
### 恢复旧发布版本
|
||||
|
||||
旧 IM 发布包缺少本次账号状态与撤销版本校验。恢复旧版本需要在维护状态完成两库与服务的成套恢复,并单独处理已经撤销的凭证及已停用账号。数据库全量恢复可能覆盖维护窗口后产生的数据,须根据实际备份时间和恢复目标执行。
|
||||
|
||||
当前自动化回滚工具适用于本批次资料恢复,安全状态和编号水位由新版服务持续解释。表结构保留便于继续修复与审计。
|
||||
|
||||
## 当前验证范围
|
||||
|
||||
本地完成两版本 MySQL 集成测试、Redis 状态校验、真实签名 HTTP 与 WebSocket 联调、客户端逻辑测试及三个服务构建。生产数据库已只读预检查,正式迁移、线上进程发布、真实账号及手机端验收由现场按本文执行。
|
||||
@@ -0,0 +1,118 @@
|
||||
# 聊天用户同步修复核验报告
|
||||
|
||||
## 问题定位
|
||||
|
||||
原业务同步将会员昵称同时写入 IM 的 `user_name` 和 `nick_name`。`im_user.user_name` 存在唯一索引,会员昵称允许重复。
|
||||
|
||||
本次两库只读核对发现,100 在业务库已逻辑删除,昵称为“老芋头”,IM 中仍保留用户名“老芋头”。131 是正常业务会员,昵称同为“老芋头”,IM 旧用户名为“芋头”。131 再次同步昵称时发生用户名唯一键冲突,IM 返回 `10003`,业务聊天凭证接口随后返回 `1004018002`。
|
||||
|
||||
修复后 100、131 分别使用 `u100`、`u131`,展示昵称均为“老芋头”。100 会员状态为已删除,131 为正常,各自原 ID 及历史关系继续保留。
|
||||
|
||||
## 线上只读预检查
|
||||
|
||||
扫描时间为北京时间 2026-11-09 11:27:50。连接业务库 `chat_v1` 与 IM 库 `im_platform`,两库服务器 UUID 一致,MySQL 版本为 5.7.43-log。用户名排序规则为 `utf8mb4_general_ci`。
|
||||
|
||||
| 项目 | 扫描结果 |
|
||||
| --- | --- |
|
||||
| 业务会员,包含逻辑删除 | 1013 |
|
||||
| IM 用户,包含两个系统账号 | 1030 |
|
||||
| 正常会员对应的现有 IM 用户 | 945 |
|
||||
| 禁用会员 | 2 |
|
||||
| 已删除会员 | 66 |
|
||||
| IM 独有正数用户 | 15 |
|
||||
| 业务会员缺少 IM 用户 | 0 |
|
||||
| 同昵称会员,包含逻辑删除 | 13 组,29 条 |
|
||||
| 同昵称会员,排除逻辑删除 | 11 组,24 条 |
|
||||
| 本次扫描的安全编号起点 | 1076 |
|
||||
| 好友记录 | 5652 |
|
||||
| 群成员记录 | 3 |
|
||||
| 群记录 | 1 |
|
||||
| 私聊消息 | 2795 |
|
||||
| 群聊消息 | 7 |
|
||||
|
||||
扫描时业务同步任务表、持久化编号水位表,以及 IM 的四个新增字段尚待执行结构迁移,预检查输出 `schemaReady=false`。这些数量记录本次在线快照,正式维护窗口停写后重新生成清单。
|
||||
|
||||
当前全量同昵称明细如下。
|
||||
|
||||
| 昵称 | 会员 ID |
|
||||
| --- | --- |
|
||||
| 逝水如丝 | 75、130、154 |
|
||||
| 喵喵酱 | 76、155 |
|
||||
| 老芋头 | 100、131 |
|
||||
| 小丸子 | 159、1041 |
|
||||
| 静静 | 190、729 |
|
||||
| 甜甜 | 226、261、993、1049 |
|
||||
| 小颜 | 241、254 |
|
||||
| 菜菜 | 257、466 |
|
||||
| 洋洋 | 304、684 |
|
||||
| 婉儿 | 362、945 |
|
||||
| 小雅 | 373、394 |
|
||||
| 糖糖 | 410、804 |
|
||||
| 媛媛 | 502、616 |
|
||||
|
||||
完整原值清单保存在工作区工具的私有 `runs` 目录,Git 已忽略该目录。正式执行时使用维护窗口的新清单和执行记录。
|
||||
|
||||
## 本地验证结果
|
||||
|
||||
| 验证项 | 环境与结果 |
|
||||
| --- | --- |
|
||||
| 业务相关回归 | MySQL 5.7.44,32 例通过 |
|
||||
| 业务相关回归 | MySQL 8.0.46,32 例通过 |
|
||||
| IM 接口全量测试 | MySQL 8.0.46,153 例通过,1 例外部存储 smoke 测试按条件跳过 |
|
||||
| IM 连接服务测试 | 4 例通过 |
|
||||
| IM 本次专项测试 | MySQL 5.7.44,接口 28 例、连接 4 例通过 |
|
||||
| 数据修复工具 | MySQL 5.7、8.0 合计 20 例通过,2 个条件入口按环境跳过 |
|
||||
| 真实 HTTP 与 WebSocket 联调 | 独立本地 IM 接口及两个连接节点,1 个完整流程通过 |
|
||||
| 客户端凭证管理 | 5 例通过 |
|
||||
| 客户端 H5 | 构建通过 |
|
||||
| 业务 JAR | Java 8 构建通过 |
|
||||
| IM 接口、连接 JAR | Java 17 构建通过 |
|
||||
|
||||
IM 测试和真实联调额外使用 `file.encoding=US-ASCII`,验证中文 JSON 正文读取与验签依赖的编码已经明确。
|
||||
|
||||
### 数据和业务事务
|
||||
|
||||
- 原 100、131 冲突、同昵称普通会员、改昵称、30 字昵称、空手机号和最大 Long 用户名。
|
||||
- 业务事务回滚时同步任务回滚,逻辑删除与物理缺失能够被对账识别。
|
||||
- 持久化编号水位、降低自增值后的新注册、同手机号并发注册。
|
||||
- 同 ID 并发 IM 创建、重复请求、旧版本覆盖拦截、同版本不同资料冲突。
|
||||
- 用户、好友及群成员资料更新的同事务提交与故障回滚,群备注和原密码保留。
|
||||
- 欢迎消息并发重试去重,Redis 更新失败后的同版本补偿,禁用恢复及独立封禁的版本校验。
|
||||
|
||||
### 真实双节点连接
|
||||
|
||||
使用实际启动的新版 `im-platform.jar` 和两个 `im-server.jar` 进程连接隔离 MySQL、Redis,通过真实第三方签名请求执行。
|
||||
|
||||
1. 同步中文昵称,获得第三方聊天凭证。
|
||||
2. 同一账号连接两个 IM 节点,确认两条连接登录成功。
|
||||
3. 同步禁用状态,两个节点均收到控制消息并关闭连接。
|
||||
4. 旧 HTTP 凭证、刷新请求均被账号状态拦截。
|
||||
5. 恢复会员后领取新凭证,新连接及接口访问正常,原凭证继续失效。
|
||||
6. 独立用户名密码登录返回业务入口提示。
|
||||
7. 模拟 IM 未接收中间禁用状态、随后直接收到恢复后的最新任务,通过状态变更版本撤销旧凭证,心跳关闭旧连接。
|
||||
|
||||
### 修复工具演练
|
||||
|
||||
在两种 MySQL 上分别演练互相占用的用户名循环、两阶段改名、重复 apply、提交确认丢失后的重跑、维护期 verify、缺失用户补建后的 verify --ready,以及重复 rollback。
|
||||
|
||||
额外检查数据库实际排序规则下的全角用户名占用、字段容量不足、非事务表、异常历史用户编号、超过 JavaScript 安全整数范围的 ID 和版本。后续编辑触发回滚保护时会返回字段路径和差异。
|
||||
|
||||
### 客户端
|
||||
|
||||
验证账号不可用后停止轮询和重试、旧登录上下文的迟到失败、强制下线期间的迟到刷新结果、业务补签返回 IM 封禁原因,以及旧业务登录的补签结果不会覆盖新业务登录凭证。
|
||||
|
||||
## 本次工程决策
|
||||
|
||||
增加持久化编号水位,覆盖 MySQL 5.7 重启重建 AUTO_INCREMENT 的行为,并将历史消息、好友和群关系中保留的用户编号纳入预留范围。
|
||||
|
||||
最新同步资料中保存状态变更版本,覆盖禁用快照被后续恢复快照替代的情况。IM 通过已应用同步版本判断这次撤销是否已处理,重复请求保持幂等。
|
||||
|
||||
业务提交后的发送使用私有有界执行队列,队列繁忙时任务保留在数据库中,避免影响项目原有异步执行器。注册及业务登录的响应结构沿用现有定义。
|
||||
|
||||
## 交付与现场验收
|
||||
|
||||
三个服务发布包、客户端 H5 产物、两侧结构迁移、四命令修复工具、SHA256 校验值及发布回滚说明随交付包提供。
|
||||
|
||||
业务 JAR 包含当前工作区同期已有的会员分销关系改动,构建范围按当前工作区记录。生产迁移、线上进程发布、131 等真实会员凭证与消息收发、原生手机客户端强制下线展示由现场执行验收。本地联调使用隔离测试账号与服务。
|
||||
|
||||
线上执行后,保存正式清单的 `journal.json`、`verification.json` 和完整备份,并补记维护时间、发布实例、真实账号验收结果与观察期错误数量,形成正式修复执行记录。
|
||||
@@ -0,0 +1,68 @@
|
||||
# 聊天用户同步修复简版上线步骤
|
||||
|
||||
本次上线需要执行两份 SQL、修复一次历史账号,再替换三个 JAR。按下面四步操作。
|
||||
|
||||
## 1. 备份并停服
|
||||
|
||||
备份 `chat_v1`、`im_platform` 两个库和原来的三个 JAR。暂停用户访问,停止业务服务、IM 接口服务和全部聊天连接节点,暂停自动拉起。
|
||||
|
||||
## 2. 在两个库分别执行 SQL
|
||||
|
||||
用现有数据库管理软件打开发布包里的文件,在对应数据库执行。
|
||||
|
||||
| 数据库 | SQL 文件 | 作用 |
|
||||
| --- | --- | --- |
|
||||
| `chat_v1` | `migrations/business.sql` | 创建同步任务表、编号水位表,添加定时任务配置 |
|
||||
| `im_platform` | `migrations/im.sql` | 为 IM 用户增加会员状态和版本字段 |
|
||||
|
||||
IM 结构脚本执行一次。每个脚本成功后继续下一步。
|
||||
|
||||
## 3. 修复历史账号
|
||||
|
||||
在能连接两个数据库、装有 Node.js 20.19 及以上版本的电脑操作。发布包已提供本次线上地址、库名和账号配置,密码在运行时输入。
|
||||
|
||||
以下命令使用 Bash。在解压后的发布包目录打开终端,依次执行。
|
||||
|
||||
```bash
|
||||
cd repair-im-users
|
||||
npm ci --omit=dev
|
||||
cp config.production.example.json config.local.json
|
||||
|
||||
read -r -s -p '业务数据库密码 ' CHAT_REPAIR_BUSINESS_PASSWORD
|
||||
printf '\n'
|
||||
read -r -s -p 'IM 数据库密码 ' CHAT_REPAIR_IM_PASSWORD
|
||||
printf '\n'
|
||||
export CHAT_REPAIR_BUSINESS_PASSWORD CHAT_REPAIR_IM_PASSWORD
|
||||
|
||||
node repair-im-users.mjs plan --config config.local.json --out runs/go.plan.json
|
||||
node repair-im-users.mjs apply --config config.local.json --plan runs/go.plan.json --maintenance
|
||||
node repair-im-users.mjs verify --config config.local.json --plan runs/go.plan.json
|
||||
```
|
||||
|
||||
`plan` 应输出 `schemaReady=true`,`apply` 应输出 `phase=complete`,`verify` 应输出 `verified=true`。任一步报错,保持停服并处理报错后继续。保存 `runs/go.plan.json*`,用于本批次核验和回滚。
|
||||
|
||||
这一步将历史用户名改为 `u<ID>`,同步昵称头像,停用已删除及孤立账号,并初始化同步任务和安全编号水位。
|
||||
|
||||
## 4. 替换 JAR、启动并验收
|
||||
|
||||
替换发布包 `jars` 目录里的三个 JAR,沿用现场有效配置。IM 接口确认 `im.auth.business-only=true`。
|
||||
|
||||
按以下顺序启动,每个服务启动成功后再启动下一个。
|
||||
|
||||
1. `im-platform.jar`
|
||||
2. `im-server.jar` 的全部节点
|
||||
3. `yudao-server.jar`
|
||||
|
||||
进入管理后台定时任务页面,点“同步”,启用并执行一次 `memberChatSyncJob`。后台“同步”会重新注册全部任务,其他任务按现场维护安排控制。
|
||||
|
||||
等待补偿完成,在刚才的 `repair-im-users` 目录执行。
|
||||
|
||||
```bash
|
||||
node repair-im-users.mjs verify --config config.local.json --plan runs/go.plan.json --ready
|
||||
```
|
||||
|
||||
输出 `verified=true`、`ready=true`,且 `pending`、`pendingInitialization` 均为 0 后,使用 131 账号登录,确认聊天凭证签发和消息收发正常,再恢复用户访问。需要多轮补偿时等待定时任务继续执行。
|
||||
|
||||
有独立发布客户端的部署,同时发布本次 H5 或对应 App 版本,验收停用提示和停止重连。
|
||||
|
||||
业务 JAR 包含当前工作区已有的会员分销关系改动,发布时一并核对。详细异常处理和回滚步骤见同目录《聊天用户同步修复_发布与数据处理》。
|
||||
Reference in new issue
Block a user