Files
starRiverProperty/docs/visitor-floor-policy-implementation-log.md
T
hpd840321 abc690af09 docs: rewrite implementation log as deployment step document
原内容为开发阶段的git操作日志,现重写为面向运维人员的部署实施步骤文档

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-26 09:32:55 +08:00

13 KiB
Raw Blame History

租户访客楼层策略 — 部署实施步骤

项目: 星河湾星中星 (starRiverProperty) 功能: 租户访客楼层策略(REPLACE_ALLOWLIST 基线版本: v2.0.17 适用环境: 生产环境(10.0.22.103


一、部署概览

1.1 涉及组件

组件 服务名 端口 变更类型
component-organization 服务 ninca-common-component-organization 17016 JAR 升级 + DDL
电梯应用 cw-elevator-application 18081 JAR 升级(无配置变更)

1.2 涉及数据库

数据库 IP 变更类型 说明
component-organization 10.0.22.103 DDL + DML 新建策略表 + 种子数据
cw-elevator-application 10.0.22.103 仅代码查询,表已废弃

1.3 发布包

发布包 构建脚本 输出路径
ninca-common-component-organization-{ver}-xinghewan-{YYYYMMDD}.zip scripts/build/release-component-organization.sh backend/ninca-common-component-organization/releases/
cw-elevator-application-V{ver}.{YYYYMMDD}.zip scripts/build/release-cw-elevator-application.sh backend/cw-elevator-application/releases/

二、前置准备

2.1 数据库全量备份(必需)

在实施任何变更前,对生产数据库服务器(10.0.22.103)执行全库备份。

# 备份全部数据库(预计 5-10 分钟,3.1 GB)
MYSQL_HOST=10.0.22.103
MYSQL_USER=root
BACKUP_DIR=/data/backup/$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"

# 获取所有数据库列表(排除系统库)
databases=$(mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p \
  -e "SHOW DATABASES;" | grep -Ev "^(Database|information_schema|performance_schema|mysql|sys)$")

# 逐个备份
for db in $databases; do
  echo "Backing up $db ..."
  mysqldump -h "$MYSQL_HOST" -u "$MYSQL_USER" -p \
    --single-transaction --routines --triggers --events \
    "$db" | gzip > "$BACKUP_DIR/${db}_$(date +%Y%m%d_%H%M%S).sql.gz"
done

echo "Backup complete: $BACKUP_DIR"
ls -lh "$BACKUP_DIR"

备份验证

# 检查备份文件完整性
for f in "$BACKUP_DIR"/*.sql.gz; do
  gzip -t "$f" || echo "CORRUPT: $f"
done

# 检查 component-organization 备份大小(应有 200MB+
ls -lh "$BACKUP_DIR"/component-organization*.sql.gz

2.2 发布包准备

# 构建 component-org 发布包
cd /path/to/repo
bash scripts/build/release-component-organization.sh 2.9.5

# 构建电梯应用发布包
bash scripts/build/release-cw-elevator-application.sh 2.0.17

# 产物确认
ls -lh backend/ninca-common-component-organization/releases/*.zip
ls -lh backend/cw-elevator-application/releases/*.zip

2.3 当前状态快照

# 记录当前运行状态
echo "=== 部署前状态快照 ===" > /tmp/pre-deploy-state.txt
date >> /tmp/pre-deploy-state.txt

# component-org 进程
ps aux | grep component-organization >> /tmp/pre-deploy-state.txt

# 电梯应用进程
ps aux | grep cw-elevator-application >> /tmp/pre-deploy-state.txt

# 当前策略表状态(应不存在或为空)
mysql -h 10.0.22.103 -u root -p component-organization \
  -e "SELECT COUNT(*) AS policy_count FROM tenant_visitor_floor_policy;" 2>/dev/null \
  || echo "Table not exists (expected)" >> /tmp/pre-deploy-state.txt

# 策略日志当前状态
tail -50 logs/component-organization.info.log | grep POLICY \
  >> /tmp/pre-deploy-state.txt 2>/dev/null || true

三、部署步骤

Step 1:数据库 DDL — 建表

component-organization 库创建策略表。

# 执行建表 DDL
mysql -h 10.0.22.103 -u root -p component-organization \
  < docs/sql/organization_tenant_visitor_floor_policy.sql

验证

SHOW TABLES LIKE 'tenant_visitor_floor_policy';
SHOW CREATE TABLE tenant_visitor_floor_policy;
-- 预期:
--   policy_type DEFAULT 'REPLACE_ALLOWLIST'(非 INTERSECT_ALLOWLIST
--   唯一键 uk_org_building (org_id, building_id)
--   索引 idx_org_enabled (org_id, enabled)

Step 2:数据库 DML — 种子数据

写入广发基金 28F + 物业管理 28F+6F 策略数据。

# 执行种子数据(幂等,可重复执行)
mysql -h 10.0.22.103 -u root -p component-organization \
  < docs/sql/organization_tenant_visitor_floor_policy_init_tenants.sql

验证

-- 验证数据完整性
SELECT id, org_id, policy_type, allow_zone_ids, remark, enabled
FROM tenant_visitor_floor_policy
WHERE enabled = 1;

-- 预期返回 8 条记录:
--   1 条广发基金 28Fgf_vstr_policy_guangfa_fund_001x
--   7 条物业管理 28F+6Fpm_6f_vstr_policy_001 ~ 007

-- 验证策略类型
SELECT DISTINCT policy_type FROM tenant_visitor_floor_policy;
-- 预期:只有 REPLACE_ALLOWLIST

Step 3:部署 component-org 服务

# 1. 传输发布包到目标服务器
scp backend/ninca-common-component-organization/releases/\
ninca-common-component-organization-2.9.5-xinghewan-*.zip \
  user@target-server:/opt/cw/component-organization/

# 2. 解压
cd /opt/cw/component-organization
unzip ninca-common-component-organization-2.9.5-xinghewan-*.zip
cd ninca-common-component-organization-2.9.5-xinghewan-*/

# 3. 替换配置(如需要)
# 确认 bootstrap.properties / application.properties 与现网一致

# 4. 停止旧服务
systemctl stop ninca-common-component-organization
# 或 kill 进程
# ps aux | grep component-organization | grep -v grep | awk '{print $2}' | xargs kill

# 5. 确认旧进程已退出
ps aux | grep component-organization

# 6. 启动新服务
bash start.sh
# 或 systemctl start ninca-common-component-organization

# 7. 检查启动日志
tail -f logs/component-organization.info.log
# 预期:
#   - 无 Bean 冲突异常
#   - 无 ResourceBundle WARN
#   - 端口 17016 监听正常

启动验证

# 检查端口
ss -tlnp | grep 17016

# 健康检查
curl -s http://127.0.0.1:17016/health

# 测试 detail 接口(含策略)
curl -X POST http://127.0.0.1:17016/component/person/detail \
  -d '{"personId":"1072908835884208128","businessId":"2524639890ba4f2cba9ba1a4eeaa4015"}'

# 检查策略日志
grep 'POLICY-HIT\|POLICY-RESULT' logs/component-organization.info.log

Step 4:部署电梯应用(如需要)

# 如果电梯应用 JAR 也有更新:
scp backend/cw-elevator-application/releases/\
cw-elevator-application-V*.zip \
  user@target-server:/opt/cw/elevator/

cd /opt/cw/elevator
unzip cw-elevator-application-V*.zip
cd cw-elevator-application-V*/

# 停止旧服务 → 替换 JAR → 启动
bash stop.sh
cp *.jar deploy/v2-maven/
bash start.sh

注意:如果仅变更策略数据(SQL 种子),电梯应用无需重启。策略查询通过 Feign → component-org 实时获取。

Step 5:日志配置确认

# 确认策略日志已正确输出
grep -E 'POLICY-HIT|POLICY-MISS|POLICY-FALLBACK|POLICY-EMPTY' \
  logs/component-organization.info.log

# 确认无 ResourceBundle WARN
grep 'ResourceBundle' logs/component-organization.info.log || echo "PASS: 无 ResourceBundle WARN"

# 确认 [POLICY] 入口日志为 DEBUGinfo.log 不应出现 POLICY entry
grep '\[POLICY\] entry' logs/component-organization.info.log || echo "PASS: 无 POLICY entry INFO 日志"

四、功能验证

4.1 策略命中验证

# 测试广发基金访客楼层
curl -X POST http://127.0.0.1:17016/elevator/person/add/visitor \
  -d '{"personId":"1072908835884208128",
       "businessId":"2524639890ba4f2cba9ba1a4eeaa4015",
       "visitorName":"test_visitor_gf"}'
# 返回楼层应为 28Fzone_id: 605560545117995008

# 测试物业管理访客楼层
curl -X POST http://127.0.0.1:17016/elevator/person/add/visitor \
  -d '{"personId":"another_person_id",
       "businessId":"another_business_id",
       "visitorName":"test_visitor_pm"}'
