Skip to content

常见问题

技术选型

为什么选择 C++23 而不是 Go 或 Rust?

三个核心原因:

  1. 极致性能要求:AuthNexus 的热路径(TCP mTLS 握手、Token 验证、心跳处理)需要亚毫秒级延迟。C++ 配合 asio 协程和零拷贝设计,在高并发场景下有最可控的性能表现。
  2. 生态成熟度:OpenSSL(TLS/PKI/OCSP)、asio(异步 IO)、Lua 5.4(云函数沙箱)、libpq/libpqxx(PostgreSQL)均为经过数十年生产验证的 C/C++ 库。
  3. 线程模型精确控制:AuthNexus 的六类线程域(IO / Logic / DB / Crypto / CloudFunction / Background)需要精确的 executor 绑定和隔离,C++ 的协程 + asio executor 体系提供了最灵活的控制能力。

C++23 的协程、std::expectedstd::format 等特性显著改善了开发体验,代码可读性接近现代语言。

为什么用自定义二进制协议而不是 gRPC?

维度自定义协议gRPC
握手开销直接走 mTLS TCP,无 HTTP/2 帧开销需要 HTTP/2 连接建立 + HPACK 头压缩
心跳效率几个字节的自定义包至少包含 HTTP/2 帧头 + protobuf 包装
TLS 控制完全控制证书验证、OCSP stapling、CA 热替换受限于 gRPC TLS 集成
推送模型Reader 线程持续读取服务端推送Server-streaming RPC,语义不同
协议演进版本号字段,完全自主受 protobuf 版本兼容性约束

总结:对于高频低延迟的认证心跳场景,自定义协议的每字节都有意义,gRPC 的通用性反而是负担。

为什么密码用 HMAC-SHA256 而不是 Argon2/bcrypt?

这是 有意为之的设计取舍,而非安全疏忽。

  • 场景差异:Argon2/bcrypt/scrypt 针对的是密码哈希离线暴力破解场景,通过高计算成本抵抗攻击。AuthNexus 的场景是在线实时认证,每秒可能处理数千次登录请求。
  • 性能优先:HMAC-SHA256 验证耗时 < 0.5ms,而 Argon2id 的推荐参数下验证耗时 50-200ms,差距两个数量级。
  • 安全补偿:密码安全不仅靠哈希算法。AuthNexus 通过 mTLS(传输层)、OCSP(证书状态)、Epoch(全局失效)、黑名单(即时阻断)、速率限制(暴力破解防护)等多层机制共同保障。

格式:$authnexus-fast-hmac-sha256$v=1$<salt_hex>$<hash_hex>,16 字节 salt + 32 字节 hash + 域分离字符串。

部署与迁移

如何从 SQLite 迁移到 PostgreSQL?

SQLite 和 PostgreSQL 的 schema 保持对齐(schema/ 目录下两套 schema 文件并行维护),迁移步骤:

  1. 导出数据:使用 seed_tool 或自定义脚本从 SQLite 导出数据
  2. 初始化 PG:使用 schema/postgres_control_plane_schema.sql 初始化 PostgreSQL 数据库
  3. 导入数据:将导出数据插入 PG
  4. 修改配置:更新 control_plane_app 启动参数,指定 PG 连接串
  5. 验证:运行基本功能测试确认数据完整性

TIP

由于两套 schema 对齐维护,字段名、约束、索引完全一致,数据迁移本质是行级拷贝。

如何水平扩展?

AuthNexus 的扩展模型:

                    ┌─── server_app (节点 A)
SDK ──mTLS TCP──────┤
                    ├─── server_app (节点 B)

                    └─── server_app (节点 C)

                    ┌─────────┘

            control_plane_app (单实例)
  • server_app 水平扩展:部署多个 server_app 节点,每个节点独立连接 CP,通过负载均衡器分发 SDK 连接
  • control_plane_app 单实例:CP 为管理面,不在热路径上,单实例足以支撑大量节点
  • 数据同步:各节点通过四通道机制与 CP 保持同步,本地缓存保证请求处理不依赖 CP 实时响应

Control Plane 断连时会发生什么?

server_app 节点具备离线自治能力:

功能CP 断连时行为
用户登录正常(基于本地 Runtime DB)
Token 验证正常(本地计算)
心跳处理正常
云函数执行正常(脚本已缓存到本地)
配置更新暂停(无法拉取新配置)
Epoch 同步Delta Puller 切换到快速轮询(800ms/5000ms)
SSE 事件断开,自动重连
新用户注册取决于是否需要 CP 参与

设计原则:业务热路径不依赖 CP 实时在线。CP 断连影响的是管理操作和增量同步,不影响已缓存的业务数据服务。

安全相关

可以不使用 mTLS 吗?

不可以。mTLS 是 AuthNexus 安全模型的基石,不是可选项。

mTLS 在 AuthNexus 中承担的职责远超传输加密:

  • 应用隔离:证书 SAN 中的 urn:authnexus:app:<id> 在 TLS 层就实现了租户隔离
  • 设备身份:客户端证书 = 设备身份凭证,与用户密码形成双因素
  • 证书生命周期:通过 OCSP stapling + must-staple 实现实时证书吊销
  • CA 热替换:generation 机制支持 CA 在线轮换

移除 mTLS 意味着丧失上述所有能力,安全模型会彻底崩塌。

