这是本节的多页打印视图。
点击此处打印.
返回本页常规视图.
开发者指南
DataMate 架构和开发指南
开发者指南介绍 DataMate 的技术架构、开发环境和贡献流程。
DataMate 是一个企业级的数据处理平台,采用微服务架构,支持大规模数据处理和自定义扩展。
架构文档
开发指南
技术栈
前端
| 技术 | 版本 | 说明 |
|---|
| React | 18.x | UI 框架 |
| TypeScript | 5.x | 类型安全 |
| Ant Design | 5.x | UI 组件库 |
| Redux Toolkit | 2.x | 状态管理 |
| Vite | 5.x | 构建工具 |
后端 (Java)
| 技术 | 版本 | 说明 |
|---|
| Java | 21 | 运行时环境 |
| Spring Boot | 3.5.6 | 应用框架 |
| Spring Cloud | 2023.x | 微服务框架 |
| MyBatis Plus | 3.x | ORM 框架 |
后端 (Python)
| 技术 | 版本 | 说明 |
|---|
| Python | 3.11+ | 运行时环境 |
| FastAPI | 0.100+ | Web 框架 |
| LangChain | 0.1+ | LLM 框架 |
| Ray | 2.x | 分布式计算 |
项目结构
DataMate/
├── backend/ # Java 后端
│ ├── services/ # 微服务模块
│ ├── openapi/ # OpenAPI 规范
│ └── scripts/ # 构建脚本
├── frontend/ # React 前端
│ ├── src/
│ │ ├── components/ # 公共组件
│ │ ├── pages/ # 页面组件
│ │ ├── services/ # API 服务
│ │ └── store/ # Redux store
│ └── package.json
├── runtime/ # Python 运行时
│ └── datamate/ # DataMate 运行时
└── deployment/ # 部署配置
├── docker/ # Docker 配置
└── helm/ # Helm Charts
快速开始
1. 克隆代码
git clone https://github.com/ModelEngine-Group/DataMate.git
cd DataMate
2. 启动服务
# 启动基础服务
make install
# 访问前端
open http://localhost:30000
3. 开发模式
# 后端开发
cd backend/services/main-application
mvn spring-boot:run
# 前端开发
cd frontend
pnpm dev
# Python 服务开发
cd runtime/datamate
python operator_runtime.py --port 8081
核心概念
微服务架构
DataMate 采用微服务架构,每个服务负责特定的业务功能:
- API Gateway:统一入口、路由、认证
- Main Application:核心业务逻辑
- Data Management Service:数据集管理
- Data Cleaning Service:数据清洗
- Data Synthesis Service:数据合成
- Runtime Service:算子执行
算子系统
算子是数据处理的基本单元:
- 内置算子:平台提供的常用算子
- 自定义算子:用户开发的自定义算子
- 算子执行:由 Runtime Service 执行
流水线编排
流水线通过可视化编排实现:
- 节点:数据处理的基本单元
- 连接:节点间的数据流
- 执行:按流程自动执行
扩展开发
开发自定义算子
算子开发指南:
- 算子市场 - 算子使用指南
- Python 算子开发示例
- 算子测试和调试
集成外部系统
- API 集成:通过 REST API 集成
- Webhook:事件通知
- 插件系统:(即将推出)
测试
单元测试
# 后端测试
cd backend
mvn test
# 前端测试
cd frontend
pnpm test
# Python 测试
cd runtime
pytest
集成测试
# 启动测试环境
make test-env-up
# 运行集成测试
make integration-test
# 清理测试环境
make test-env-down
性能优化
后端优化
前端优化
安全
认证授权
- JWT 认证
- RBAC 权限控制
- API Key 认证
数据安全
- 传输加密(HTTPS/TLS)
- 存储加密
- 敏感数据脱敏
相关资源
1 - 后端架构
DataMate Java 后端架构设计
DataMate 后端采用微服务架构,基于 Spring Boot 3.x 和 Spring Cloud 构建。
架构概览
DataMate 后端采用微服务架构,将系统拆分为多个独立的服务:
┌─────────────────────────────────────────────┐
│ API Gateway │
│ (Spring Cloud Gateway) │
│ Port: 8080 │
└──────────────┬──────────────────────────────┘
│
┌───────┴───────┬───────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Main │ │ Data │ │ Data │
│ Application │ │ Management │ │ Collection │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└───────────────┴───────────────┘
│
▼
┌────────────────┐
│ PostgreSQL │
│ Port: 5432 │
└────────────────┘
技术栈
核心框架
| 技术 | 版本 | 用途 |
|---|
| Java | 21 | 编程语言 |
| Spring Boot | 3.5.6 | 应用框架 |
| Spring Cloud | 2023.x | 微服务框架 |
| MyBatis Plus | 3.5.x | ORM 框架 |
| PostgreSQL Driver | 42.7.x | 数据库驱动 |
支持组件
| 技术 | 版本 | 用途 |
|---|
| Redis | 5.x | 缓存和消息队列 |
| MinIO | 8.x | 对象存储 |
| Milvus SDK | 2.3.x | 向量数据库 |
| OpenAI API | - | LLM 集成 |
微服务列表
API Gateway
端口: 8080
功能:
技术:
- Spring Cloud Gateway
- JWT 认证
- 限流:Redis + Lua
Main Application
端口: 无(内部服务)
功能:
核心模块:
com.datamate.main
├── auth # 认证授权
├── user # 用户管理
├── permission # 权限管理
├── config # 配置管理
└── scheduler # 任务调度
Data Management Service
端口: 8092
功能:
API 端点:
/data-management/datasets - 数据集管理/data-management/datasets/{id}/files - 文件管理/data-management/tags - 标签管理
核心模块:
com.datamate.data.management
├── dataset # 数据集管理
├── file # 文件管理
├── tag # 标签管理
└── statistics # 统计分析
Data Collection Service
端口: 无(内部服务)
功能:
核心模块:
com.datamate.data.collection
├── task # 任务管理
├── execution # 执行管理
└── datax # DataX 集成
Data Cleaning Service
端口: 无(内部服务)
功能:
核心模块:
com.datamate.data.cleaning
├── task # 任务管理
├── template # 模板管理
└── operator # 算子调用
Data Synthesis Service
端口: 无(内部服务)
功能:
核心模块:
com.datamate.data.synthesis
├── task # 任务管理
├── template # 模板管理
└── llm # LLM 集成
Runtime Service
端口: 8081
功能:
技术:
- Python + Ray
- FastAPI
- 算子插件系统
数据库设计
主要数据表
用户表 (users)
| 字段 | 类型 | 说明 |
|---|
| id | BIGINT | 主键 |
| username | VARCHAR(50) | 用户名 |
| password | VARCHAR(255) | 密码(加密) |
| email | VARCHAR(100) | 邮箱 |
| role | VARCHAR(20) | 角色 |
| created_at | TIMESTAMP | 创建时间 |
数据集表 (datasets)
| 字段 | 类型 | 说明 |
|---|
| id | VARCHAR(50) | 主键 |
| name | VARCHAR(100) | 名称 |
| description | TEXT | 描述 |
| type | VARCHAR(20) | 类型 |
| status | VARCHAR(20) | 状态 |
| created_by | VARCHAR(50) | 创建者 |
| created_at | TIMESTAMP | 创建时间 |
任务表 (tasks)
| 字段 | 类型 | 说明 |
|---|
| id | VARCHAR(50) | 主键 |
| name | VARCHAR(100) | 名称 |
| type | VARCHAR(20) | 任务类型 |
| status | VARCHAR(20) | 状态 |
| config | JSON | 配置 |
| created_at | TIMESTAMP | 创建时间 |
数据库连接配置
spring:
datasource:
url: jdbc:postgresql://localhost:5432/datamate
username: postgres
password: ${DB_PASSWORD:password}
driver-class-name: org.postgresql.Driver
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
服务通信
同步通信
服务间使用 HTTP/REST 进行同步通信:
// 使用 Feign Client
@FeignClient(name = "data-management-service")
public interface DataManagementClient {
@GetMapping("/data-management/datasets/{id}")
DatasetResponse getDataset(@PathVariable String id);
}
异步通信
使用 Redis 实现异步消息队列:
// 发送消息
redisTemplate.convertAndSend("task.created", taskMessage);
// 接收消息
@RedisListener(topic = "task.created")
public void handleTaskCreated(TaskMessage message) {
// 处理任务创建事件
}
认证授权
JWT 认证
// JWT 配置
@Configuration
public class JwtConfig {
@Value("${datamate.jwt.secret}")
private String secret;
@Value("${datamate.jwt.expiration}")
private Long expiration;
}
// JWT 工具类
public class JwtUtil {
public String generateToken(User user) {
// 生成 JWT Token
}
public Claims parseToken(String token) {
// 解析 JWT Token
}
}
权限控制
// RBAC 权限控制
@PreAuthorize("hasRole('ADMIN')")
public void adminOperation() {
// 管理员操作
}
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public void userOperation() {
// 用户操作
}
异常处理
统一异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ValidationException.class)
public ResponseEntity<ErrorResponse> handleValidation(ValidationException e) {
return ResponseEntity.badRequest()
.body(new ErrorResponse("INVALID_PARAMETER", e.getMessage()));
}
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("NOT_FOUND", e.getMessage()));
}
}
配置管理
配置文件
# application.yml
spring:
application:
name: data-management-service
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
# application-dev.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/datamate
# application-prod.yml
spring:
datasource:
url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
配置中心
使用 Spring Cloud Config 进行配置管理:
spring:
cloud:
config:
uri: http://config-server:8888
name: ${spring.application.name}
profile: ${spring.profiles.active}
日志管理
日志配置
<!-- logback-spring.xml -->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/datamate/backend/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/datamate/backend/app-%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>
性能优化
数据库优化
缓存策略
// 使用 Redis 缓存
@Cacheable(value = "datasets", key = "#id")
public Dataset getDataset(String id) {
return datasetRepository.findById(id);
}
@CacheEvict(value = "datasets", key = "#id")
public void deleteDataset(String id) {
datasetRepository.deleteById(id);
}
相关文档
2 - 前端架构
DataMate React 前端架构设计
DataMate 前端基于 React 18 和 TypeScript 构建,采用现代化前端架构。
架构概览
DataMate 前端采用 SPA(单页应用)架构,使用 React 18 + TypeScript + Ant Design 技术栈:
┌─────────────────────────────────────────────┐
│ Browser │
└──────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ React App │
│ ┌──────────────────────────────────────┐ │
│ │ Components │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐│ │
│ │ │ Pages │ │Common UI│ │ Forms ││ │
│ │ └─────────┘ └─────────┘ └─────────┘│ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ State Management │ │
│ │ (Redux Toolkit) │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Services (API) │ │
│ │ (Axios) │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Routing │ │
│ │ (React Router) │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
技术栈
核心框架
| 技术 | 版本 | 用途 |
|---|
| React | 18.x | UI 框架 |
| TypeScript | 5.x | 类型安全 |
| Ant Design | 5.x | UI 组件库 |
| Tailwind CSS | 3.x | 样式框架 |
状态管理
| 技术 | 版本 | 用途 |
|---|
| Redux Toolkit | 2.x | 全局状态管理 |
| React Query | 5.x | 服务器状态管理 |
路由和构建
| 技术 | 版本 | 用途 |
|---|
| React Router | 6.x | 路由管理 |
| Vite | 5.x | 构建工具 |
项目结构
frontend/
├── public/ # 静态资源
├── src/
│ ├── assets/ # 资源文件
│ ├── components/ # 公共组件
│ │ ├── layout/ # 布局组件
│ │ ├── common/ # 通用组件
│ │ └── charts/ # 图表组件
│ ├── pages/ # 页面组件
│ │ ├── DataCollection/
│ │ ├── DataManagement/
│ │ ├── DataCleansing/
│ │ ├── DataAnnotation/
│ │ ├── SynthesisTask/
│ │ ├── RatioTask/
│ │ ├── DataEvaluation/
│ │ ├── KnowledgeBase/
│ │ ├── OperatorMarket/
│ │ ├── Orchestration/
│ │ └── Agent/
│ ├── services/ # API 服务
│ │ ├── api/ # API 定义
│ │ └── types/ # TypeScript 类型
│ ├── store/ # Redux store
│ │ ├── slices/ # Redux slices
│ │ └── index.ts # Store 配置
│ ├── hooks/ # 自定义 Hooks
│ ├── utils/ # 工具函数
│ ├── constants/ # 常量定义
│ ├── routes/ # 路由配置
│ ├── App.tsx # 根组件
│ └── main.tsx # 入口文件
├── index.html
├── vite.config.ts
├── tailwind.config.js
├── tsconfig.json
└── package.json
路由设计
路由结构
// routes/routes.ts
const router = createBrowserRouter([
{
path: "/",
Component: Home,
},
{
path: "/chat",
Component: AgentPage,
},
{
path: "/orchestration",
children: [
{ path: "", Component: SmartOrchestrationPage },
{ path: "create-workflow", Component: WorkflowEditor },
],
},
{
path: "/data",
Component: MainLayout,
children: [
{
path: "collection",
children: [
{ index: true, Component: DataCollection },
{ path: "create-task", Component: CollectionTaskCreate },
],
},
{
path: "management",
children: [
{ index: true, Component: DatasetManagement },
{ path: "create/:id?", Component: DatasetCreate },
{ path: "detail/:id", Component: DatasetDetail },
],
},
// ... 其他路由
],
},
]);
路由守卫
// hooks/useAuthGuard.ts
export const useAuthGuard = () => {
const location = useLocation();
const navigate = useNavigate();
const { isAuthenticated } = useAuth();
useEffect(() => {
if (!isAuthenticated) {
navigate('/login', { state: { from: location } });
}
}, [isAuthenticated, location, navigate]);
};
状态管理
// store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import dataManagementSlice from './slices/dataManagementSlice';
import userSlice from './slices/userSlice';
export const store = configureStore({
reducer: {
dataManagement: dataManagementSlice,
user: userSlice,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
Slice 示例
// store/slices/dataManagementSlice.ts
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { getDatasets, createDataset } from '@/services/api/dataManagement';
interface DataManagementState {
datasets: Dataset[];
loading: boolean;
error: string | null;
}
const initialState: DataManagementState = {
datasets: [],
loading: false,
error: null,
};
export const fetchDatasets = createAsyncThunk(
'dataManagement/fetchDatasets',
async (params: GetDatasetsParams) => {
const response = await getDatasets(params);
return response.data;
}
);
const dataManagementSlice = createSlice({
name: 'dataManagement',
initialState,
reducers: {
clearError: (state) => {
state.error = null;
},
},
extraReducers: (builder) => {
builder
.addCase(fetchDatasets.pending, (state) => {
state.loading = true;
})
.addCase(fetchDatasets.fulfilled, (state, action) => {
state.loading = false;
state.datasets = action.payload;
})
.addCase(fetchDatasets.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message || 'Failed to fetch datasets';
});
},
});
export const { clearError } = dataManagementSlice.actions;
export default dataManagementSlice.reducer;
组件设计
页面组件
// pages/DataManagement/Home/DataManagement.tsx
import React, { useEffect } from 'react';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { fetchDatasets } from '@/store/slices/dataManagementSlice';
import DataTable from '@/components/common/DataTable';
export const DataManagement: React.FC = () => {
const dispatch = useAppDispatch();
const { datasets, loading } = useAppSelector((state) => state.dataManagement);
useEffect(() => {
dispatch(fetchDatasets({ page: 0, size: 20 }));
}, [dispatch]);
return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-6">数据集管理</h1>
<DataTable data={datasets} loading={loading} />
</div>
);
};
公共组件
// components/common/DataTable.tsx
import React from 'react';
import { Table } from 'antd';
interface DataTableProps {
data: any[];
loading: boolean;
}
export const DataTable: React.FC<DataTableProps> = ({ data, loading }) => {
const columns = [
{ title: '名称', dataIndex: 'name', key: 'name' },
{ title: '类型', dataIndex: 'type', key: 'type' },
{ title: '状态', dataIndex: 'status', key: 'status' },
];
return (
<Table
columns={columns}
dataSource={data}
loading={loading}
rowKey="id"
/>
);
};
API 服务
Axios 配置
// services/api/request.ts
import axios from 'axios';
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080',
timeout: 30000,
});
// 请求拦截器
request.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
request.interceptors.response.use(
(response) => {
return response.data;
},
(error) => {
if (error.response?.status === 401) {
// 跳转到登录页
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default request;
API 定义
// services/api/dataManagement.ts
import request from './request';
import type { Dataset, CreateDatasetRequest } from './types';
export const getDatasets = (params: any) => {
return request.get<{ content: Dataset[] }>('/data-management/datasets', {
params,
});
};
export const getDataset = (id: string) => {
return request.get<Dataset>(`/data-management/datasets/${id}`);
};
export const createDataset = (data: CreateDatasetRequest) => {
return request.post<Dataset>('/data-management/datasets', data);
};
export const updateDataset = (id: string, data: Partial<Dataset>) => {
return request.put<Dataset>(`/data-management/datasets/${id}`, data);
};
export const deleteDataset = (id: string) => {
return request.delete(`/data-management/datasets/${id}`);
};
TypeScript 类型定义
// services/types/dataManagement.ts
export interface Dataset {
id: string;
name: string;
description: string;
type: DatasetType;
status: DatasetStatus;
tags: Tag[];
fileCount: number;
totalSize: number;
completionRate: number;
createdAt: string;
createdBy: string;
}
export interface DatasetType {
code: string;
name: string;
description: string;
supportedFormats: string[];
}
export interface Tag {
id: string;
name: string;
color: string;
}
export type DatasetStatus = 'ACTIVE' | 'INACTIVE' | 'PROCESSING';
export interface CreateDatasetRequest {
name: string;
description?: string;
type: string;
tags?: string[];
}
样式方案
Tailwind CSS
// 使用 Tailwind CSS
<div className="flex items-center justify-between p-4 bg-white rounded-lg shadow">
<h2 className="text-lg font-semibold">标题</h2>
<button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
按钮
</button>
</div>
Ant Design
// 使用 Ant Design 组件
import { Button, Table, Modal } from 'antd';
<Modal
title="创建数据集"
open={visible}
onOk={handleOk}
onCancel={handleCancel}
>
<Form>
<Form.Item label="名称" name="name" rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>
</Modal>
性能优化
代码分割
// 路由懒加载
import { lazy } from 'react';
const DataManagement = lazy(() => import('@/pages/DataManagement/Home/DataManagement'));
const router = createBrowserRouter([
{
path: '/data/management',
Component: lazy(() => import('@/pages/Layout/MainLayout')),
children: [
{
index: true,
Component: DataManagement,
},
],
},
]);
React.memo
// 使用 React.memo 避免不必要的重渲染
export const DataCard = React.memo<DataCardProps>(({ data }) => {
return <div>{data.name}</div>;
});
useMemo 和 useCallback
// 使用 useMemo 缓存计算结果
const filteredData = useMemo(() => {
return data.filter(item => item.status === 'ACTIVE');
}, [data]);
// 使用 useCallback 缓存函数
const handleClick = useCallback(() => {
console.log('clicked');
}, []);
测试
组件测试
// DataManagement.test.tsx
import { render, screen } from '@testing-library/react';
import { DataManagement } from './DataManagement';
test('renders data management page', () => {
render(<DataManagement />);
expect(screen.getByText('数据集管理')).toBeInTheDocument();
});
相关文档