# 返回楼层应为 28F + 6F

4.2 无策略兜底验证

# 使用无策略配置的组织人员测试
curl -X POST http://127.0.0.1:17016/component/person/detail \
  -d '{"personId":"person_id_without_policy",
       "businessId":"business_id_without_policy"}'
# 返回 floorList 应保持 listByImageId 原始值(未被替换)

4.3 异常容错验证

# 模拟策略表不可用(临时重命名)
# mysql -h 10.0.22.103 -u root -p component-organization \
#   -e "RENAME TABLE tenant_visitor_floor_policy TO tenant_visitor_floor_policy_bak;"

# 测试 detail 仍正常返回
curl -X POST http://127.0.0.1:17016/component/person/detail \
  -d '{"personId":"1072908835884208128",
       "businessId":"2524639890ba4f2cba9ba1a4eeaa4015"}'
# 预期:正常返回数据,floorList 为原始值

# 日志应有 POLICY-FALLBACK WARN

# 恢复策略表
# mysql -h 10.0.22.103 -u root -p component-organization \
#   -e "RENAME TABLE tenant_visitor_floor_policy_bak TO tenant_visitor_floor_policy;"

4.4 验收检查表

# 检查项 预期 结果
1 策略表已创建 SHOW TABLES 显示 tenant_visitor_floor_policy □ 通过 □ 不通过
2 广发基金 28F 策略 查表有 gf_vstr_policy_guangfa_fund_001x □ 通过 □ 不通过
3 物业 7 条 28F+6F 策略 查表有 pm_6f_vstr_policy_001 ~ 007 □ 通过 □ 不通过
4 策略类型全为 REPLACE_ALLOWLIST SELECT DISTINCT policy_type = 1 种 □ 通过 □ 不通过
5 广发访客 → 28F 访客创建后楼层为 28F □ 通过 □ 不通过
6 物业访客 → 28F+6F 访客创建后楼层为 28F+6F □ 通过 □ 不通过
7 无策略组织 → 原始楼层 不受影响 □ 通过 □ 不通过
8 策略停用 (enabled=0) → 不生效 停用后楼层不被替换 □ 通过 □ 不通过
9 策略查询异常 → 不阻断 表不可用时 detail 正常返回 □ 通过 □ 不通过
10 component-org 启动正常 端口 17016 监听,无 Bean 冲突 □ 通过 □ 不通过
11 POLICY-HIT 有日志 grep 'POLICY-HIT' info.log 有输出 □ 通过 □ 不通过
12 无 ResourceBundle WARN grep ResourceBundle 无输出 □ 通过 □ 不通过

