Files
AIclinicalresearch/docs/02-通用能力层/06-R统计引擎/01-R统计引擎架构与部署指南.md

581 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# R 统计引擎架构与部署指南
> **版本:** v1.0
> **创建日期:** 2026-02-19
> **维护者:** SSA-Pro 开发团队
> **状态:** ✅ 生产就绪
---
## 📋 目录
1. [概述](#1-概述)
2. [架构设计](#2-架构设计)
3. [Docker 镜像构建](#3-docker-镜像构建)
4. [部署指南](#4-部署指南)
5. [API 参考](#5-api-参考)
6. [开发指南](#6-开发指南)
7. [运维指南](#7-运维指南)
8. [常见问题](#8-常见问题)
---
## 1. 概述
### 1.1 什么是 R 统计引擎
R 统计引擎是平台的**专用统计计算服务**,基于 Docker 容器化部署,提供:
- 🧮 **严谨的统计分析能力**T 检验、方差分析、回归等)
- 🛡️ **统计护栏**(正态性检验、方差齐性检验等)
- 📊 **可视化输出**Base64 编码的图表)
- 📝 **可复现代码生成**APA 格式的 R 脚本)
### 1.2 定位
```
┌─────────────────────────────────────────────────────────────┐
│ 业务模块层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ SSA-Pro │ │ 其他 │ │ 其他 │ │
│ │ 智能统计 │ │ 模块 │ │ 模块 │ │
│ └────┬────┘ └─────────┘ └─────────┘ │
├───────┼─────────────────────────────────────────────────────┤
│ ▼ 通用能力层 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ R 统计引擎 (Docker) │ │
│ │ • /health 健康检查 │ │
│ │ • /api/v1/tools 工具列表 │ │
│ │ • /api/v1/skills 技能执行 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 1.3 技术栈
| 组件 | 版本 | 说明 |
|------|------|------|
| R | 4.3.3 | 统计计算核心 |
| plumber | 1.2.1 | REST API 框架 |
| ggplot2 | 最新 | 数据可视化 |
| car | 3.1-2 | 高级统计检验 |
| dplyr/tidyr | 最新 | 数据处理 |
| Docker | 24+ | 容器化部署 |
---
## 2. 架构设计
### 2.1 Brain-Hand 模型
R 统计引擎采用 **Brain-Hand 分离架构**
```
┌──────────────────┐ ┌──────────────────┐
│ Node.js │ │ R Docker │
│ (Brain) │ │ (Hand) │
├──────────────────┤ ├──────────────────┤
│ • 业务逻辑 │ HTTP │ • 统计计算 │
│ • 认证鉴权 │ ───────> │ • 数据处理 │
│ • OSS 签名 │ │ • 图表生成 │
│ • 结果解释 │ <─────── │ • 代码生成 │
└──────────────────┘ JSON └──────────────────┘
```
### 2.2 数据传输协议
支持两种数据传输方式:
| 方式 | 条件 | 字段 |
|------|------|------|
| **inline** | 数据 < 2MB | `data_source.data` (JSON) |
| **oss** | 数据 >= 2MB | `data_source.oss_url` (预签名 URL) |
```json
// 方式 1: inline
{
"data_source": {
"type": "inline",
"data": [{"group": "A", "value": 10}, ...]
}
}
// 方式 2: oss (预签名 URL)
{
"data_source": {
"type": "oss",
"oss_url": "https://bucket.oss.com/data.csv?signature=xxx"
}
}
```
### 2.3 安全设计
| 安全措施 | 实现方式 |
|----------|----------|
| 非特权用户 | `USER appuser` |
| 路径遍历防护 | `tool_code` 正则白名单 `^[A-Z][A-Z0-9_]*$` |
| OSS 密钥隔离 | Node.js 生成预签名 URLR 无需持有密钥 |
| 健康检查 | Docker HEALTHCHECK |
---
## 3. Docker 镜像构建
### 3.1 完整 Dockerfile
```dockerfile
FROM rocker/r-ver:4.3
LABEL maintainer="dev-team@aiclinicalresearch.com"
LABEL version="1.0.1"
LABEL description="SSA-Pro R Statistics Service"
# 安装系统依赖(包括 R 包编译所需的库)
RUN apt-get update && apt-get install -y \
libcurl4-openssl-dev \
libssl-dev \
libxml2-dev \
libsodium-dev \
zlib1g-dev \
libnlopt-dev \
liblapack-dev \
libblas-dev \
gfortran \
pkg-config \
cmake \
curl \
&& rm -rf /var/lib/apt/lists/*
# 直接安装 R 包
RUN R -e "install.packages(c( \
'plumber', \
'jsonlite', \
'ggplot2', \
'glue', \
'dplyr', \
'tidyr', \
'base64enc', \
'yaml', \
'car', \
'httr' \
), repos='https://cloud.r-project.org/', Ncpus=2)"
# 安全加固:创建非特权用户
RUN useradd -m -s /bin/bash appuser
WORKDIR /app
# 复制应用代码
COPY plumber.R plumber.R
COPY utils/ utils/
COPY tools/ tools/
COPY tests/ tests/
# 设置目录权限
RUN chown -R appuser:appuser /app
# 切换到非特权用户
USER appuser
EXPOSE 8080
# 环境变量
ENV DEV_MODE="false"
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# 启动服务
CMD ["R", "-e", "plumber::plumb('plumber.R')$run(host='0.0.0.0', port=8080)"]
```
### 3.2 系统依赖说明
| 依赖包 | 用途 |
|--------|------|
| `libcurl4-openssl-dev` | httr 包HTTP 请求) |
| `libssl-dev` | openssl 包(加密) |
| `libxml2-dev` | xml2 包XML 解析) |
| `libsodium-dev` | sodium 包(加密) |
| `zlib1g-dev` | httpuv 包Web 服务器) |
| `libnlopt-dev` | nloptr 包(优化算法) |
| `liblapack-dev` | 线性代数计算 |
| `libblas-dev` | 基础线性代数 |
| `gfortran` | Fortran 编译器(部分 R 包需要) |
| `cmake` | nloptr 包构建 |
| `curl` | 健康检查 |
### 3.3 构建命令
```bash
# 本地构建
cd r-statistics-service
docker build -t ssa-r-statistics:1.0.1 .
# 查看镜像
docker images ssa-r-statistics
# 预期输出
REPOSITORY TAG IMAGE ID CREATED SIZE
ssa-r-statistics 1.0.1 xxxxxxxxxxxx x minutes ago 1.81GB
```
### 3.4 构建时间参考
| 阶段 | 耗时 |
|------|------|
| 基础镜像下载 | ~2 分钟(首次) |
| 系统依赖安装 | ~1 分钟 |
| R 包安装 | ~6 分钟 |
| **总计** | **~9 分钟** |
---
## 4. 部署指南
### 4.1 开发环境
使用 docker-compose
```yaml
# r-statistics-service/docker-compose.yml
version: '3.8'
services:
ssa-r-service:
build: .
container_name: ssa-r-statistics
ports:
- "8082:8080" # 主机8082 → 容器8080REDCap占用8080/8081
environment:
- DEV_MODE=true
volumes:
# 开发环境挂载:支持热重载
- ./tools:/app/tools
- ./utils:/app/utils
- ./tests:/app/tests
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"] # 容器内部仍是8080
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
```
启动命令:
```bash
cd r-statistics-service
docker-compose up -d
```
### 4.2 生产环境 (SAE)
```yaml
# SAE 配置
容器镜像: registry.cn-beijing.aliyuncs.com/aiclinical/ssa-r-statistics:1.0.1
实例规格: 2 vCPU, 4 GB
最小实例: 1
最大实例: 5
端口: 8080
环境变量:
DEV_MODE: "false"
```
### 4.3 环境变量
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `DEV_MODE` | `false` | 开发模式(启用热重载,每次请求重新加载工具脚本) |
> **说明**:开发环境和生产环境都使用真实 OSS无需 Mock 数据。
> - 开发环境:`ai-clinical-data-dev` bucket
> - 生产环境:`ai-clinical-data` bucket
### 4.4 端口配置
| 环境 | 主机端口 | 容器端口 | 说明 |
|------|----------|----------|------|
| **开发环境** | 8082 | 8080 | 避免与 REDCap 8080/8081 冲突 |
| **生产环境 (SAE)** | 8080 | 8080 | 云端无端口冲突 |
> **注意**Node.js 后端通过 `R_SERVICE_URL` 环境变量配置 R 服务地址,默认值为 `http://localhost:8082`。
---
## 5. API 参考
### 5.1 健康检查
```http
GET /health
```
**响应:**
```json
{
"status": "ok",
"timestamp": "2026-02-19 08:00:00",
"version": "1.0.1",
"dev_mode": true,
"tools_loaded": 1
}
```
### 5.2 工具列表
```http
GET /api/v1/tools
```
**响应:**
```json
{
"status": "ok",
"tools": ["t_test_ind", "anova_oneway"],
"count": 2
}
```
### 5.3 执行技能
```http
POST /api/v1/skills/{tool_code}
Content-Type: application/json
```
**请求体:**
```json
{
"data_source": {
"type": "inline",
"data": [...]
},
"params": {
"group_var": "group",
"value_var": "value"
},
"guardrails": {
"check_normality": true
}
}
```
**成功响应:**
```json
{
"status": "success",
"message": "分析完成",
"warnings": null,
"results": {
"method": "Welch Two Sample t-test",
"statistic": -5.196,
"df": 5.98,
"p_value": 0.002,
"p_value_fmt": "p = .002"
},
"plots": ["data:image/png;base64,..."],
"trace_log": [...],
"reproducible_code": "..."
}
```
**错误响应:**
```json
{
"status": "error",
"error_code": "E001",
"error_type": "business",
"message": "列名 'xxx' 在数据中不存在",
"user_hint": "请检查变量名是否拼写正确"
}
```
---
## 6. 开发指南
### 6.1 添加新工具
1.`tools/` 目录创建 R 脚本:
```r
# tools/my_analysis.R
#' @tool_code ST_MY_ANALYSIS
#' @name 我的分析工具
#' @version 1.0.0
# 统一入口函数
run_analysis <- function(input) {
# 加载数据
df <- load_input_data(input)
# 参数
p <- input$params
# 护栏检查
# ...
# 核心计算
# ...
# 返回结果
return(list(
status = "success",
message = "分析完成",
results = list(...)
))
}
```
2. 重启服务(开发模式无需重启)
3. 测试:
```bash
curl -X POST http://localhost:8082/api/v1/skills/ST_MY_ANALYSIS \
-H "Content-Type: application/json" \
-d '{"data_source": {...}, "params": {...}}'
```
### 6.2 工具命名规范
| 项目 | 规范 |
|------|------|
| 文件名 | 小写下划线:`t_test_ind.R` |
| tool_code | 大写下划线:`ST_T_TEST_IND` |
| 入口函数 | 固定名称:`run_analysis` |
### 6.3 结果格式规范
```r
return(list(
status = "success" | "error" | "blocked",
message = "...",
warnings = c("...") | NULL,
results = list(
# 统计结果
),
plots = list(
"data:image/png;base64,..."
),
trace_log = c("..."),
reproducible_code = "..."
))
```
---
## 7. 运维指南
### 7.1 日志查看
```bash
# 实时日志
docker logs -f ssa-r-statistics
# 最近 100 行
docker logs --tail 100 ssa-r-statistics
```
### 7.2 性能监控
```bash
# 容器资源使用
docker stats ssa-r-statistics
```
### 7.3 重启服务
```bash
# 开发环境
docker-compose restart
# 生产环境 (SAE)
通过 SAE 控制台重启实例
```
### 7.4 镜像更新
```bash
# 1. 构建新镜像
docker build -t ssa-r-statistics:1.0.2 .
# 2. 推送到镜像仓库
docker tag ssa-r-statistics:1.0.2 registry.cn-beijing.aliyuncs.com/aiclinical/ssa-r-statistics:1.0.2
docker push registry.cn-beijing.aliyuncs.com/aiclinical/ssa-r-statistics:1.0.2
# 3. 更新 SAE 部署
```
---
## 8. 常见问题
### Q1: 构建时 httpuv 安装失败
**错误:** `fatal error: zlib.h: No such file or directory`
**解决:** 添加 `zlib1g-dev` 到系统依赖
### Q2: 构建时 nloptr 安装失败
**错误:** `CMAKE NOT FOUND`
**解决:** 添加 `cmake` 到系统依赖
### Q3: /tmp 权限问题
**错误:** `cannot open file '/tmp/Rtmpxxx': No such file or directory`
**解决:** 不要在启动命令中清理 /tmp
### Q4: DEV_MODE 热重载不生效
**原因:** 没有挂载 volumes
**解决:**
```yaml
volumes:
- ./tools:/app/tools
```
### Q5: 容器启动后无法访问
**检查:**
1. 端口映射是否正确
2. 健康检查是否通过
3. 查看容器日志
---
## 附录:文件结构
```
r-statistics-service/
├── Dockerfile # 生产镜像定义
├── docker-compose.yml # 开发环境编排
├── renv.lock # R 包版本锁定(备用)
├── .Rprofile # R 启动配置(备用)
├── plumber.R # API 入口
├── utils/
│ ├── data_loader.R # 数据加载(预签名 URL
│ ├── guardrails.R # 统计护栏
│ ├── error_codes.R # 错误映射
│ └── result_formatter.R # 结果格式化
├── tools/
│ └── t_test_ind.R # 独立样本 T 检验
├── tests/
│ └── fixtures/
│ └── normal_data.csv # 测试数据
├── metadata/ # 工具元数据(预留)
└── templates/ # 解释模板(预留)
```
---
**文档结束**