如何调试 TLS 握手问题?

分步排查:

1. 开启调试日志(临时):

将日志级别调为 debug,查看完整的 TLS 握手过程。

2. 检查证书链

powershell
# 查看证书信息
openssl x509 -in client.crt -text -noout

# 验证证书链
openssl verify -CAfile tcp_server_ca.pem client.crt

# 检查证书有效期
openssl x509 -in client.crt -dates -noout

3. 常见问题清单

错误现象可能原因解决方案
certificate has expired证书过期重新签发证书
unable to verify the first certificateCA 链不完整补全中间 CA 证书
unsupported certificate purposeEKU 不匹配确保包含 clientAuth EKU
OCSP response not yet valid时钟偏差同步系统时间
certificate revoked证书已被吊销重新签发或恢复证书
SAN 不匹配app_id 错误检查证书的 urn:authnexus:app:<id> URI SAN

4. 恢复日志级别:调试完毕后务必恢复 info 级别。

开发与扩展

如何添加新的配置类型?

  1. 注册配置类型:在 src/control_plane/service/config_registry.h 中注册新类型名称
  2. 实现 CP 侧逻辑
    • Pull 端点:节点拉取配置内容
    • ACK 端点:节点确认配置已应用
    • Error 端点:节点上报应用错误
  3. 实现节点侧逻辑
    • ControlPlaneAgent 中添加配置拉取与应用逻辑
    • 处理 SSE hint 触发拉取
  4. 更新 Schema:如需持久化,在 SQLite 和 PostgreSQL schema 中同步添加表/字段

现有配置类型可作为参考模板:server_runtime_settingsapp_policyapp_variables 等。

如何添加新的测试?

  1. tests/ 目录下创建新文件,命名为 *_tests.cpp
  2. 使用 GoogleTest 框架编写测试
  3. 重新运行 CMake configure(GLOB 重扫)
cpp
// tests/my_feature_tests.cpp
#include <gtest/gtest.h>

TEST(MyFeature, BasicCase) {
    EXPECT_EQ(1 + 1, 2);
}
powershell
# Reconfigure(让 GLOB 扫描到新文件)
cmake -B build -S .

# 构建并运行
cmake --build build --config Release --target unit_tests --parallel
ctest --test-dir build -C Release --output-on-failure -R "MyFeature"

无需修改 tests/CMakeLists.txt,GLOB 自动收集。

性能相关

最大并发连接数是多少?

没有硬编码上限,取决于硬件和线程配置:

硬件规格推荐线程配置预期并发
2 核 4Gauto(最小档)500-1000
4 核 8Gauto2000-5000
8 核 16Gauto5000-10000
16+ 核 32G+auto 或手动调优10000+

CLI 默认 --auto 模式按 CPU 核数自动规划线程数(4 档),也可通过参数手动覆盖:

powershell
# 手动指定线程数
.\server_app.exe -i 4 --logic-threads 4 -d 2 -c 2

关键瓶颈通常在 TLS 握手(CPU 密集)和数据库操作(IO 密集),线程池隔离确保它们互不干扰。

Token 验证性能如何?

HMAC-SHA256 Token 验证耗时 < 0.5ms,在 crypto_threads 池中执行。实测在 8 核机器上可支撑每秒数万次验证,不构成性能瓶颈。

运维常见问题

节点注册后无法连接 CP 怎么办?

按顺序排查:

  1. 确认 CP 的南向端口(默认 9091)网络可达
  2. 确认节点 mTLS 客户端证书由 cp_node_client_ca 签发
  3. 确认证书未过期且未被吊销
  4. 检查 CP 日志中是否有 TLS 握手拒绝记录
  5. 确认 CP 已完成 PKI 初始化(setup 流程)

OCSP 拉取失败但业务不受影响?

正常现象。OCSP Staple 有本地缓存机制:

  • 缓存在 nextUpdate 有效期内仍可用
  • OCSP 通道(Channel 4)独立于 mTLS 通道,fetch 失败不影响已建立的连接
  • 只有当缓存过期且 must-staple 开启时,新的 SDK 握手才会受影响

日志文件增长过快?

  • 确认日志级别为 info(默认)。debug 级别日志量是 info 的 10-100 倍
  • 配置日志轮转(参见运维手册
  • 检查是否有持续的错误日志输出(如 TLS 握手失败循环)
  • 生产环境严禁长期开启 debugtrace

如何验证四通道通讯是否正常?

通道验证方法
Channel 1 (Command)管理后台查看节点心跳时间是否更新
Channel 2 (SSE)修改配置后检查节点是否在秒级内拉取
Channel 3 (Delta)Bump epoch 后检查节点是否同步
Channel 4 (OCSP)检查节点日志中 OCSP fetch 状态

如果 Channel 2 SSE 断开,Channel 1 仍可工作(节点轮询拉取),Channel 3 Delta Puller 自动切换到快速轮询,业务不受影响,但配置下发延迟会增加。

Demo 模式的数据会影响生产环境吗?

不会。Demo 模式通过 MSW (Mock Service Worker) 在浏览器内拦截所有 /admin/v1 请求,请求根本不会发送到真实后端。Demo 相关代码(MSW、mocks、seed 数据)仅在 VITE_DEMO_MODE=true 时动态导入,不会出现在生产构建产物中。