五、回滚方案

5.1 快速回滚(停用策略)

无需重启服务,仅需 SQL。

# 停用所有策略(立即生效)
mysql -h 10.0.22.103 -u root -p component-organization \
  -e "UPDATE tenant_visitor_floor_policy SET enabled=0 WHERE enabled=1;"

# 验证
mysql -h 10.0.22.103 -u root -p component-organization \
  -e "SELECT COUNT(*) AS active_policies FROM tenant_visitor_floor_policy WHERE enabled=1;"
# 预期:0

# 恢复策略(重新启用)
mysql -h 10.0.22.103 -u root -p component-organization \
  -e "UPDATE tenant_visitor_floor_policy SET enabled=1;"

5.2 服务回滚(JAR 回退)

# 1. 停止服务
systemctl stop ninca-common-component-organization

# 2. 备份新 JAR
mv ninca-common-component-organization-2.9.5.jar \
   ninca-common-component-organization-2.9.5.jar.rollback

# 3. 恢复旧 JAR
cp /backup/ninca-common-component-organization-previous.jar \
   ninca-common-component-organization-2.9.5.jar

# 4. 启动服务
systemctl start ninca-common-component-organization

# 5. 验证
tail -f logs/component-organization.info.log

5.3 全量数据库恢复

仅在 DDL 执行后出现数据损坏时使用。

# 使用部署前备份的全量 SQL
RESTORE_FILE=/data/backup/YYYYMMDD_HHMMSS/component-organization_YYYYMMDD_HHMMSS.sql.gz

# 恢复 component-organization 库
zcat "$RESTORE_FILE" | mysql -h 10.0.22.103 -u root -p component-organization

# 验证恢复后策略表应不存在(或为旧状态)
mysql -h 10.0.22.103 -u root -p component-organization \
  -e "SHOW TABLES LIKE 'tenant_visitor_floor_policy';"

六、注意事项

  1. DDL 幂等性:建表 SQL 使用 CREATE TABLE IF NOT EXISTS,种子 SQL 使用 ON DUPLICATE KEY UPDATE,重复执行不会报错。
  2. 电梯侧策略表已废弃cw-elevator-application 库的 tenant_visitor_floor_policy 表 V2 不再查询,仅供历史参考。
  3. 唯一策略维护点:所有策略变更在 component-organization 库执行。
  4. Graceful Shutdowncomponent-org 服务配置了 30s 排空等待,停止服务时在途请求可正常完成。
  5. JDK 版本:所有服务必须使用 JDK 8。
  6. 日志级别[POLICY] 入口日志为 DEBUG 级别,正常运行时 info.log 不会出现 POLICY entry

附录:关键命令速查

操作 命令
建表 mysql -h 10.0.22.103 -u root -p component-organization < organization_tenant_visitor_floor_policy.sql
种子数据 mysql -h 10.0.22.103 -u root -p component-organization < organization_tenant_visitor_floor_policy_init_tenants.sql
查策略 SELECT id, org_id, policy_type, allow_zone_ids, remark FROM tenant_visitor_floor_policy WHERE enabled=1;
停用策略 UPDATE tenant_visitor_floor_policy SET enabled=0;
查策略命中 grep 'POLICY-HIT' logs/component-organization.info.log
查策略回退 grep 'POLICY-FALLBACK' logs/component-organization.info.log
服务状态 ss -tlnp | grep 17016
健康检查 curl http://127.0.0.1:17016/health
全库备份 mysqldump --single-transaction ... | gzip > backup.sql.gz